Source file
test/devirtualization_nil_panics.go
1
2
3
4
5
6
7 package main
8
9 import (
10 "fmt"
11 "runtime"
12 "strings"
13 )
14
15 type A interface{ A() }
16
17 type Impl struct{}
18
19 func (*Impl) A() {}
20
21 type Impl2 struct{}
22
23 func (*Impl2) A() {}
24
25 func main() {
26 shouldNilPanic(28, func() {
27 var v A
28 v.A()
29 v = &Impl{}
30 })
31 shouldNilPanic(36, func() {
32 var v A
33 defer func() {
34 v = &Impl{}
35 }()
36 v.A()
37 })
38 shouldNilPanic(43, func() {
39 var v A
40 f := func() {
41 v = &Impl{}
42 }
43 v.A()
44 f()
45 })
46
47
48
49 shouldNilPanic(55, func() {
50 var v A
51 defer func() {
52 v = &Impl{}
53 }()
54 v.
55 A()
56 })
57 shouldNilPanic(64, func() {
58 var v A
59 defer func() {
60 v = &Impl{}
61 v = &Impl2{}
62 }()
63 v.
64 A()
65 })
66 }
67
68 var cnt = 0
69
70 func shouldNilPanic(wantLine int, f func()) {
71 cnt++
72 defer func() {
73 p := recover()
74 if p == nil {
75 panic("no nil deref panic")
76 }
77 if strings.Contains(fmt.Sprintf("%s", p), "invalid memory address or nil pointer dereference") {
78 callers := make([]uintptr, 128)
79 n := runtime.Callers(0, callers)
80 callers = callers[:n]
81
82 frames := runtime.CallersFrames(callers)
83 line := -1
84 for f, next := frames.Next(); next; f, next = frames.Next() {
85 if f.Func.Name() == fmt.Sprintf("main.main.func%v", cnt) {
86 line = f.Line
87 break
88 }
89 }
90
91 if line != wantLine {
92 panic(fmt.Sprintf("invalid line number in panic = %v; want = %v", line, wantLine))
93 }
94
95 return
96 }
97 panic(p)
98 }()
99 f()
100 }
101
View as plain text