Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions test/go/nil_deref_address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package gotest

import (
"fmt"
"strings"
"testing"
)

type nilDerefAddressStruct struct {
i int
x [2]int
}

var nilDerefAddressSink any

func TestNilDerefAddressOperationsPanic(t *testing.T) {
tests := []struct {
name string
f func()
}{
{
name: "address of dereference",
f: func() {
var p *int
nilDerefAddressSink = &*p
},
},
{
name: "field address",
f: func() {
var p *nilDerefAddressStruct
nilDerefAddressSink = &p.i
},
},
{
name: "array pointer element address",
f: func() {
var p *[2]int
nilDerefAddressSink = &p[0]
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expectNilDerefAddressPanic(t, tt.f)
})
}
}

func TestNilDerefPrintedCompositeLoadsPanic(t *testing.T) {
tests := []struct {
name string
f func()
}{
{
name: "slice pointer load",
f: func() {
var p *[]byte
println(*p)
},
},
{
name: "string pointer load",
f: func() {
var p *string
println(*p)
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expectNilDerefAddressPanic(t, tt.f)
})
}
}

func TestNilDerefPrintedFieldLoadPanic(t *testing.T) {
expectNilDerefAddressPanic(t, func() {
var p *nilDerefAddressStruct
println(p.i)
})
}

func TestNilDerefInterfaceCopiesPanic(t *testing.T) {
tests := []struct {
name string
f func()
}{
{
name: "array pointer to interface",
f: func() {
var p *[4]int
nilDerefAddressSink = *p
},
},
{
name: "struct pointer to interface",
f: func() {
var p *nilDerefAddressStruct
nilDerefAddressSink = *p
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expectNilDerefAddressPanic(t, tt.f)
})
}
}

func expectNilDerefAddressPanic(t *testing.T, f func()) {
t.Helper()
defer func() {
err := recover()
if err == nil {
t.Fatal("expected nil pointer dereference panic")
}
if got := nilDerefAddressPanicString(err); !strings.Contains(got, "nil pointer dereference") {
t.Fatalf("panic = %q, want nil pointer dereference", got)
}
}()
f()
}

func nilDerefAddressPanicString(v any) string {
if err, ok := v.(interface{ Error() string }); ok {
return err.Error()
}
return fmt.Sprint(v)
}
67 changes: 67 additions & 0 deletions test/go/nil_panic_runtime_error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package gotest

import (
"runtime"
"strings"
"testing"
)

type nilPanicRuntimeInterface interface {
M()
}

func TestNilPanicValuesAreRuntimeErrors(t *testing.T) {
tests := []struct {
name string
f func()
}{
{
name: "generic nil interface method",
f: func() {
nilPanicRuntimeCall[nilPanicRuntimeInterface](nil)
},
},
{
name: "nil interface method expression",
f: func() {
nilPanicRuntimeMethodExpression[int]()
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := expectRuntimeErrorPanic(t, tt.f)
if !strings.Contains(err.Error(), "nil pointer dereference") {
t.Fatalf("panic = %q, want nil pointer dereference", err.Error())
}
})
}
}

func nilPanicRuntimeCall[P nilPanicRuntimeInterface](p P) {
p.M()
}

func nilPanicRuntimeMethodExpression[T any]() {
interface{ M() T }.M(nil)
}

func expectRuntimeErrorPanic(t *testing.T, f func()) runtime.Error {
t.Helper()
var recovered any
func() {
defer func() {
recovered = recover()
}()
f()
}()
if recovered == nil {
t.Fatal("expected panic")
}
err, ok := recovered.(runtime.Error)
if !ok {
t.Fatalf("panic type = %T, want runtime.Error", recovered)
}
return err
}
41 changes: 7 additions & 34 deletions test/goroot/xfail.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1747,10 +1747,6 @@ xfails:
directive: run
case: method5.go
reason: current main goroot run failure on darwin/arm64
- platform: darwin/arm64
directive: run
case: nilptr2.go
reason: current main goroot run failure on darwin/arm64
- platform: darwin/arm64
directive: run
case: noinit.go
Expand Down Expand Up @@ -1818,11 +1814,6 @@ xfails:
directive: run
case: method5.go
reason: go1.24 goroot run failure on linux/amd64
- version: go1.24
platform: linux/amd64
directive: run
case: nilptr2.go
reason: go1.24 goroot run failure on linux/amd64
- version: go1.24
platform: linux/amd64
directive: run
Expand Down Expand Up @@ -1898,11 +1889,6 @@ xfails:
directive: run
case: method5.go
reason: go1.25 goroot run failure on linux/amd64
- version: go1.25
platform: linux/amd64
directive: run
case: nilptr2.go
reason: go1.25 goroot run failure on linux/amd64
- version: go1.25
platform: linux/amd64
directive: run
Expand Down Expand Up @@ -1983,11 +1969,6 @@ xfails:
directive: run
case: method5.go
reason: go1.26 goroot run failure on linux/amd64
- version: go1.26
platform: linux/amd64
directive: run
case: nilptr2.go
reason: go1.26 goroot run failure on linux/amd64
- version: go1.26
platform: linux/amd64
directive: run
Expand Down Expand Up @@ -3005,15 +2986,15 @@ xfails:
reason: current main goroot run failure on darwin/arm64
- platform: darwin/arm64
directive: run
case: fixedbugs/issue38496.go
case: fixedbugs/issue43835.go
reason: current main goroot run failure on darwin/arm64
- platform: darwin/arm64
directive: run
case: fixedbugs/issue43835.go
case: fixedbugs/issue47928.go
reason: current main goroot run failure on darwin/arm64
- platform: darwin/arm64
directive: run
case: fixedbugs/issue47928.go
case: fixedbugs/issue38496.go
reason: current main goroot run failure on darwin/arm64
- version: go1.26
platform: darwin/arm64
Expand Down Expand Up @@ -3041,10 +3022,6 @@ xfails:
directive: run
case: typeparam/chans.go
reason: select over unbuffered channel misses final receive on darwin/arm64
- platform: darwin/arm64
directive: run
case: typeparam/issue51521.go
reason: nil-deref panic value does not implement error on darwin/arm64
- platform: darwin/arm64
directive: run
case: typeparam/mdempsky/15.go
Expand All @@ -3065,10 +3042,6 @@ xfails:
directive: run
case: fixedbugs/issue26094.go
reason: current main goroot run failure on linux/amd64
- platform: linux/amd64
directive: run
case: fixedbugs/issue38496.go
reason: current main goroot run failure on linux/amd64
- platform: linux/amd64
directive: run
case: fixedbugs/issue43835.go
Expand All @@ -3095,6 +3068,10 @@ xfails:
directive: run
case: fixedbugs/issue8132.go
reason: current main goroot run failure on linux/amd64
- platform: linux/amd64
directive: run
case: fixedbugs/issue38496.go
reason: current main goroot run failure on linux/amd64
- version: go1.24
platform: linux/amd64
directive: run
Expand All @@ -3117,10 +3094,6 @@ xfails:
directive: run
case: typeparam/chans.go
reason: select over unbuffered channel misses final receive on linux/amd64
- platform: linux/amd64
directive: run
case: typeparam/issue51521.go
reason: nil-deref panic value does not implement error on linux/amd64
- platform: linux/amd64
directive: run
case: typeparam/mdempsky/15.go
Expand Down
Loading