1
2
3
4
5 package main
6
7 import (
8 "internal/asan"
9 "internal/race"
10 "runtime"
11 "runtime/debug"
12 "unsafe"
13 )
14
15 func init() {
16 register("DetectFinalizerAndCleanupLeaks", DetectFinalizerAndCleanupLeaks)
17 }
18
19 type tiny uint8
20
21 var tinySink *tiny
22
23
24 func DetectFinalizerAndCleanupLeaks() {
25 type T *int
26
27 defer debug.SetGCPercent(debug.SetGCPercent(-1))
28
29
30 cLeak := new(T)
31
32
33
34 var closeOverCLeak func(int)
35 closeOverCLeak = func(x int) {
36
37 if x <= 0 {
38 **cLeak = x
39 } else {
40 closeOverCLeak(x - 1)
41 }
42 }
43
44 runtime.AddCleanup(cLeak, func(x int) {
45 closeOverCLeak(x)
46 }, int(0))
47
48
49 cNoLeak := new(T)
50 runtime.AddCleanup(cNoLeak, func(_ int) {}, int(0))
51
52
53 var closeOverCNoLeak func(int)
54 closeOverCNoLeak = func(x int) {
55 if x <= 0 {
56 **cNoLeak = x
57 } else {
58 closeOverCNoLeak(x - 1)
59 }
60 }
61
62
63 runtime.AddCleanup(cNoLeak, func(x int) {
64 closeOverCNoLeak(x)
65 }, int(0)).Stop()
66
67 if !asan.Enabled && !race.Enabled {
68
69
70
71
72 var ctLeak *tiny
73 for {
74 tinySink = ctLeak
75 ctLeak = new(tiny)
76 *ctLeak = tiny(55)
77
78
79
80 if uintptr(unsafe.Pointer(ctLeak))%2 != 0 {
81 break
82 }
83 }
84 runtime.AddCleanup(ctLeak, func(_ struct{}) {}, struct{}{})
85 }
86
87
88 fLeak := new(T)
89 runtime.SetFinalizer(fLeak, func(_ *T) {
90 **fLeak = 12
91 })
92
93
94 fNoLeak := new(T)
95 runtime.SetFinalizer(fNoLeak, func(x *T) {
96 **x = 51
97 })
98
99
100 runtime.GC()
101 println("OK")
102 }
103
View as plain text