@@ -38,17 +38,14 @@ const (
38
38
CtxIn int = 1 << iota // ctx in function's param
39
39
CtxOut // ctx in function's results
40
40
CtxInField // ctx in function's field param
41
- HttpRes // http.ResponseWriter in function's param
42
- HttpReq // *http.Request in function's param
43
-
44
- HttpHandler = HttpRes | HttpReq
45
41
)
46
42
47
- const (
48
- EntryWithCtx int = 1 << iota // has ctx in
49
- EntryWithHttpHandler // is http handler
43
+ type entryType int
50
44
51
- Entry = EntryWithCtx | EntryWithHttpHandler
45
+ const (
46
+ EntryNone entryType = iota
47
+ EntryWithCtx // has ctx in
48
+ EntryWithHttpHandler // is http handler
52
49
)
53
50
54
51
type resInfo struct {
@@ -109,7 +106,7 @@ func (r *runner) run(pass *analysis.Pass) {
109
106
110
107
type entryInfo struct {
111
108
f * ssa.Function // entryfunc
112
- tp int // entrytype
109
+ tp entryType // entrytype
113
110
}
114
111
var tmpFuncs []entryInfo
115
112
for _ , f := range funcs {
@@ -119,7 +116,7 @@ func (r *runner) run(pass *analysis.Pass) {
119
116
continue
120
117
}
121
118
122
- if entryType := r .checkIsEntry (f ); entryType & Entry == 0 {
119
+ if entryType := r .checkIsEntry (f ); entryType == EntryNone {
123
120
// record the result of nomal function
124
121
checkingMap := make (map [string ]bool )
125
122
checkingMap [key ] = true
@@ -161,7 +158,7 @@ func (r *runner) getRequiedType(pssa *buildssa.SSA, path, name string) (obj *typ
161
158
func (r * runner ) collectHttpTyps (pssa * buildssa.SSA ) {
162
159
objRes , pobjRes , ok := r .getRequiedType (pssa , httpPkg , httpRes )
163
160
if ok {
164
- r .httpResTyps = append (r .httpResTyps , objRes , pobjRes , types . NewPointer ( pobjRes ) )
161
+ r .httpResTyps = append (r .httpResTyps , objRes , pobjRes )
165
162
}
166
163
167
164
objReq , pobjReq , ok := r .getRequiedType (pssa , httpPkg , httpReq )
@@ -201,27 +198,26 @@ func (r *runner) noImportedContextAndHttp(f *ssa.Function) (ret bool) {
201
198
return true
202
199
}
203
200
204
- func (r * runner ) checkIsEntry (f * ssa.Function ) ( entryType int ) {
201
+ func (r * runner ) checkIsEntry (f * ssa.Function ) entryType {
205
202
if r .noImportedContextAndHttp (f ) {
206
- return
203
+ return EntryNone
207
204
}
208
205
209
206
ctxIn , ctxOut := r .checkIsCtx (f )
210
207
if ctxOut {
211
208
// skip the function which generate ctx
212
- return
209
+ return EntryNone
213
210
} else if ctxIn {
214
211
// has ctx in, ignore *http.Request.Context()
215
- entryType |= EntryWithCtx
216
- return
212
+ return EntryWithCtx
217
213
}
218
214
219
215
// check is `func handler(w http.ResponseWriter, r *http.Request) {}`
220
216
if r .checkIsHttpHandler (f ) {
221
- entryType |= EntryWithHttpHandler
217
+ return EntryWithHttpHandler
222
218
}
223
219
224
- return
220
+ return EntryNone
225
221
}
226
222
227
223
func (r * runner ) checkIsCtx (f * ssa.Function ) (in , out bool ) {
@@ -259,39 +255,12 @@ func (r *runner) checkIsHttpHandler(f *ssa.Function) bool {
259
255
return false
260
256
}
261
257
262
- // must has http.ResponseWriter and *http.Request in param or freevar
263
- var tp int
264
-
265
- // check params
258
+ // must be `func f(w http.ResponseWriter, r *http.Request) {}`
266
259
tuple := f .Signature .Params ()
267
- for i := 0 ; i < tuple .Len (); i ++ {
268
- if r .isCtxType (tuple .At (i ).Type ()) {
269
- return false
270
- } else if r .isHttpReqType (tuple .At (i ).Type ()) {
271
- tp |= HttpReq
272
- } else if r .isHttpResType (tuple .At (i ).Type ()) {
273
- tp |= HttpRes
274
- }
275
- if tp == HttpHandler {
276
- return true
277
- }
278
- }
279
-
280
- // check freevars
281
- for _ , param := range f .FreeVars {
282
- if r .isCtxType (param .Type ()) {
283
- return false
284
- } else if r .isHttpReqType (param .Type ()) {
285
- tp |= HttpReq
286
- } else if r .isHttpResType (param .Type ()) {
287
- tp |= HttpRes
288
- }
289
- if tp == HttpHandler {
290
- return true
291
- }
260
+ if tuple .Len () != 2 {
261
+ return false
292
262
}
293
-
294
- return false
263
+ return r .isHttpResType (tuple .At (0 ).Type ()) && r .isHttpReqType (tuple .At (1 ).Type ())
295
264
}
296
265
297
266
func (r * runner ) collectCtxRef (f * ssa.Function , isHttpHandler bool ) (refMap map [ssa.Instruction ]bool , ok bool ) {
@@ -358,15 +327,21 @@ func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[
358
327
}
359
328
}
360
329
361
- for _ , param := range f .Params {
362
- if r .isCtxType (param .Type ()) {
363
- checkRefs (param , false )
330
+ if isHttpHandler {
331
+ for _ , v := range r .getHttpReqCtx (f ) {
332
+ checkRefs (v , false )
333
+ }
334
+ } else {
335
+ for _ , param := range f .Params {
336
+ if r .isCtxType (param .Type ()) {
337
+ checkRefs (param , false )
338
+ }
364
339
}
365
- }
366
340
367
- for _ , param := range f .FreeVars {
368
- if r .isCtxType (param .Type ()) {
369
- checkRefs (param , false )
341
+ for _ , param := range f .FreeVars {
342
+ if r .isCtxType (param .Type ()) {
343
+ checkRefs (param , false )
344
+ }
370
345
}
371
346
}
372
347
@@ -386,14 +361,6 @@ func (r *runner) collectCtxRef(f *ssa.Function, isHttpHandler bool) (refMap map[
386
361
}
387
362
}
388
363
389
- if ! isHttpHandler {
390
- return
391
- }
392
-
393
- for _ , v := range r .getHttpReqCtx (f ) {
394
- checkRefs (v , false )
395
- }
396
-
397
364
return
398
365
}
399
366
@@ -421,40 +388,34 @@ func (r *runner) getHttpReqCtx(f *ssa.Function) (rets []ssa.Value) {
421
388
checkInstr = func (instr ssa.Instruction , fromAddr bool ) {
422
389
switch i := instr .(type ) {
423
390
case ssa.CallInstruction :
391
+ // r.Context() only has one recv
392
+ if len (i .Common ().Args ) != 1 {
393
+ break
394
+ }
395
+
424
396
// find r.Context()
425
397
if r .getCallInstrCtxType (i )& CtxOut != CtxOut {
426
398
break
427
399
}
428
400
429
- for _ , v := range i .Common ().Args {
430
- if ! r .isHttpReqType (v .Type ()) {
431
- continue
432
- }
433
-
434
- f := r .getFunction (instr )
435
- if f == nil {
436
- continue
437
- }
438
-
439
- // check is r.Context
440
- if f .Signature .Recv () != nil && r .isHttpReqType (f .Signature .Recv ().Type ()) && f .Name () == ctxName {
441
- // collect the return of r.Context
442
- rets = append (rets , i .Value ())
443
- }
401
+ // check is r.Context
402
+ f := r .getFunction (instr )
403
+ if f == nil || f .Name () != ctxName {
404
+ break
405
+ }
406
+ if f .Signature .Recv () != nil {
407
+ // collect the return of r.Context
408
+ rets = append (rets , i .Value ())
444
409
}
445
410
case * ssa.Store :
446
411
if ! fromAddr {
447
412
checkRefs (i .Addr , true )
448
413
}
449
414
case * ssa.UnOp :
450
- if r .isHttpReqType (i .Type ()) {
451
- checkRefs (i , false )
452
- }
453
- case * ssa.MakeClosure :
415
+ checkRefs (i , false )
454
416
case * ssa.Phi :
455
- if r .isHttpReqType (i .Type ()) {
456
- checkRefs (i , false )
457
- }
417
+ checkRefs (i , false )
418
+ case * ssa.MakeClosure :
458
419
case * ssa.Extract :
459
420
// http.Request can only be input
460
421
}
@@ -463,20 +424,15 @@ func (r *runner) getHttpReqCtx(f *ssa.Function) (rets []ssa.Value) {
463
424
for _ , param := range f .Params {
464
425
if r .isHttpReqType (param .Type ()) {
465
426
checkRefs (param , false )
466
- }
467
- }
468
-
469
- for _ , param := range f .FreeVars {
470
- if r .isHttpReqType (param .Type ()) {
471
- checkRefs (param , false )
427
+ break
472
428
}
473
429
}
474
430
475
431
return
476
432
}
477
433
478
- func (r * runner ) checkFuncWithCtx (f * ssa.Function , tp int ) {
479
- isHttpHandler := tp & EntryWithHttpHandler != 0
434
+ func (r * runner ) checkFuncWithCtx (f * ssa.Function , tp entryType ) {
435
+ isHttpHandler := tp == EntryWithHttpHandler
480
436
refMap , ok := r .collectCtxRef (f , isHttpHandler )
481
437
if ! ok {
482
438
return
@@ -496,15 +452,14 @@ func (r *runner) checkFuncWithCtx(f *ssa.Function, tp int) {
496
452
497
453
if tp & CtxIn != 0 {
498
454
if ! refMap [instr ] {
499
- r .pass .Reportf (instr .Pos (), "Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead" )
455
+ if isHttpHandler {
456
+ r .pass .Reportf (instr .Pos (), "Non-inherited new context, use function like `context.WithXXX` or `r.Context` instead" )
457
+ } else {
458
+ r .pass .Reportf (instr .Pos (), "Non-inherited new context, use function like `context.WithXXX` instead" )
459
+ }
500
460
}
501
461
}
502
462
503
- // only check if the ctx used in the current function is r.Context()
504
- if isHttpHandler {
505
- continue
506
- }
507
-
508
463
ff := r .getFunction (instr )
509
464
if ff == nil {
510
465
continue
@@ -564,13 +519,13 @@ func (r *runner) checkFuncWithoutCtx(f *ssa.Function, checkingMap map[string]boo
564
519
continue
565
520
}
566
521
567
- if entryType := r .checkIsEntry (ff ); entryType & Entry == 0 {
522
+ if entryType := r .checkIsEntry (ff ); entryType == EntryNone {
568
523
// cannot get info from fact, skip
569
524
if ff .Blocks == nil {
570
525
continue
571
526
}
572
527
573
- // handler ring call
528
+ // handler cycle call
574
529
if checkingMap [key ] {
575
530
continue
576
531
}
@@ -681,23 +636,21 @@ func (r *runner) isCtxType(tp types.Type) bool {
681
636
}
682
637
683
638
func (r * runner ) isHttpResType (tp types.Type ) bool {
684
- var ok bool
685
639
for _ , v := range r .httpResTyps {
686
- if ok = types .Identical (v , v ); ok {
687
- break
640
+ if ok : = types .Identical (v , v ); ok {
641
+ return true
688
642
}
689
643
}
690
- return ok
644
+ return false
691
645
}
692
646
693
647
func (r * runner ) isHttpReqType (tp types.Type ) bool {
694
- var ok bool
695
648
for _ , v := range r .httpReqTyps {
696
- if ok = types .Identical (tp , v ); ok {
697
- break
649
+ if ok : = types .Identical (tp , v ); ok {
650
+ return true
698
651
}
699
652
}
700
- return ok
653
+ return false
701
654
}
702
655
703
656
func (r * runner ) getValue (key string , f * ssa.Function ) (res resInfo , ok bool ) {
0 commit comments