go source for verification 2026-05-22
This commit is contained in:
100
test/devirtualization_nil_panics.go
Normal file
100
test/devirtualization_nil_panics.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type A interface{ A() }
|
||||
|
||||
type Impl struct{}
|
||||
|
||||
func (*Impl) A() {}
|
||||
|
||||
type Impl2 struct{}
|
||||
|
||||
func (*Impl2) A() {}
|
||||
|
||||
func main() {
|
||||
shouldNilPanic(28, func() {
|
||||
var v A
|
||||
v.A()
|
||||
v = &Impl{}
|
||||
})
|
||||
shouldNilPanic(36, func() {
|
||||
var v A
|
||||
defer func() {
|
||||
v = &Impl{}
|
||||
}()
|
||||
v.A()
|
||||
})
|
||||
shouldNilPanic(43, func() {
|
||||
var v A
|
||||
f := func() {
|
||||
v = &Impl{}
|
||||
}
|
||||
v.A()
|
||||
f()
|
||||
})
|
||||
|
||||
// Make sure that both devirtualized and non devirtualized
|
||||
// variants have the panic at the same line.
|
||||
shouldNilPanic(55, func() {
|
||||
var v A
|
||||
defer func() {
|
||||
v = &Impl{}
|
||||
}()
|
||||
v. // A() is on a sepearate line
|
||||
A()
|
||||
})
|
||||
shouldNilPanic(64, func() {
|
||||
var v A
|
||||
defer func() {
|
||||
v = &Impl{}
|
||||
v = &Impl2{} // assign different type, such that the call below does not get devirtualized
|
||||
}()
|
||||
v. // A() is on a sepearate line
|
||||
A()
|
||||
})
|
||||
}
|
||||
|
||||
var cnt = 0
|
||||
|
||||
func shouldNilPanic(wantLine int, f func()) {
|
||||
cnt++
|
||||
defer func() {
|
||||
p := recover()
|
||||
if p == nil {
|
||||
panic("no nil deref panic")
|
||||
}
|
||||
if strings.Contains(fmt.Sprintf("%s", p), "invalid memory address or nil pointer dereference") {
|
||||
callers := make([]uintptr, 128)
|
||||
n := runtime.Callers(0, callers)
|
||||
callers = callers[:n]
|
||||
|
||||
frames := runtime.CallersFrames(callers)
|
||||
line := -1
|
||||
for f, next := frames.Next(); next; f, next = frames.Next() {
|
||||
if f.Func.Name() == fmt.Sprintf("main.main.func%v", cnt) {
|
||||
line = f.Line
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if line != wantLine {
|
||||
panic(fmt.Sprintf("invalid line number in panic = %v; want = %v", line, wantLine))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
panic(p)
|
||||
}()
|
||||
f()
|
||||
}
|
||||
Reference in New Issue
Block a user