1
2
3
4
5 package main
6
7 import (
8 "context"
9 "fmt"
10 "os"
11 "runtime"
12 "runtime/pprof"
13 "time"
14 )
15
16
17
18
19
20
21
22
23
24
25 func init() {
26 register("NoCloseRange", NoCloseRange)
27 register("MethodContractViolation", MethodContractViolation)
28 register("DoubleSend", DoubleSend)
29 register("EarlyReturn", EarlyReturn)
30 register("NCastLeak", NCastLeak)
31 register("Timeout", Timeout)
32 }
33
34
35 func noCloseRange(list []any, workers int) {
36 ch := make(chan any)
37
38
39 for i := 0; i < workers; i++ {
40 go func() {
41
42
43 for item := range ch {
44
45 _ = item
46 }
47 }()
48 }
49
50
51 for _, item := range list {
52
53 ch <- item
54 }
55
56
57 }
58
59 func NoCloseRange() {
60 prof := pprof.Lookup("goroutineleak")
61 defer func() {
62 time.Sleep(100 * time.Millisecond)
63 prof.WriteTo(os.Stdout, 2)
64 }()
65
66 go noCloseRange([]any{1, 2, 3}, 0)
67 go noCloseRange([]any{1, 2, 3}, 3)
68 }
69
70
71
72
73
74
75
76
77
78
79 type worker struct {
80 ch chan any
81 done chan any
82 }
83
84
85 func (w worker) Start() {
86 go func() {
87
88 for {
89 select {
90 case <-w.ch:
91 case <-w.done:
92 return
93 }
94 }
95 }()
96 }
97
98 func (w worker) Stop() {
99
100 close(w.done)
101 }
102
103 func (w worker) AddToQueue(item any) {
104 w.ch <- item
105 }
106
107
108 func workerLifecycle(items []any) {
109
110 w := worker{
111 ch: make(chan any),
112 done: make(chan any),
113 }
114
115 w.Start()
116
117
118 for _, item := range items {
119 w.AddToQueue(item)
120 }
121
122 runtime.Gosched()
123
124 }
125
126 func MethodContractViolation() {
127 prof := pprof.Lookup("goroutineleak")
128 defer func() {
129 runtime.Gosched()
130 prof.WriteTo(os.Stdout, 2)
131 }()
132
133 workerLifecycle(make([]any, 10))
134 runtime.Gosched()
135 }
136
137
138 func doubleSend(ch chan any, err error) {
139 if err != nil {
140
141 ch <- nil
142
143 }
144
145
146 ch <- struct{}{}
147 }
148
149 func DoubleSend() {
150 prof := pprof.Lookup("goroutineleak")
151 ch := make(chan any)
152 defer func() {
153 runtime.Gosched()
154 prof.WriteTo(os.Stdout, 2)
155 }()
156
157 go func() {
158 doubleSend(ch, nil)
159 }()
160 <-ch
161
162 go func() {
163 doubleSend(ch, fmt.Errorf("error"))
164 }()
165 <-ch
166
167 ch1 := make(chan any, 1)
168 go func() {
169 doubleSend(ch1, fmt.Errorf("error"))
170 }()
171 <-ch1
172 }
173
174
175
176
177 func earlyReturn(err error) {
178
179 ch := make(chan any)
180
181 go func() {
182
183
184
185 ch <- struct{}{}
186 }()
187
188 if err != nil {
189
190
191 return
192 }
193
194
195 <-ch
196 }
197
198 func EarlyReturn() {
199 prof := pprof.Lookup("goroutineleak")
200 defer func() {
201 runtime.Gosched()
202 prof.WriteTo(os.Stdout, 2)
203 }()
204
205 go earlyReturn(fmt.Errorf("error"))
206 }
207
208
209 func nCastLeak(items []any) {
210
211 ch := make(chan any)
212
213
214 for range items {
215 go func() {
216
217
218 ch <- struct{}{}
219
220 }()
221 }
222
223
224 <-ch
225 }
226
227 func NCastLeak() {
228 prof := pprof.Lookup("goroutineleak")
229 defer func() {
230 for i := 0; i < yieldCount; i++ {
231
232
233 runtime.Gosched()
234 }
235 prof.WriteTo(os.Stdout, 2)
236 }()
237
238 go func() {
239 nCastLeak(nil)
240 }()
241
242 go func() {
243 nCastLeak(make([]any, 5))
244 }()
245 }
246
247
248
249 func timeout(ctx context.Context) {
250 ch := make(chan any)
251
252 go func() {
253 ch <- struct{}{}
254 }()
255
256 select {
257 case <-ch:
258
259 case <-ctx.Done():
260
261 }
262 }
263
264 func Timeout() {
265 prof := pprof.Lookup("goroutineleak")
266 defer func() {
267 runtime.Gosched()
268 prof.WriteTo(os.Stdout, 2)
269 }()
270
271 ctx, cancel := context.WithCancel(context.Background())
272 cancel()
273
274 for i := 0; i < 100; i++ {
275 go timeout(ctx)
276 }
277 }
278
View as plain text