honnef.co/go/tools@v0.4.7/staticcheck/lint.go (about) 1 package staticcheck 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/constant" 7 "go/token" 8 "go/types" 9 htmltemplate "html/template" 10 "net/http" 11 "os" 12 "reflect" 13 "regexp" 14 "regexp/syntax" 15 "sort" 16 "strconv" 17 "strings" 18 texttemplate "text/template" 19 "unicode" 20 21 "honnef.co/go/tools/analysis/code" 22 "honnef.co/go/tools/analysis/edit" 23 "honnef.co/go/tools/analysis/facts/deprecated" 24 "honnef.co/go/tools/analysis/facts/generated" 25 "honnef.co/go/tools/analysis/facts/nilness" 26 "honnef.co/go/tools/analysis/facts/purity" 27 "honnef.co/go/tools/analysis/facts/typedness" 28 "honnef.co/go/tools/analysis/lint" 29 "honnef.co/go/tools/analysis/report" 30 "honnef.co/go/tools/go/ast/astutil" 31 "honnef.co/go/tools/go/ir" 32 "honnef.co/go/tools/go/ir/irutil" 33 "honnef.co/go/tools/go/types/typeutil" 34 "honnef.co/go/tools/internal/passes/buildir" 35 "honnef.co/go/tools/internal/sharedcheck" 36 "honnef.co/go/tools/knowledge" 37 "honnef.co/go/tools/pattern" 38 "honnef.co/go/tools/printf" 39 "honnef.co/go/tools/staticcheck/fakejson" 40 "honnef.co/go/tools/staticcheck/fakereflect" 41 "honnef.co/go/tools/staticcheck/fakexml" 42 43 "golang.org/x/exp/typeparams" 44 "golang.org/x/tools/go/analysis" 45 "golang.org/x/tools/go/analysis/passes/inspect" 46 "golang.org/x/tools/go/ast/inspector" 47 ) 48 49 func checkSortSlice(call *Call) { 50 c := call.Instr.Common().StaticCallee() 51 arg := call.Args[0] 52 53 T := arg.Value.Value.Type().Underlying() 54 switch T.(type) { 55 case *types.Interface: 56 // we don't know. 57 // TODO(dh): if the value is a phi node we can look at its edges 58 if k, ok := arg.Value.Value.(*ir.Const); ok && k.Value == nil { 59 // literal nil, e.g. sort.Sort(nil, ...) 60 arg.Invalid(fmt.Sprintf("cannot call %s on nil literal", c)) 61 } 62 case *types.Slice: 63 // this is fine 64 default: 65 // this is not fine 66 arg.Invalid(fmt.Sprintf("%s must only be called on slices, was called on %s", c, T)) 67 } 68 } 69 70 func validRegexp(call *Call) { 71 arg := call.Args[0] 72 err := ValidateRegexp(arg.Value) 73 if err != nil { 74 arg.Invalid(err.Error()) 75 } 76 } 77 78 type runeSlice []rune 79 80 func (rs runeSlice) Len() int { return len(rs) } 81 func (rs runeSlice) Less(i int, j int) bool { return rs[i] < rs[j] } 82 func (rs runeSlice) Swap(i int, j int) { rs[i], rs[j] = rs[j], rs[i] } 83 84 func utf8Cutset(call *Call) { 85 arg := call.Args[1] 86 if InvalidUTF8(arg.Value) { 87 arg.Invalid(MsgInvalidUTF8) 88 } 89 } 90 91 func uniqueCutset(call *Call) { 92 arg := call.Args[1] 93 if !UniqueStringCutset(arg.Value) { 94 arg.Invalid(MsgNonUniqueCutset) 95 } 96 } 97 98 func unmarshalPointer(name string, arg int) CallCheck { 99 return func(call *Call) { 100 if !Pointer(call.Args[arg].Value) { 101 call.Args[arg].Invalid(fmt.Sprintf("%s expects to unmarshal into a pointer, but the provided value is not a pointer", name)) 102 } 103 } 104 } 105 106 func pointlessIntMath(call *Call) { 107 if ConvertedFromInt(call.Args[0].Value) { 108 call.Invalid(fmt.Sprintf("calling %s on a converted integer is pointless", irutil.CallName(call.Instr.Common()))) 109 } 110 } 111 112 func checkValidHostPort(arg int) CallCheck { 113 return func(call *Call) { 114 if !ValidHostPort(call.Args[arg].Value) { 115 call.Args[arg].Invalid(MsgInvalidHostPort) 116 } 117 } 118 } 119 120 var ( 121 checkRegexpRules = map[string]CallCheck{ 122 "regexp.MustCompile": validRegexp, 123 "regexp.Compile": validRegexp, 124 "regexp.Match": validRegexp, 125 "regexp.MatchReader": validRegexp, 126 "regexp.MatchString": validRegexp, 127 } 128 129 checkTimeParseRules = map[string]CallCheck{ 130 "time.Parse": func(call *Call) { 131 arg := call.Args[knowledge.Arg("time.Parse.layout")] 132 err := ValidateTimeLayout(arg.Value) 133 if err != nil { 134 arg.Invalid(err.Error()) 135 } 136 }, 137 } 138 139 checkEncodingBinaryRules = map[string]CallCheck{ 140 "encoding/binary.Write": func(call *Call) { 141 arg := call.Args[knowledge.Arg("encoding/binary.Write.data")] 142 if !CanBinaryMarshal(call.Pass, arg.Value) { 143 arg.Invalid(fmt.Sprintf("value of type %s cannot be used with binary.Write", arg.Value.Value.Type())) 144 } 145 }, 146 } 147 148 checkURLsRules = map[string]CallCheck{ 149 "net/url.Parse": func(call *Call) { 150 arg := call.Args[knowledge.Arg("net/url.Parse.rawurl")] 151 err := ValidateURL(arg.Value) 152 if err != nil { 153 arg.Invalid(err.Error()) 154 } 155 }, 156 } 157 158 checkSyncPoolValueRules = map[string]CallCheck{ 159 "(*sync.Pool).Put": func(call *Call) { 160 arg := call.Args[knowledge.Arg("(*sync.Pool).Put.x")] 161 typ := arg.Value.Value.Type() 162 _, isSlice := typ.Underlying().(*types.Slice) 163 if !typeutil.IsPointerLike(typ) || isSlice { 164 arg.Invalid("argument should be pointer-like to avoid allocations") 165 } 166 }, 167 } 168 169 checkRegexpFindAllRules = map[string]CallCheck{ 170 "(*regexp.Regexp).FindAll": RepeatZeroTimes("a FindAll method", 1), 171 "(*regexp.Regexp).FindAllIndex": RepeatZeroTimes("a FindAll method", 1), 172 "(*regexp.Regexp).FindAllString": RepeatZeroTimes("a FindAll method", 1), 173 "(*regexp.Regexp).FindAllStringIndex": RepeatZeroTimes("a FindAll method", 1), 174 "(*regexp.Regexp).FindAllStringSubmatch": RepeatZeroTimes("a FindAll method", 1), 175 "(*regexp.Regexp).FindAllStringSubmatchIndex": RepeatZeroTimes("a FindAll method", 1), 176 "(*regexp.Regexp).FindAllSubmatch": RepeatZeroTimes("a FindAll method", 1), 177 "(*regexp.Regexp).FindAllSubmatchIndex": RepeatZeroTimes("a FindAll method", 1), 178 } 179 180 checkUTF8CutsetRules = map[string]CallCheck{ 181 "strings.IndexAny": utf8Cutset, 182 "strings.LastIndexAny": utf8Cutset, 183 "strings.ContainsAny": utf8Cutset, 184 "strings.Trim": utf8Cutset, 185 "strings.TrimLeft": utf8Cutset, 186 "strings.TrimRight": utf8Cutset, 187 } 188 189 checkUniqueCutsetRules = map[string]CallCheck{ 190 "strings.Trim": uniqueCutset, 191 "strings.TrimLeft": uniqueCutset, 192 "strings.TrimRight": uniqueCutset, 193 } 194 195 checkUnmarshalPointerRules = map[string]CallCheck{ 196 "encoding/xml.Unmarshal": unmarshalPointer("xml.Unmarshal", 1), 197 "(*encoding/xml.Decoder).Decode": unmarshalPointer("Decode", 0), 198 "(*encoding/xml.Decoder).DecodeElement": unmarshalPointer("DecodeElement", 0), 199 "encoding/json.Unmarshal": unmarshalPointer("json.Unmarshal", 1), 200 "(*encoding/json.Decoder).Decode": unmarshalPointer("Decode", 0), 201 } 202 203 checkUnbufferedSignalChanRules = map[string]CallCheck{ 204 "os/signal.Notify": func(call *Call) { 205 arg := call.Args[knowledge.Arg("os/signal.Notify.c")] 206 if UnbufferedChannel(arg.Value) { 207 arg.Invalid("the channel used with signal.Notify should be buffered") 208 } 209 }, 210 } 211 212 checkMathIntRules = map[string]CallCheck{ 213 "math.Ceil": pointlessIntMath, 214 "math.Floor": pointlessIntMath, 215 "math.IsNaN": pointlessIntMath, 216 "math.Trunc": pointlessIntMath, 217 "math.IsInf": pointlessIntMath, 218 } 219 220 checkStringsReplaceZeroRules = map[string]CallCheck{ 221 "strings.Replace": RepeatZeroTimes("strings.Replace", 3), 222 "bytes.Replace": RepeatZeroTimes("bytes.Replace", 3), 223 } 224 225 checkListenAddressRules = map[string]CallCheck{ 226 "net/http.ListenAndServe": checkValidHostPort(0), 227 "net/http.ListenAndServeTLS": checkValidHostPort(0), 228 } 229 230 checkBytesEqualIPRules = map[string]CallCheck{ 231 "bytes.Equal": func(call *Call) { 232 if ConvertedFrom(call.Args[knowledge.Arg("bytes.Equal.a")].Value, "net.IP") && 233 ConvertedFrom(call.Args[knowledge.Arg("bytes.Equal.b")].Value, "net.IP") { 234 call.Invalid("use net.IP.Equal to compare net.IPs, not bytes.Equal") 235 } 236 }, 237 } 238 239 checkRegexpMatchLoopRules = map[string]CallCheck{ 240 "regexp.Match": loopedRegexp("regexp.Match"), 241 "regexp.MatchReader": loopedRegexp("regexp.MatchReader"), 242 "regexp.MatchString": loopedRegexp("regexp.MatchString"), 243 } 244 245 checkNoopMarshal = map[string]CallCheck{ 246 // TODO(dh): should we really flag XML? Even an empty struct 247 // produces a non-zero amount of data, namely its type name. 248 // Let's see if we encounter any false positives. 249 // 250 // Also, should we flag gob? 251 "encoding/json.Marshal": checkNoopMarshalImpl(knowledge.Arg("json.Marshal.v"), "MarshalJSON", "MarshalText"), 252 "encoding/xml.Marshal": checkNoopMarshalImpl(knowledge.Arg("xml.Marshal.v"), "MarshalXML", "MarshalText"), 253 "(*encoding/json.Encoder).Encode": checkNoopMarshalImpl(knowledge.Arg("(*encoding/json.Encoder).Encode.v"), "MarshalJSON", "MarshalText"), 254 "(*encoding/xml.Encoder).Encode": checkNoopMarshalImpl(knowledge.Arg("(*encoding/xml.Encoder).Encode.v"), "MarshalXML", "MarshalText"), 255 256 "encoding/json.Unmarshal": checkNoopMarshalImpl(knowledge.Arg("json.Unmarshal.v"), "UnmarshalJSON", "UnmarshalText"), 257 "encoding/xml.Unmarshal": checkNoopMarshalImpl(knowledge.Arg("xml.Unmarshal.v"), "UnmarshalXML", "UnmarshalText"), 258 "(*encoding/json.Decoder).Decode": checkNoopMarshalImpl(knowledge.Arg("(*encoding/json.Decoder).Decode.v"), "UnmarshalJSON", "UnmarshalText"), 259 "(*encoding/xml.Decoder).Decode": checkNoopMarshalImpl(knowledge.Arg("(*encoding/xml.Decoder).Decode.v"), "UnmarshalXML", "UnmarshalText"), 260 } 261 262 checkUnsupportedMarshal = map[string]CallCheck{ 263 "encoding/json.Marshal": checkUnsupportedMarshalJSON, 264 "encoding/xml.Marshal": checkUnsupportedMarshalXML, 265 "(*encoding/json.Encoder).Encode": checkUnsupportedMarshalJSON, 266 "(*encoding/xml.Encoder).Encode": checkUnsupportedMarshalXML, 267 } 268 269 checkAtomicAlignment = map[string]CallCheck{ 270 "sync/atomic.AddInt64": checkAtomicAlignmentImpl, 271 "sync/atomic.AddUint64": checkAtomicAlignmentImpl, 272 "sync/atomic.CompareAndSwapInt64": checkAtomicAlignmentImpl, 273 "sync/atomic.CompareAndSwapUint64": checkAtomicAlignmentImpl, 274 "sync/atomic.LoadInt64": checkAtomicAlignmentImpl, 275 "sync/atomic.LoadUint64": checkAtomicAlignmentImpl, 276 "sync/atomic.StoreInt64": checkAtomicAlignmentImpl, 277 "sync/atomic.StoreUint64": checkAtomicAlignmentImpl, 278 "sync/atomic.SwapInt64": checkAtomicAlignmentImpl, 279 "sync/atomic.SwapUint64": checkAtomicAlignmentImpl, 280 } 281 282 // TODO(dh): detect printf wrappers 283 checkPrintfRules = map[string]CallCheck{ 284 "fmt.Errorf": func(call *Call) { checkPrintfCall(call, 0, 1) }, 285 "fmt.Printf": func(call *Call) { checkPrintfCall(call, 0, 1) }, 286 "fmt.Sprintf": func(call *Call) { checkPrintfCall(call, 0, 1) }, 287 "fmt.Fprintf": func(call *Call) { checkPrintfCall(call, 1, 2) }, 288 "golang.org/x/xerrors.Errorf": func(call *Call) { checkPrintfCall(call, 0, 1) }, 289 } 290 291 checkSortSliceRules = map[string]CallCheck{ 292 "sort.Slice": checkSortSlice, 293 "sort.SliceIsSorted": checkSortSlice, 294 "sort.SliceStable": checkSortSlice, 295 } 296 297 checkWithValueKeyRules = map[string]CallCheck{ 298 "context.WithValue": checkWithValueKey, 299 } 300 301 checkStrconvRules = map[string]CallCheck{ 302 "strconv.ParseComplex": func(call *Call) { 303 validateComplexBitSize(call.Args[knowledge.Arg("strconv.ParseComplex.bitSize")]) 304 }, 305 "strconv.ParseFloat": func(call *Call) { 306 validateFloatBitSize(call.Args[knowledge.Arg("strconv.ParseFloat.bitSize")]) 307 }, 308 "strconv.ParseInt": func(call *Call) { 309 validateContinuousBitSize(call.Args[knowledge.Arg("strconv.ParseInt.bitSize")], 0, 64) 310 validateIntBaseAllowZero(call.Args[knowledge.Arg("strconv.ParseInt.base")]) 311 }, 312 "strconv.ParseUint": func(call *Call) { 313 validateContinuousBitSize(call.Args[knowledge.Arg("strconv.ParseUint.bitSize")], 0, 64) 314 validateIntBaseAllowZero(call.Args[knowledge.Arg("strconv.ParseUint.base")]) 315 }, 316 317 "strconv.FormatComplex": func(call *Call) { 318 validateComplexFormat(call.Args[knowledge.Arg("strconv.FormatComplex.fmt")]) 319 validateComplexBitSize(call.Args[knowledge.Arg("strconv.FormatComplex.bitSize")]) 320 }, 321 "strconv.FormatFloat": func(call *Call) { 322 validateFloatFormat(call.Args[knowledge.Arg("strconv.FormatFloat.fmt")]) 323 validateFloatBitSize(call.Args[knowledge.Arg("strconv.FormatFloat.bitSize")]) 324 }, 325 "strconv.FormatInt": func(call *Call) { 326 validateIntBase(call.Args[knowledge.Arg("strconv.FormatInt.base")]) 327 }, 328 "strconv.FormatUint": func(call *Call) { 329 validateIntBase(call.Args[knowledge.Arg("strconv.FormatUint.base")]) 330 }, 331 332 "strconv.AppendFloat": func(call *Call) { 333 validateFloatFormat(call.Args[knowledge.Arg("strconv.AppendFloat.fmt")]) 334 validateFloatBitSize(call.Args[knowledge.Arg("strconv.AppendFloat.bitSize")]) 335 }, 336 "strconv.AppendInt": func(call *Call) { 337 validateIntBase(call.Args[knowledge.Arg("strconv.AppendInt.base")]) 338 }, 339 "strconv.AppendUint": func(call *Call) { 340 validateIntBase(call.Args[knowledge.Arg("strconv.AppendUint.base")]) 341 }, 342 } 343 ) 344 345 func validateIntBase(arg *Argument) { 346 if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil { 347 val, _ := constant.Int64Val(c.Value) 348 if val < 2 { 349 arg.Invalid("'base' must not be smaller than 2") 350 } 351 if val > 36 { 352 arg.Invalid("'base' must not be larger than 36") 353 } 354 } 355 } 356 357 func validateIntBaseAllowZero(arg *Argument) { 358 if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil { 359 val, _ := constant.Int64Val(c.Value) 360 if val < 2 && val != 0 { 361 arg.Invalid("'base' must not be smaller than 2, unless it is 0") 362 } 363 if val > 36 { 364 arg.Invalid("'base' must not be larger than 36") 365 } 366 } 367 } 368 369 func validateComplexFormat(arg *Argument) { 370 validateFloatFormat(arg) 371 } 372 373 func validateFloatFormat(arg *Argument) { 374 if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil { 375 val, _ := constant.Int64Val(c.Value) 376 switch val { 377 case 'b', 'e', 'E', 'f', 'g', 'G', 'x', 'X': 378 default: 379 arg.Invalid(fmt.Sprintf("'fmt' argument is invalid: unknown format %q", val)) 380 } 381 } 382 } 383 384 func validateComplexBitSize(arg *Argument) { validateDiscreetBitSize(arg, 64, 128) } 385 func validateFloatBitSize(arg *Argument) { validateDiscreetBitSize(arg, 32, 64) } 386 387 func validateDiscreetBitSize(arg *Argument, size1 int, size2 int) { 388 if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil { 389 val, _ := constant.Int64Val(c.Value) 390 if val != int64(size1) && val != int64(size2) { 391 arg.Invalid(fmt.Sprintf("'bitSize' argument is invalid, must be either %d or %d", size1, size2)) 392 } 393 } 394 } 395 396 func validateContinuousBitSize(arg *Argument, min int, max int) { 397 if c := extractConstExpectKind(arg.Value.Value, constant.Int); c != nil { 398 val, _ := constant.Int64Val(c.Value) 399 if val < int64(min) || val > int64(max) { 400 arg.Invalid(fmt.Sprintf("'bitSize' argument is invalid, must be within %d and %d", min, max)) 401 } 402 } 403 } 404 405 func checkPrintfCall(call *Call, fIdx, vIdx int) { 406 f := call.Args[fIdx] 407 var args []ir.Value 408 switch v := call.Args[vIdx].Value.Value.(type) { 409 case *ir.Slice: 410 var ok bool 411 args, ok = irutil.Vararg(v) 412 if !ok { 413 // We don't know what the actual arguments to the function are 414 return 415 } 416 case *ir.Const: 417 // nil, i.e. no arguments 418 default: 419 // We don't know what the actual arguments to the function are 420 return 421 } 422 checkPrintfCallImpl(f, f.Value.Value, args) 423 } 424 425 type verbFlag int 426 427 const ( 428 isInt verbFlag = 1 << iota 429 isBool 430 isFP 431 isString 432 isPointer 433 // Verbs that accept "pseudo pointers" will sometimes dereference 434 // non-nil pointers. For example, %x on a non-nil *struct will print the 435 // individual fields, but on a nil pointer it will print the address. 436 isPseudoPointer 437 isSlice 438 isAny 439 noRecurse 440 ) 441 442 var verbs = [...]verbFlag{ 443 'b': isPseudoPointer | isInt | isFP, 444 'c': isInt, 445 'd': isPseudoPointer | isInt, 446 'e': isFP, 447 'E': isFP, 448 'f': isFP, 449 'F': isFP, 450 'g': isFP, 451 'G': isFP, 452 'o': isPseudoPointer | isInt, 453 'O': isPseudoPointer | isInt, 454 'p': isSlice | isPointer | noRecurse, 455 'q': isInt | isString, 456 's': isString, 457 't': isBool, 458 'T': isAny, 459 'U': isInt, 460 'v': isAny, 461 'X': isPseudoPointer | isInt | isFP | isString, 462 'x': isPseudoPointer | isInt | isFP | isString, 463 } 464 465 func checkPrintfCallImpl(carg *Argument, f ir.Value, args []ir.Value) { 466 var msCache *typeutil.MethodSetCache 467 if f.Parent() != nil { 468 msCache = &f.Parent().Prog.MethodSets 469 } 470 471 elem := func(T types.Type, verb rune) ([]types.Type, bool) { 472 if verbs[verb]&noRecurse != 0 { 473 return []types.Type{T}, false 474 } 475 switch T := T.(type) { 476 case *types.Slice: 477 if verbs[verb]&isSlice != 0 { 478 return []types.Type{T}, false 479 } 480 if verbs[verb]&isString != 0 && typeutil.IsType(T.Elem().Underlying(), "byte") { 481 return []types.Type{T}, false 482 } 483 return []types.Type{T.Elem()}, true 484 case *types.Map: 485 key := T.Key() 486 val := T.Elem() 487 return []types.Type{key, val}, true 488 case *types.Struct: 489 out := make([]types.Type, 0, T.NumFields()) 490 for i := 0; i < T.NumFields(); i++ { 491 out = append(out, T.Field(i).Type()) 492 } 493 return out, true 494 case *types.Array: 495 return []types.Type{T.Elem()}, true 496 default: 497 return []types.Type{T}, false 498 } 499 } 500 isInfo := func(T types.Type, info types.BasicInfo) bool { 501 basic, ok := T.Underlying().(*types.Basic) 502 return ok && basic.Info()&info != 0 503 } 504 505 isFormatter := func(T types.Type, ms *types.MethodSet) bool { 506 sel := ms.Lookup(nil, "Format") 507 if sel == nil { 508 return false 509 } 510 fn, ok := sel.Obj().(*types.Func) 511 if !ok { 512 // should be unreachable 513 return false 514 } 515 sig := fn.Type().(*types.Signature) 516 if sig.Params().Len() != 2 { 517 return false 518 } 519 // TODO(dh): check the types of the arguments for more 520 // precision 521 if sig.Results().Len() != 0 { 522 return false 523 } 524 return true 525 } 526 527 var seen typeutil.Map[struct{}] 528 var checkType func(verb rune, T types.Type, top bool) bool 529 checkType = func(verb rune, T types.Type, top bool) bool { 530 if top { 531 seen = typeutil.Map[struct{}]{} 532 } 533 if _, ok := seen.At(T); ok { 534 return true 535 } 536 seen.Set(T, struct{}{}) 537 if int(verb) >= len(verbs) { 538 // Unknown verb 539 return true 540 } 541 542 flags := verbs[verb] 543 if flags == 0 { 544 // Unknown verb 545 return true 546 } 547 548 ms := msCache.MethodSet(T) 549 if isFormatter(T, ms) { 550 // the value is responsible for formatting itself 551 return true 552 } 553 554 if flags&isString != 0 && (types.Implements(T, knowledge.Interfaces["fmt.Stringer"]) || types.Implements(T, knowledge.Interfaces["error"])) { 555 // Check for stringer early because we're about to dereference 556 return true 557 } 558 559 T = T.Underlying() 560 if flags&(isPointer|isPseudoPointer) == 0 && top { 561 T = typeutil.Dereference(T) 562 } 563 if flags&isPseudoPointer != 0 && top { 564 t := typeutil.Dereference(T) 565 if _, ok := t.Underlying().(*types.Struct); ok { 566 T = t 567 } 568 } 569 570 if _, ok := T.(*types.Interface); ok { 571 // We don't know what's in the interface 572 return true 573 } 574 575 var info types.BasicInfo 576 if flags&isInt != 0 { 577 info |= types.IsInteger 578 } 579 if flags&isBool != 0 { 580 info |= types.IsBoolean 581 } 582 if flags&isFP != 0 { 583 info |= types.IsFloat | types.IsComplex 584 } 585 if flags&isString != 0 { 586 info |= types.IsString 587 } 588 589 if info != 0 && isInfo(T, info) { 590 return true 591 } 592 593 if flags&isString != 0 { 594 isStringyElem := func(typ types.Type) bool { 595 if typ, ok := typ.Underlying().(*types.Basic); ok { 596 return typ.Kind() == types.Byte 597 } 598 return false 599 } 600 switch T := T.(type) { 601 case *types.Slice: 602 if isStringyElem(T.Elem()) { 603 return true 604 } 605 case *types.Array: 606 if isStringyElem(T.Elem()) { 607 return true 608 } 609 } 610 if types.Implements(T, knowledge.Interfaces["fmt.Stringer"]) || types.Implements(T, knowledge.Interfaces["error"]) { 611 return true 612 } 613 } 614 615 if flags&isPointer != 0 && typeutil.IsPointerLike(T) { 616 return true 617 } 618 if flags&isPseudoPointer != 0 { 619 switch U := T.Underlying().(type) { 620 case *types.Pointer: 621 if !top { 622 return true 623 } 624 625 if _, ok := U.Elem().Underlying().(*types.Struct); !ok { 626 // TODO(dh): can this condition ever be false? For 627 // *T, if T is a struct, we'll already have 628 // dereferenced it, meaning the *types.Pointer 629 // branch couldn't have been taken. For T that 630 // aren't structs, this condition will always 631 // evaluate to true. 632 return true 633 } 634 case *types.Chan, *types.Signature: 635 // Channels and functions are always treated as 636 // pointers and never recursed into. 637 return true 638 case *types.Basic: 639 if U.Kind() == types.UnsafePointer { 640 return true 641 } 642 case *types.Interface: 643 // we will already have bailed if the type is an 644 // interface. 645 panic("unreachable") 646 default: 647 // other pointer-like types, such as maps or slices, 648 // will be printed element-wise. 649 } 650 } 651 652 if flags&isSlice != 0 { 653 if _, ok := T.(*types.Slice); ok { 654 return true 655 } 656 } 657 658 if flags&isAny != 0 { 659 return true 660 } 661 662 elems, ok := elem(T.Underlying(), verb) 663 if !ok { 664 return false 665 } 666 for _, elem := range elems { 667 if !checkType(verb, elem, false) { 668 return false 669 } 670 } 671 672 return true 673 } 674 675 k, ok := irutil.Flatten(f).(*ir.Const) 676 if !ok { 677 return 678 } 679 actions, err := printf.Parse(constant.StringVal(k.Value)) 680 if err != nil { 681 carg.Invalid("couldn't parse format string") 682 return 683 } 684 685 ptr := 1 686 hasExplicit := false 687 688 checkStar := func(verb printf.Verb, star printf.Argument) bool { 689 if star, ok := star.(printf.Star); ok { 690 idx := 0 691 if star.Index == -1 { 692 idx = ptr 693 ptr++ 694 } else { 695 hasExplicit = true 696 idx = star.Index 697 ptr = star.Index + 1 698 } 699 if idx == 0 { 700 carg.Invalid(fmt.Sprintf("Printf format %s reads invalid arg 0; indices are 1-based", verb.Raw)) 701 return false 702 } 703 if idx > len(args) { 704 carg.Invalid( 705 fmt.Sprintf("Printf format %s reads arg #%d, but call has only %d args", 706 verb.Raw, idx, len(args))) 707 return false 708 } 709 if arg, ok := args[idx-1].(*ir.MakeInterface); ok { 710 if !isInfo(arg.X.Type(), types.IsInteger) { 711 carg.Invalid(fmt.Sprintf("Printf format %s reads non-int arg #%d as argument of *", verb.Raw, idx)) 712 } 713 } 714 } 715 return true 716 } 717 718 // We only report one problem per format string. Making a 719 // mistake with an index tends to invalidate all future 720 // implicit indices. 721 for _, action := range actions { 722 verb, ok := action.(printf.Verb) 723 if !ok { 724 continue 725 } 726 727 if !checkStar(verb, verb.Width) || !checkStar(verb, verb.Precision) { 728 return 729 } 730 731 off := ptr 732 if verb.Value != -1 { 733 hasExplicit = true 734 off = verb.Value 735 } 736 if off > len(args) { 737 carg.Invalid( 738 fmt.Sprintf("Printf format %s reads arg #%d, but call has only %d args", 739 verb.Raw, off, len(args))) 740 return 741 } else if verb.Value == 0 && verb.Letter != '%' { 742 carg.Invalid(fmt.Sprintf("Printf format %s reads invalid arg 0; indices are 1-based", verb.Raw)) 743 return 744 } else if off != 0 { 745 arg, ok := args[off-1].(*ir.MakeInterface) 746 if ok { 747 if !checkType(verb.Letter, arg.X.Type(), true) { 748 carg.Invalid(fmt.Sprintf("Printf format %s has arg #%d of wrong type %s", 749 verb.Raw, ptr, args[ptr-1].(*ir.MakeInterface).X.Type())) 750 return 751 } 752 } 753 } 754 755 switch verb.Value { 756 case -1: 757 // Consume next argument 758 ptr++ 759 case 0: 760 // Don't consume any arguments 761 default: 762 ptr = verb.Value + 1 763 } 764 } 765 766 if !hasExplicit && ptr <= len(args) { 767 carg.Invalid(fmt.Sprintf("Printf call needs %d args but has %d args", ptr-1, len(args))) 768 } 769 } 770 771 func checkAtomicAlignmentImpl(call *Call) { 772 sizes := call.Pass.TypesSizes 773 if sizes.Sizeof(types.Typ[types.Uintptr]) != 4 { 774 // Not running on a 32-bit platform 775 return 776 } 777 v, ok := irutil.Flatten(call.Args[0].Value.Value).(*ir.FieldAddr) 778 if !ok { 779 // TODO(dh): also check indexing into arrays and slices 780 return 781 } 782 T := v.X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct) 783 fields := make([]*types.Var, 0, T.NumFields()) 784 for i := 0; i < T.NumFields() && i <= v.Field; i++ { 785 fields = append(fields, T.Field(i)) 786 } 787 788 off := sizes.Offsetsof(fields)[v.Field] 789 if off%8 != 0 { 790 msg := fmt.Sprintf("address of non 64-bit aligned field %s passed to %s", 791 T.Field(v.Field).Name(), 792 irutil.CallName(call.Instr.Common())) 793 call.Invalid(msg) 794 } 795 } 796 797 func checkNoopMarshalImpl(argN int, meths ...string) CallCheck { 798 return func(call *Call) { 799 if code.IsGenerated(call.Pass, call.Instr.Pos()) { 800 return 801 } 802 arg := call.Args[argN] 803 T := arg.Value.Value.Type() 804 Ts, ok := typeutil.Dereference(T).Underlying().(*types.Struct) 805 if !ok { 806 return 807 } 808 if Ts.NumFields() == 0 { 809 return 810 } 811 fields := typeutil.FlattenFields(Ts) 812 for _, field := range fields { 813 if field.Var.Exported() { 814 return 815 } 816 } 817 // OPT(dh): we could use a method set cache here 818 ms := call.Instr.Parent().Prog.MethodSets.MethodSet(T) 819 // TODO(dh): we're not checking the signature, which can cause false negatives. 820 // This isn't a huge problem, however, since vet complains about incorrect signatures. 821 for _, meth := range meths { 822 if ms.Lookup(nil, meth) != nil { 823 return 824 } 825 } 826 arg.Invalid(fmt.Sprintf("struct type '%s' doesn't have any exported fields, nor custom marshaling", typeutil.Dereference(T))) 827 } 828 } 829 830 func checkUnsupportedMarshalJSON(call *Call) { 831 arg := call.Args[0] 832 T := arg.Value.Value.Type() 833 if err := fakejson.Marshal(T); err != nil { 834 typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg)) 835 if err.Path == "x" { 836 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ)) 837 } else { 838 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path)) 839 } 840 } 841 } 842 843 func checkUnsupportedMarshalXML(call *Call) { 844 arg := call.Args[0] 845 T := arg.Value.Value.Type() 846 if err := fakexml.Marshal(T); err != nil { 847 switch err := err.(type) { 848 case *fakexml.UnsupportedTypeError: 849 typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg)) 850 if err.Path == "x" { 851 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s", typ)) 852 } else { 853 arg.Invalid(fmt.Sprintf("trying to marshal unsupported type %s, via %s", typ, err.Path)) 854 } 855 case *fakexml.CyclicTypeError: 856 typ := types.TypeString(err.Type, types.RelativeTo(arg.Value.Value.Parent().Pkg.Pkg)) 857 if err.Path == "x" { 858 arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s", typ)) 859 } else { 860 arg.Invalid(fmt.Sprintf("trying to marshal cyclic type %s, via %s", typ, err.Path)) 861 } 862 case *fakexml.TagPathError: 863 // Vet does a better job at reporting this error, because it can flag the actual struct tags, not just the call to Marshal 864 default: 865 // These errors get reported by SA5008 instead, which can flag the actual fields, independently of calls to xml.Marshal 866 } 867 } 868 } 869 870 func isInLoop(b *ir.BasicBlock) bool { 871 sets := irutil.FindLoops(b.Parent()) 872 for _, set := range sets { 873 if set.Has(b) { 874 return true 875 } 876 } 877 return false 878 } 879 880 func CheckUntrappableSignal(pass *analysis.Pass) (interface{}, error) { 881 isSignal := func(pass *analysis.Pass, expr ast.Expr, name string) bool { 882 if expr, ok := expr.(*ast.SelectorExpr); ok { 883 return code.SelectorName(pass, expr) == name 884 } else { 885 return false 886 } 887 } 888 889 fn := func(node ast.Node) { 890 call := node.(*ast.CallExpr) 891 if !code.IsCallToAny(pass, call, 892 "os/signal.Ignore", "os/signal.Notify", "os/signal.Reset") { 893 return 894 } 895 896 hasSigterm := false 897 for _, arg := range call.Args { 898 if conv, ok := arg.(*ast.CallExpr); ok && isSignal(pass, conv.Fun, "os.Signal") { 899 arg = conv.Args[0] 900 } 901 902 if isSignal(pass, arg, "syscall.SIGTERM") { 903 hasSigterm = true 904 break 905 } 906 907 } 908 for i, arg := range call.Args { 909 if conv, ok := arg.(*ast.CallExpr); ok && isSignal(pass, conv.Fun, "os.Signal") { 910 arg = conv.Args[0] 911 } 912 913 if isSignal(pass, arg, "os.Kill") || isSignal(pass, arg, "syscall.SIGKILL") { 914 var fixes []analysis.SuggestedFix 915 if !hasSigterm { 916 nargs := make([]ast.Expr, len(call.Args)) 917 for j, a := range call.Args { 918 if i == j { 919 nargs[j] = edit.Selector("syscall", "SIGTERM") 920 } else { 921 nargs[j] = a 922 } 923 } 924 ncall := *call 925 ncall.Args = nargs 926 fixes = append(fixes, edit.Fix(fmt.Sprintf("use syscall.SIGTERM instead of %s", report.Render(pass, arg)), edit.ReplaceWithNode(pass.Fset, call, &ncall))) 927 } 928 nargs := make([]ast.Expr, 0, len(call.Args)) 929 for j, a := range call.Args { 930 if i == j { 931 continue 932 } 933 nargs = append(nargs, a) 934 } 935 ncall := *call 936 ncall.Args = nargs 937 fixes = append(fixes, edit.Fix(fmt.Sprintf("remove %s from list of arguments", report.Render(pass, arg)), edit.ReplaceWithNode(pass.Fset, call, &ncall))) 938 report.Report(pass, arg, fmt.Sprintf("%s cannot be trapped (did you mean syscall.SIGTERM?)", report.Render(pass, arg)), report.Fixes(fixes...)) 939 } 940 if isSignal(pass, arg, "syscall.SIGSTOP") { 941 nargs := make([]ast.Expr, 0, len(call.Args)-1) 942 for j, a := range call.Args { 943 if i == j { 944 continue 945 } 946 nargs = append(nargs, a) 947 } 948 ncall := *call 949 ncall.Args = nargs 950 report.Report(pass, arg, "syscall.SIGSTOP cannot be trapped", report.Fixes(edit.Fix("remove syscall.SIGSTOP from list of arguments", edit.ReplaceWithNode(pass.Fset, call, &ncall)))) 951 } 952 } 953 } 954 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 955 return nil, nil 956 } 957 958 func CheckTemplate(pass *analysis.Pass) (interface{}, error) { 959 fn := func(node ast.Node) { 960 call := node.(*ast.CallExpr) 961 // OPT(dh): use integer for kind 962 var kind string 963 switch code.CallName(pass, call) { 964 case "(*text/template.Template).Parse": 965 kind = "text" 966 case "(*html/template.Template).Parse": 967 kind = "html" 968 default: 969 return 970 } 971 sel := call.Fun.(*ast.SelectorExpr) 972 if !code.IsCallToAny(pass, sel.X, "text/template.New", "html/template.New") { 973 // TODO(dh): this is a cheap workaround for templates with 974 // different delims. A better solution with less false 975 // negatives would use data flow analysis to see where the 976 // template comes from and where it has been 977 return 978 } 979 s, ok := code.ExprToString(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")]) 980 if !ok { 981 return 982 } 983 var err error 984 switch kind { 985 case "text": 986 _, err = texttemplate.New("").Parse(s) 987 case "html": 988 _, err = htmltemplate.New("").Parse(s) 989 } 990 if err != nil { 991 // TODO(dominikh): whitelist other parse errors, if any 992 if strings.Contains(err.Error(), "unexpected") || 993 strings.Contains(err.Error(), "bad character") { 994 report.Report(pass, call.Args[knowledge.Arg("(*text/template.Template).Parse.text")], err.Error()) 995 } 996 } 997 } 998 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 999 return nil, nil 1000 } 1001 1002 var ( 1003 checkTimeSleepConstantPatternQ = pattern.MustParse(`(CallExpr (Symbol "time.Sleep") lit@(IntegerLiteral value))`) 1004 checkTimeSleepConstantPatternRns = pattern.MustParse(`(BinaryExpr duration "*" (SelectorExpr (Ident "time") (Ident "Nanosecond")))`) 1005 checkTimeSleepConstantPatternRs = pattern.MustParse(`(BinaryExpr duration "*" (SelectorExpr (Ident "time") (Ident "Second")))`) 1006 ) 1007 1008 func CheckTimeSleepConstant(pass *analysis.Pass) (interface{}, error) { 1009 fn := func(node ast.Node) { 1010 m, ok := code.Match(pass, checkTimeSleepConstantPatternQ, node) 1011 if !ok { 1012 return 1013 } 1014 n, ok := constant.Int64Val(m.State["value"].(types.TypeAndValue).Value) 1015 if !ok { 1016 return 1017 } 1018 if n == 0 || n > 120 { 1019 // time.Sleep(0) is a seldom used pattern in concurrency 1020 // tests. >120 might be intentional. 120 was chosen 1021 // because the user could've meant 2 minutes. 1022 return 1023 } 1024 1025 lit := m.State["lit"].(ast.Node) 1026 report.Report(pass, lit, 1027 fmt.Sprintf("sleeping for %d nanoseconds is probably a bug; be explicit if it isn't", n), report.Fixes( 1028 edit.Fix("explicitly use nanoseconds", edit.ReplaceWithPattern(pass.Fset, lit, checkTimeSleepConstantPatternRns, pattern.State{"duration": lit})), 1029 edit.Fix("use seconds", edit.ReplaceWithPattern(pass.Fset, lit, checkTimeSleepConstantPatternRs, pattern.State{"duration": lit})))) 1030 } 1031 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 1032 return nil, nil 1033 } 1034 1035 var checkWaitgroupAddQ = pattern.MustParse(` 1036 (GoStmt 1037 (CallExpr 1038 (FuncLit 1039 _ 1040 call@(CallExpr (Symbol "(*sync.WaitGroup).Add") _):_) _))`) 1041 1042 func CheckWaitgroupAdd(pass *analysis.Pass) (interface{}, error) { 1043 fn := func(node ast.Node) { 1044 if m, ok := code.Match(pass, checkWaitgroupAddQ, node); ok { 1045 call := m.State["call"].(ast.Node) 1046 report.Report(pass, call, fmt.Sprintf("should call %s before starting the goroutine to avoid a race", report.Render(pass, call))) 1047 } 1048 } 1049 code.Preorder(pass, fn, (*ast.GoStmt)(nil)) 1050 return nil, nil 1051 } 1052 1053 func CheckInfiniteEmptyLoop(pass *analysis.Pass) (interface{}, error) { 1054 fn := func(node ast.Node) { 1055 loop := node.(*ast.ForStmt) 1056 if len(loop.Body.List) != 0 || loop.Post != nil { 1057 return 1058 } 1059 1060 if loop.Init != nil { 1061 // TODO(dh): this isn't strictly necessary, it just makes 1062 // the check easier. 1063 return 1064 } 1065 // An empty loop is bad news in two cases: 1) The loop has no 1066 // condition. In that case, it's just a loop that spins 1067 // forever and as fast as it can, keeping a core busy. 2) The 1068 // loop condition only consists of variable or field reads and 1069 // operators on those. The only way those could change their 1070 // value is with unsynchronised access, which constitutes a 1071 // data race. 1072 // 1073 // If the condition contains any function calls, its behaviour 1074 // is dynamic and the loop might terminate. Similarly for 1075 // channel receives. 1076 1077 if loop.Cond != nil { 1078 if code.MayHaveSideEffects(pass, loop.Cond, nil) { 1079 return 1080 } 1081 if ident, ok := loop.Cond.(*ast.Ident); ok { 1082 if k, ok := pass.TypesInfo.ObjectOf(ident).(*types.Const); ok { 1083 if !constant.BoolVal(k.Val()) { 1084 // don't flag `for false {}` loops. They're a debug aid. 1085 return 1086 } 1087 } 1088 } 1089 report.Report(pass, loop, "loop condition never changes or has a race condition") 1090 } 1091 report.Report(pass, loop, "this loop will spin, using 100% CPU", report.ShortRange()) 1092 } 1093 code.Preorder(pass, fn, (*ast.ForStmt)(nil)) 1094 return nil, nil 1095 } 1096 1097 func CheckDeferInInfiniteLoop(pass *analysis.Pass) (interface{}, error) { 1098 fn := func(node ast.Node) { 1099 mightExit := false 1100 var defers []ast.Stmt 1101 loop := node.(*ast.ForStmt) 1102 if loop.Cond != nil { 1103 return 1104 } 1105 fn2 := func(node ast.Node) bool { 1106 switch stmt := node.(type) { 1107 case *ast.ReturnStmt: 1108 mightExit = true 1109 return false 1110 case *ast.BranchStmt: 1111 // TODO(dominikh): if this sees a break in a switch or 1112 // select, it doesn't check if it breaks the loop or 1113 // just the select/switch. This causes some false 1114 // negatives. 1115 if stmt.Tok == token.BREAK { 1116 mightExit = true 1117 return false 1118 } 1119 case *ast.DeferStmt: 1120 defers = append(defers, stmt) 1121 case *ast.FuncLit: 1122 // Don't look into function bodies 1123 return false 1124 } 1125 return true 1126 } 1127 ast.Inspect(loop.Body, fn2) 1128 if mightExit { 1129 return 1130 } 1131 for _, stmt := range defers { 1132 report.Report(pass, stmt, "defers in this infinite loop will never run") 1133 } 1134 } 1135 code.Preorder(pass, fn, (*ast.ForStmt)(nil)) 1136 return nil, nil 1137 } 1138 1139 func CheckDubiousDeferInChannelRangeLoop(pass *analysis.Pass) (interface{}, error) { 1140 fn := func(node ast.Node) { 1141 loop := node.(*ast.RangeStmt) 1142 typ := pass.TypesInfo.TypeOf(loop.X) 1143 _, ok := typeutil.CoreType(typ).(*types.Chan) 1144 if !ok { 1145 return 1146 } 1147 1148 stmts := []*ast.DeferStmt{} 1149 exits := false 1150 fn2 := func(node ast.Node) bool { 1151 switch stmt := node.(type) { 1152 case *ast.DeferStmt: 1153 stmts = append(stmts, stmt) 1154 case *ast.FuncLit: 1155 // Don't look into function bodies 1156 return false 1157 case *ast.ReturnStmt: 1158 exits = true 1159 case *ast.BranchStmt: 1160 exits = node.(*ast.BranchStmt).Tok == token.BREAK 1161 } 1162 return true 1163 } 1164 ast.Inspect(loop.Body, fn2) 1165 1166 if exits { 1167 return 1168 } 1169 for _, stmt := range stmts { 1170 report.Report(pass, stmt, "defers in this range loop won't run unless the channel gets closed") 1171 } 1172 } 1173 code.Preorder(pass, fn, (*ast.RangeStmt)(nil)) 1174 return nil, nil 1175 } 1176 1177 func CheckTestMainExit(pass *analysis.Pass) (interface{}, error) { 1178 if code.IsGoVersion(pass, 15) { 1179 // Beginning with Go 1.15, the test framework will call 1180 // os.Exit for us. 1181 return nil, nil 1182 } 1183 1184 var ( 1185 fnmain ast.Node 1186 callsExit bool 1187 callsRun bool 1188 arg types.Object 1189 ) 1190 fn := func(node ast.Node, push bool) bool { 1191 if !push { 1192 if fnmain != nil && node == fnmain { 1193 if !callsExit && callsRun { 1194 report.Report(pass, fnmain, "TestMain should call os.Exit to set exit code") 1195 } 1196 fnmain = nil 1197 callsExit = false 1198 callsRun = false 1199 arg = nil 1200 } 1201 return true 1202 } 1203 1204 switch node := node.(type) { 1205 case *ast.FuncDecl: 1206 if fnmain != nil { 1207 return true 1208 } 1209 if !isTestMain(pass, node) { 1210 return false 1211 } 1212 fnmain = node 1213 arg = pass.TypesInfo.ObjectOf(node.Type.Params.List[0].Names[0]) 1214 return true 1215 case *ast.CallExpr: 1216 if code.IsCallTo(pass, node, "os.Exit") { 1217 callsExit = true 1218 return false 1219 } 1220 sel, ok := node.Fun.(*ast.SelectorExpr) 1221 if !ok { 1222 return true 1223 } 1224 ident, ok := sel.X.(*ast.Ident) 1225 if !ok { 1226 return true 1227 } 1228 if arg != pass.TypesInfo.ObjectOf(ident) { 1229 return true 1230 } 1231 if sel.Sel.Name == "Run" { 1232 callsRun = true 1233 return false 1234 } 1235 return true 1236 default: 1237 lint.ExhaustiveTypeSwitch(node) 1238 return true 1239 } 1240 } 1241 pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes([]ast.Node{(*ast.FuncDecl)(nil), (*ast.CallExpr)(nil)}, fn) 1242 return nil, nil 1243 } 1244 1245 func isTestMain(pass *analysis.Pass, decl *ast.FuncDecl) bool { 1246 if decl.Name.Name != "TestMain" { 1247 return false 1248 } 1249 if len(decl.Type.Params.List) != 1 { 1250 return false 1251 } 1252 arg := decl.Type.Params.List[0] 1253 if len(arg.Names) != 1 { 1254 return false 1255 } 1256 return code.IsOfType(pass, arg.Type, "*testing.M") 1257 } 1258 1259 func CheckExec(pass *analysis.Pass) (interface{}, error) { 1260 fn := func(node ast.Node) { 1261 call := node.(*ast.CallExpr) 1262 if !code.IsCallTo(pass, call, "os/exec.Command") { 1263 return 1264 } 1265 val, ok := code.ExprToString(pass, call.Args[knowledge.Arg("os/exec.Command.name")]) 1266 if !ok { 1267 return 1268 } 1269 if !strings.Contains(val, " ") || strings.Contains(val, `\`) || strings.Contains(val, "/") { 1270 return 1271 } 1272 report.Report(pass, call.Args[knowledge.Arg("os/exec.Command.name")], 1273 "first argument to exec.Command looks like a shell command, but a program name or path are expected") 1274 } 1275 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 1276 return nil, nil 1277 } 1278 1279 func CheckLoopEmptyDefault(pass *analysis.Pass) (interface{}, error) { 1280 fn := func(node ast.Node) { 1281 loop := node.(*ast.ForStmt) 1282 if len(loop.Body.List) != 1 || loop.Cond != nil || loop.Init != nil { 1283 return 1284 } 1285 sel, ok := loop.Body.List[0].(*ast.SelectStmt) 1286 if !ok { 1287 return 1288 } 1289 for _, c := range sel.Body.List { 1290 // FIXME this leaves behind an empty line, and possibly 1291 // comments in the default branch. We can't easily fix 1292 // either. 1293 if comm, ok := c.(*ast.CommClause); ok && comm.Comm == nil && len(comm.Body) == 0 { 1294 report.Report(pass, comm, "should not have an empty default case in a for+select loop; the loop will spin", 1295 report.Fixes(edit.Fix("remove empty default branch", edit.Delete(comm)))) 1296 // there can only be one default case 1297 break 1298 } 1299 } 1300 } 1301 code.Preorder(pass, fn, (*ast.ForStmt)(nil)) 1302 return nil, nil 1303 } 1304 1305 func CheckLhsRhsIdentical(pass *analysis.Pass) (interface{}, error) { 1306 var isFloat func(T types.Type) bool 1307 isFloat = func(T types.Type) bool { 1308 tset := typeutil.NewTypeSet(T) 1309 if len(tset.Terms) == 0 { 1310 // no terms, so floats are a possibility 1311 return true 1312 } 1313 return tset.Any(func(term *types.Term) bool { 1314 switch typ := term.Type().Underlying().(type) { 1315 case *types.Basic: 1316 kind := typ.Kind() 1317 return kind == types.Float32 || kind == types.Float64 1318 case *types.Array: 1319 return isFloat(typ.Elem()) 1320 case *types.Struct: 1321 for i := 0; i < typ.NumFields(); i++ { 1322 if !isFloat(typ.Field(i).Type()) { 1323 return false 1324 } 1325 } 1326 return true 1327 default: 1328 return false 1329 } 1330 }) 1331 } 1332 1333 // TODO(dh): this check ignores the existence of side-effects and 1334 // happily flags fn() == fn() – so far, we've had nobody complain 1335 // about a false positive, and it's caught several bugs in real 1336 // code. 1337 // 1338 // We special case functions from the math/rand package. Someone ran 1339 // into the following false positive: "rand.Intn(2) - rand.Intn(2), which I wrote to generate values {-1, 0, 1} with {0.25, 0.5, 0.25} probability." 1340 fn := func(node ast.Node) { 1341 op := node.(*ast.BinaryExpr) 1342 switch op.Op { 1343 case token.EQL, token.NEQ: 1344 case token.SUB, token.QUO, token.AND, token.REM, token.OR, token.XOR, token.AND_NOT, 1345 token.LAND, token.LOR, token.LSS, token.GTR, token.LEQ, token.GEQ: 1346 default: 1347 // For some ops, such as + and *, it can make sense to 1348 // have identical operands 1349 return 1350 } 1351 1352 if isFloat(pass.TypesInfo.TypeOf(op.X)) { 1353 // 'float <op> float' makes sense for several operators. 1354 // We've tried keeping an exact list of operators to allow, but floats keep surprising us. Let's just give up instead. 1355 return 1356 } 1357 1358 if reflect.TypeOf(op.X) != reflect.TypeOf(op.Y) { 1359 return 1360 } 1361 if report.Render(pass, op.X) != report.Render(pass, op.Y) { 1362 return 1363 } 1364 l1, ok1 := op.X.(*ast.BasicLit) 1365 l2, ok2 := op.Y.(*ast.BasicLit) 1366 if ok1 && ok2 && l1.Kind == token.INT && l2.Kind == l1.Kind && l1.Value == "0" && l2.Value == l1.Value && code.IsGenerated(pass, l1.Pos()) { 1367 // cgo generates the following function call: 1368 // _cgoCheckPointer(_cgoBase0, 0 == 0) – it uses 0 == 0 1369 // instead of true in case the user shadowed the 1370 // identifier. Ideally we'd restrict this exception to 1371 // calls of _cgoCheckPointer, but it's not worth the 1372 // hassle of keeping track of the stack. <lit> <op> <lit> 1373 // are very rare to begin with, and we're mostly checking 1374 // for them to catch typos such as 1 == 1 where the user 1375 // meant to type i == 1. The odds of a false negative for 1376 // 0 == 0 are slim. 1377 return 1378 } 1379 1380 if expr, ok := op.X.(*ast.CallExpr); ok { 1381 call := code.CallName(pass, expr) 1382 switch call { 1383 case "math/rand.Int", 1384 "math/rand.Int31", 1385 "math/rand.Int31n", 1386 "math/rand.Int63", 1387 "math/rand.Int63n", 1388 "math/rand.Intn", 1389 "math/rand.Uint32", 1390 "math/rand.Uint64", 1391 "math/rand.ExpFloat64", 1392 "math/rand.Float32", 1393 "math/rand.Float64", 1394 "math/rand.NormFloat64", 1395 "(*math/rand.Rand).Int", 1396 "(*math/rand.Rand).Int31", 1397 "(*math/rand.Rand).Int31n", 1398 "(*math/rand.Rand).Int63", 1399 "(*math/rand.Rand).Int63n", 1400 "(*math/rand.Rand).Intn", 1401 "(*math/rand.Rand).Uint32", 1402 "(*math/rand.Rand).Uint64", 1403 "(*math/rand.Rand).ExpFloat64", 1404 "(*math/rand.Rand).Float32", 1405 "(*math/rand.Rand).Float64", 1406 "(*math/rand.Rand).NormFloat64": 1407 return 1408 } 1409 } 1410 1411 report.Report(pass, op, fmt.Sprintf("identical expressions on the left and right side of the '%s' operator", op.Op)) 1412 } 1413 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 1414 return nil, nil 1415 } 1416 1417 func CheckScopedBreak(pass *analysis.Pass) (interface{}, error) { 1418 fn := func(node ast.Node) { 1419 var body *ast.BlockStmt 1420 switch node := node.(type) { 1421 case *ast.ForStmt: 1422 body = node.Body 1423 case *ast.RangeStmt: 1424 body = node.Body 1425 default: 1426 lint.ExhaustiveTypeSwitch(node) 1427 } 1428 for _, stmt := range body.List { 1429 var blocks [][]ast.Stmt 1430 switch stmt := stmt.(type) { 1431 case *ast.SwitchStmt: 1432 for _, c := range stmt.Body.List { 1433 blocks = append(blocks, c.(*ast.CaseClause).Body) 1434 } 1435 case *ast.SelectStmt: 1436 for _, c := range stmt.Body.List { 1437 blocks = append(blocks, c.(*ast.CommClause).Body) 1438 } 1439 default: 1440 continue 1441 } 1442 1443 for _, body := range blocks { 1444 if len(body) == 0 { 1445 continue 1446 } 1447 lasts := []ast.Stmt{body[len(body)-1]} 1448 // TODO(dh): unfold all levels of nested block 1449 // statements, not just a single level if statement 1450 if ifs, ok := lasts[0].(*ast.IfStmt); ok { 1451 if len(ifs.Body.List) == 0 { 1452 continue 1453 } 1454 lasts[0] = ifs.Body.List[len(ifs.Body.List)-1] 1455 1456 if block, ok := ifs.Else.(*ast.BlockStmt); ok { 1457 if len(block.List) != 0 { 1458 lasts = append(lasts, block.List[len(block.List)-1]) 1459 } 1460 } 1461 } 1462 for _, last := range lasts { 1463 branch, ok := last.(*ast.BranchStmt) 1464 if !ok || branch.Tok != token.BREAK || branch.Label != nil { 1465 continue 1466 } 1467 report.Report(pass, branch, "ineffective break statement. Did you mean to break out of the outer loop?") 1468 } 1469 } 1470 } 1471 } 1472 code.Preorder(pass, fn, (*ast.ForStmt)(nil), (*ast.RangeStmt)(nil)) 1473 return nil, nil 1474 } 1475 1476 func CheckUnsafePrintf(pass *analysis.Pass) (interface{}, error) { 1477 fn := func(node ast.Node) { 1478 call := node.(*ast.CallExpr) 1479 name := code.CallName(pass, call) 1480 var arg int 1481 1482 switch name { 1483 case "fmt.Printf", "fmt.Sprintf", "log.Printf": 1484 arg = knowledge.Arg("fmt.Printf.format") 1485 case "fmt.Fprintf": 1486 arg = knowledge.Arg("fmt.Fprintf.format") 1487 default: 1488 return 1489 } 1490 if len(call.Args) != arg+1 { 1491 return 1492 } 1493 switch call.Args[arg].(type) { 1494 case *ast.CallExpr, *ast.Ident: 1495 default: 1496 return 1497 } 1498 1499 if _, ok := pass.TypesInfo.TypeOf(call.Args[arg]).(*types.Tuple); ok { 1500 // the called function returns multiple values and got 1501 // splatted into the call. for all we know, it is 1502 // returning good arguments. 1503 return 1504 } 1505 1506 alt := name[:len(name)-1] 1507 report.Report(pass, call, 1508 "printf-style function with dynamic format string and no further arguments should use print-style function instead", 1509 report.Fixes(edit.Fix(fmt.Sprintf("use %s instead of %s", alt, name), edit.ReplaceWithString(call.Fun, alt)))) 1510 } 1511 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 1512 return nil, nil 1513 } 1514 1515 func CheckEarlyDefer(pass *analysis.Pass) (interface{}, error) { 1516 fn := func(node ast.Node) { 1517 block := node.(*ast.BlockStmt) 1518 if len(block.List) < 2 { 1519 return 1520 } 1521 for i, stmt := range block.List { 1522 if i == len(block.List)-1 { 1523 break 1524 } 1525 assign, ok := stmt.(*ast.AssignStmt) 1526 if !ok { 1527 continue 1528 } 1529 if len(assign.Rhs) != 1 { 1530 continue 1531 } 1532 if len(assign.Lhs) < 2 { 1533 continue 1534 } 1535 if lhs, ok := assign.Lhs[len(assign.Lhs)-1].(*ast.Ident); ok && lhs.Name == "_" { 1536 continue 1537 } 1538 call, ok := assign.Rhs[0].(*ast.CallExpr) 1539 if !ok { 1540 continue 1541 } 1542 sig, ok := pass.TypesInfo.TypeOf(call.Fun).(*types.Signature) 1543 if !ok { 1544 continue 1545 } 1546 if sig.Results().Len() < 2 { 1547 continue 1548 } 1549 last := sig.Results().At(sig.Results().Len() - 1) 1550 // FIXME(dh): check that it's error from universe, not 1551 // another type of the same name 1552 if last.Type().String() != "error" { 1553 continue 1554 } 1555 lhs, ok := assign.Lhs[0].(*ast.Ident) 1556 if !ok { 1557 continue 1558 } 1559 def, ok := block.List[i+1].(*ast.DeferStmt) 1560 if !ok { 1561 continue 1562 } 1563 sel, ok := def.Call.Fun.(*ast.SelectorExpr) 1564 if !ok { 1565 continue 1566 } 1567 ident, ok := selectorX(sel).(*ast.Ident) 1568 if !ok { 1569 continue 1570 } 1571 if pass.TypesInfo.ObjectOf(ident) != pass.TypesInfo.ObjectOf(lhs) { 1572 continue 1573 } 1574 if sel.Sel.Name != "Close" { 1575 continue 1576 } 1577 report.Report(pass, def, fmt.Sprintf("should check returned error before deferring %s", report.Render(pass, def.Call))) 1578 } 1579 } 1580 code.Preorder(pass, fn, (*ast.BlockStmt)(nil)) 1581 return nil, nil 1582 } 1583 1584 func selectorX(sel *ast.SelectorExpr) ast.Node { 1585 switch x := sel.X.(type) { 1586 case *ast.SelectorExpr: 1587 return selectorX(x) 1588 default: 1589 return x 1590 } 1591 } 1592 1593 func CheckEmptyCriticalSection(pass *analysis.Pass) (interface{}, error) { 1594 if pass.Pkg.Path() == "sync_test" { 1595 // exception for the sync package's tests 1596 return nil, nil 1597 } 1598 1599 // Initially it might seem like this check would be easier to 1600 // implement using IR. After all, we're only checking for two 1601 // consecutive method calls. In reality, however, there may be any 1602 // number of other instructions between the lock and unlock, while 1603 // still constituting an empty critical section. For example, 1604 // given `m.x().Lock(); m.x().Unlock()`, there will be a call to 1605 // x(). In the AST-based approach, this has a tiny potential for a 1606 // false positive (the second call to x might be doing work that 1607 // is protected by the mutex). In an IR-based approach, however, 1608 // it would miss a lot of real bugs. 1609 1610 mutexParams := func(s ast.Stmt) (x ast.Expr, funcName string, ok bool) { 1611 expr, ok := s.(*ast.ExprStmt) 1612 if !ok { 1613 return nil, "", false 1614 } 1615 call, ok := astutil.Unparen(expr.X).(*ast.CallExpr) 1616 if !ok { 1617 return nil, "", false 1618 } 1619 sel, ok := call.Fun.(*ast.SelectorExpr) 1620 if !ok { 1621 return nil, "", false 1622 } 1623 1624 fn, ok := pass.TypesInfo.ObjectOf(sel.Sel).(*types.Func) 1625 if !ok { 1626 return nil, "", false 1627 } 1628 sig := fn.Type().(*types.Signature) 1629 if sig.Params().Len() != 0 || sig.Results().Len() != 0 { 1630 return nil, "", false 1631 } 1632 1633 return sel.X, fn.Name(), true 1634 } 1635 1636 fn := func(node ast.Node) { 1637 block := node.(*ast.BlockStmt) 1638 if len(block.List) < 2 { 1639 return 1640 } 1641 for i := range block.List[:len(block.List)-1] { 1642 sel1, method1, ok1 := mutexParams(block.List[i]) 1643 sel2, method2, ok2 := mutexParams(block.List[i+1]) 1644 1645 if !ok1 || !ok2 || report.Render(pass, sel1) != report.Render(pass, sel2) { 1646 continue 1647 } 1648 if (method1 == "Lock" && method2 == "Unlock") || 1649 (method1 == "RLock" && method2 == "RUnlock") { 1650 report.Report(pass, block.List[i+1], "empty critical section") 1651 } 1652 } 1653 } 1654 code.Preorder(pass, fn, (*ast.BlockStmt)(nil)) 1655 return nil, nil 1656 } 1657 1658 var ( 1659 // cgo produces code like fn(&*_Cvar_kSomeCallbacks) which we don't 1660 // want to flag. 1661 cgoIdent = regexp.MustCompile(`^_C(func|var)_.+$`) 1662 checkIneffectiveCopyQ1 = pattern.MustParse(`(UnaryExpr "&" (StarExpr obj))`) 1663 checkIneffectiveCopyQ2 = pattern.MustParse(`(StarExpr (UnaryExpr "&" _))`) 1664 ) 1665 1666 func CheckIneffectiveCopy(pass *analysis.Pass) (interface{}, error) { 1667 fn := func(node ast.Node) { 1668 if m, ok := code.Match(pass, checkIneffectiveCopyQ1, node); ok { 1669 if ident, ok := m.State["obj"].(*ast.Ident); !ok || !cgoIdent.MatchString(ident.Name) { 1670 report.Report(pass, node, "&*x will be simplified to x. It will not copy x.") 1671 } 1672 } else if _, ok := code.Match(pass, checkIneffectiveCopyQ2, node); ok { 1673 report.Report(pass, node, "*&x will be simplified to x. It will not copy x.") 1674 } 1675 } 1676 code.Preorder(pass, fn, (*ast.UnaryExpr)(nil), (*ast.StarExpr)(nil)) 1677 return nil, nil 1678 } 1679 1680 func CheckCanonicalHeaderKey(pass *analysis.Pass) (interface{}, error) { 1681 fn := func(node ast.Node, push bool) bool { 1682 if !push { 1683 return false 1684 } 1685 if assign, ok := node.(*ast.AssignStmt); ok { 1686 // TODO(dh): This risks missing some Header reads, for 1687 // example in `h1["foo"] = h2["foo"]` – these edge 1688 // cases are probably rare enough to ignore for now. 1689 for _, expr := range assign.Lhs { 1690 op, ok := expr.(*ast.IndexExpr) 1691 if !ok { 1692 continue 1693 } 1694 if code.IsOfType(pass, op.X, "net/http.Header") { 1695 return false 1696 } 1697 } 1698 return true 1699 } 1700 op, ok := node.(*ast.IndexExpr) 1701 if !ok { 1702 return true 1703 } 1704 if !code.IsOfType(pass, op.X, "net/http.Header") { 1705 return true 1706 } 1707 s, ok := code.ExprToString(pass, op.Index) 1708 if !ok { 1709 return true 1710 } 1711 canonical := http.CanonicalHeaderKey(s) 1712 if s == canonical { 1713 return true 1714 } 1715 var fix analysis.SuggestedFix 1716 switch op.Index.(type) { 1717 case *ast.BasicLit: 1718 fix = edit.Fix("canonicalize header key", edit.ReplaceWithString(op.Index, strconv.Quote(canonical))) 1719 case *ast.Ident: 1720 call := &ast.CallExpr{ 1721 Fun: edit.Selector("http", "CanonicalHeaderKey"), 1722 Args: []ast.Expr{op.Index}, 1723 } 1724 fix = edit.Fix("wrap in http.CanonicalHeaderKey", edit.ReplaceWithNode(pass.Fset, op.Index, call)) 1725 } 1726 msg := fmt.Sprintf("keys in http.Header are canonicalized, %q is not canonical; fix the constant or use http.CanonicalHeaderKey", s) 1727 if fix.Message != "" { 1728 report.Report(pass, op, msg, report.Fixes(fix)) 1729 } else { 1730 report.Report(pass, op, msg) 1731 } 1732 return true 1733 } 1734 pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes([]ast.Node{(*ast.AssignStmt)(nil), (*ast.IndexExpr)(nil)}, fn) 1735 return nil, nil 1736 } 1737 1738 func CheckBenchmarkN(pass *analysis.Pass) (interface{}, error) { 1739 fn := func(node ast.Node) { 1740 assign := node.(*ast.AssignStmt) 1741 if len(assign.Lhs) != 1 || len(assign.Rhs) != 1 { 1742 return 1743 } 1744 sel, ok := assign.Lhs[0].(*ast.SelectorExpr) 1745 if !ok { 1746 return 1747 } 1748 if sel.Sel.Name != "N" { 1749 return 1750 } 1751 if !code.IsOfType(pass, sel.X, "*testing.B") { 1752 return 1753 } 1754 report.Report(pass, assign, fmt.Sprintf("should not assign to %s", report.Render(pass, sel))) 1755 } 1756 code.Preorder(pass, fn, (*ast.AssignStmt)(nil)) 1757 return nil, nil 1758 } 1759 1760 func CheckUnreadVariableValues(pass *analysis.Pass) (interface{}, error) { 1761 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1762 if irutil.IsExample(fn) { 1763 continue 1764 } 1765 node := fn.Source() 1766 if node == nil { 1767 continue 1768 } 1769 if gen, ok := code.Generator(pass, node.Pos()); ok && gen == generated.Goyacc { 1770 // Don't flag unused values in code generated by goyacc. 1771 // There may be hundreds of those due to the way the state 1772 // machine is constructed. 1773 continue 1774 } 1775 1776 switchTags := map[ir.Value]struct{}{} 1777 ast.Inspect(node, func(node ast.Node) bool { 1778 s, ok := node.(*ast.SwitchStmt) 1779 if !ok { 1780 return true 1781 } 1782 v, _ := fn.ValueForExpr(s.Tag) 1783 switchTags[v] = struct{}{} 1784 return true 1785 }) 1786 1787 // OPT(dh): don't use a map, possibly use a bitset 1788 var hasUse func(v ir.Value, seen map[ir.Value]struct{}) bool 1789 hasUse = func(v ir.Value, seen map[ir.Value]struct{}) bool { 1790 if _, ok := seen[v]; ok { 1791 return false 1792 } 1793 if _, ok := switchTags[v]; ok { 1794 return true 1795 } 1796 refs := v.Referrers() 1797 if refs == nil { 1798 // TODO investigate why refs can be nil 1799 return true 1800 } 1801 for _, ref := range *refs { 1802 switch ref := ref.(type) { 1803 case *ir.DebugRef: 1804 case *ir.Sigma: 1805 if seen == nil { 1806 seen = map[ir.Value]struct{}{} 1807 } 1808 seen[v] = struct{}{} 1809 if hasUse(ref, seen) { 1810 return true 1811 } 1812 case *ir.Phi: 1813 if seen == nil { 1814 seen = map[ir.Value]struct{}{} 1815 } 1816 seen[v] = struct{}{} 1817 if hasUse(ref, seen) { 1818 return true 1819 } 1820 default: 1821 return true 1822 } 1823 } 1824 return false 1825 } 1826 1827 ast.Inspect(node, func(node ast.Node) bool { 1828 assign, ok := node.(*ast.AssignStmt) 1829 if !ok { 1830 return true 1831 } 1832 if len(assign.Lhs) > 1 && len(assign.Rhs) == 1 { 1833 // Either a function call with multiple return values, 1834 // or a comma-ok assignment 1835 1836 val, _ := fn.ValueForExpr(assign.Rhs[0]) 1837 if val == nil { 1838 return true 1839 } 1840 refs := val.Referrers() 1841 if refs == nil { 1842 return true 1843 } 1844 for _, ref := range *refs { 1845 ex, ok := ref.(*ir.Extract) 1846 if !ok { 1847 continue 1848 } 1849 if !hasUse(ex, nil) { 1850 lhs := assign.Lhs[ex.Index] 1851 if ident, ok := lhs.(*ast.Ident); !ok || ok && ident.Name == "_" { 1852 continue 1853 } 1854 report.Report(pass, assign, fmt.Sprintf("this value of %s is never used", lhs)) 1855 } 1856 } 1857 return true 1858 } 1859 for i, lhs := range assign.Lhs { 1860 rhs := assign.Rhs[i] 1861 if ident, ok := lhs.(*ast.Ident); !ok || ok && ident.Name == "_" { 1862 continue 1863 } 1864 val, _ := fn.ValueForExpr(rhs) 1865 if val == nil { 1866 continue 1867 } 1868 1869 if _, ok := val.(*ir.Const); ok { 1870 // a zero-valued constant, for example in 'foo := []string(nil)' 1871 continue 1872 } 1873 if !hasUse(val, nil) { 1874 report.Report(pass, assign, fmt.Sprintf("this value of %s is never used", lhs)) 1875 } 1876 } 1877 return true 1878 }) 1879 } 1880 return nil, nil 1881 } 1882 1883 func CheckPredeterminedBooleanExprs(pass *analysis.Pass) (interface{}, error) { 1884 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1885 for _, block := range fn.Blocks { 1886 for _, ins := range block.Instrs { 1887 binop, ok := ins.(*ir.BinOp) 1888 if !ok { 1889 continue 1890 } 1891 switch binop.Op { 1892 case token.GTR, token.LSS, token.EQL, token.NEQ, token.LEQ, token.GEQ: 1893 default: 1894 continue 1895 } 1896 1897 xs, ok1 := consts(binop.X, nil, nil) 1898 ys, ok2 := consts(binop.Y, nil, nil) 1899 if !ok1 || !ok2 || len(xs) == 0 || len(ys) == 0 { 1900 continue 1901 } 1902 1903 trues := 0 1904 for _, x := range xs { 1905 for _, y := range ys { 1906 if x.Value == nil { 1907 if y.Value == nil { 1908 trues++ 1909 } 1910 continue 1911 } 1912 if constant.Compare(x.Value, binop.Op, y.Value) { 1913 trues++ 1914 } 1915 } 1916 } 1917 b := trues != 0 1918 if trues == 0 || trues == len(xs)*len(ys) { 1919 report.Report(pass, binop, fmt.Sprintf("binary expression is always %t for all possible values (%s %s %s)", b, xs, binop.Op, ys)) 1920 } 1921 } 1922 } 1923 } 1924 return nil, nil 1925 } 1926 1927 func CheckNilMaps(pass *analysis.Pass) (interface{}, error) { 1928 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 1929 for _, block := range fn.Blocks { 1930 for _, ins := range block.Instrs { 1931 mu, ok := ins.(*ir.MapUpdate) 1932 if !ok { 1933 continue 1934 } 1935 c, ok := irutil.Flatten(mu.Map).(*ir.Const) 1936 if !ok { 1937 continue 1938 } 1939 if c.Value != nil { 1940 continue 1941 } 1942 report.Report(pass, mu, "assignment to nil map") 1943 } 1944 } 1945 } 1946 return nil, nil 1947 } 1948 1949 func CheckExtremeComparison(pass *analysis.Pass) (interface{}, error) { 1950 isobj := func(expr ast.Expr, name string) bool { 1951 sel, ok := expr.(*ast.SelectorExpr) 1952 if !ok { 1953 return false 1954 } 1955 return typeutil.IsObject(pass.TypesInfo.ObjectOf(sel.Sel), name) 1956 } 1957 1958 fn := func(node ast.Node) { 1959 expr := node.(*ast.BinaryExpr) 1960 tx := pass.TypesInfo.TypeOf(expr.X) 1961 basic, ok := tx.Underlying().(*types.Basic) 1962 if !ok { 1963 return 1964 } 1965 1966 var max string 1967 var min string 1968 1969 switch basic.Kind() { 1970 case types.Uint8: 1971 max = "math.MaxUint8" 1972 case types.Uint16: 1973 max = "math.MaxUint16" 1974 case types.Uint32: 1975 max = "math.MaxUint32" 1976 case types.Uint64: 1977 max = "math.MaxUint64" 1978 case types.Uint: 1979 max = "math.MaxUint64" 1980 1981 case types.Int8: 1982 min = "math.MinInt8" 1983 max = "math.MaxInt8" 1984 case types.Int16: 1985 min = "math.MinInt16" 1986 max = "math.MaxInt16" 1987 case types.Int32: 1988 min = "math.MinInt32" 1989 max = "math.MaxInt32" 1990 case types.Int64: 1991 min = "math.MinInt64" 1992 max = "math.MaxInt64" 1993 case types.Int: 1994 min = "math.MinInt64" 1995 max = "math.MaxInt64" 1996 } 1997 1998 if (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.Y, max) || 1999 (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.X, max) { 2000 report.Report(pass, expr, fmt.Sprintf("no value of type %s is greater than %s", basic, max)) 2001 } 2002 if expr.Op == token.LEQ && isobj(expr.Y, max) || 2003 expr.Op == token.GEQ && isobj(expr.X, max) { 2004 report.Report(pass, expr, fmt.Sprintf("every value of type %s is <= %s", basic, max)) 2005 } 2006 2007 isZeroLiteral := func(expr ast.Expr) bool { 2008 return code.IsIntegerLiteral(pass, expr, constant.MakeInt64(0)) 2009 } 2010 if (basic.Info() & types.IsUnsigned) != 0 { 2011 if (expr.Op == token.LSS && isZeroLiteral(expr.Y)) || 2012 (expr.Op == token.GTR && isZeroLiteral(expr.X)) { 2013 report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than 0", basic)) 2014 } 2015 if expr.Op == token.GEQ && isZeroLiteral(expr.Y) || 2016 expr.Op == token.LEQ && isZeroLiteral(expr.X) { 2017 report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= 0", basic)) 2018 } 2019 } else { 2020 if (expr.Op == token.LSS || expr.Op == token.LEQ) && isobj(expr.Y, min) || 2021 (expr.Op == token.GTR || expr.Op == token.GEQ) && isobj(expr.X, min) { 2022 report.Report(pass, expr, fmt.Sprintf("no value of type %s is less than %s", basic, min)) 2023 } 2024 if expr.Op == token.GEQ && isobj(expr.Y, min) || 2025 expr.Op == token.LEQ && isobj(expr.X, min) { 2026 report.Report(pass, expr, fmt.Sprintf("every value of type %s is >= %s", basic, min)) 2027 } 2028 } 2029 2030 } 2031 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 2032 return nil, nil 2033 } 2034 2035 func consts(val ir.Value, out []*ir.Const, visitedPhis map[string]bool) ([]*ir.Const, bool) { 2036 if visitedPhis == nil { 2037 visitedPhis = map[string]bool{} 2038 } 2039 var ok bool 2040 switch val := val.(type) { 2041 case *ir.Phi: 2042 if visitedPhis[val.Name()] { 2043 break 2044 } 2045 visitedPhis[val.Name()] = true 2046 vals := val.Operands(nil) 2047 for _, phival := range vals { 2048 out, ok = consts(*phival, out, visitedPhis) 2049 if !ok { 2050 return nil, false 2051 } 2052 } 2053 case *ir.Const: 2054 out = append(out, val) 2055 case *ir.Convert: 2056 out, ok = consts(val.X, out, visitedPhis) 2057 if !ok { 2058 return nil, false 2059 } 2060 default: 2061 return nil, false 2062 } 2063 if len(out) < 2 { 2064 return out, true 2065 } 2066 uniq := []*ir.Const{out[0]} 2067 for _, val := range out[1:] { 2068 if val.Value == uniq[len(uniq)-1].Value { 2069 continue 2070 } 2071 uniq = append(uniq, val) 2072 } 2073 return uniq, true 2074 } 2075 2076 func CheckLoopCondition(pass *analysis.Pass) (interface{}, error) { 2077 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2078 cb := func(node ast.Node) bool { 2079 loop, ok := node.(*ast.ForStmt) 2080 if !ok { 2081 return true 2082 } 2083 if loop.Init == nil || loop.Cond == nil || loop.Post == nil { 2084 return true 2085 } 2086 init, ok := loop.Init.(*ast.AssignStmt) 2087 if !ok || len(init.Lhs) != 1 || len(init.Rhs) != 1 { 2088 return true 2089 } 2090 cond, ok := loop.Cond.(*ast.BinaryExpr) 2091 if !ok { 2092 return true 2093 } 2094 x, ok := cond.X.(*ast.Ident) 2095 if !ok { 2096 return true 2097 } 2098 lhs, ok := init.Lhs[0].(*ast.Ident) 2099 if !ok { 2100 return true 2101 } 2102 if pass.TypesInfo.ObjectOf(x) != pass.TypesInfo.ObjectOf(lhs) { 2103 return true 2104 } 2105 if _, ok := loop.Post.(*ast.IncDecStmt); !ok { 2106 return true 2107 } 2108 2109 v, isAddr := fn.ValueForExpr(cond.X) 2110 if v == nil || isAddr { 2111 return true 2112 } 2113 switch v := v.(type) { 2114 case *ir.Phi: 2115 ops := v.Operands(nil) 2116 if len(ops) != 2 { 2117 return true 2118 } 2119 _, ok := (*ops[0]).(*ir.Const) 2120 if !ok { 2121 return true 2122 } 2123 sigma, ok := (*ops[1]).(*ir.Sigma) 2124 if !ok { 2125 return true 2126 } 2127 if sigma.X != v { 2128 return true 2129 } 2130 case *ir.Load: 2131 return true 2132 } 2133 report.Report(pass, cond, "variable in loop condition never changes") 2134 2135 return true 2136 } 2137 if source := fn.Source(); source != nil { 2138 ast.Inspect(source, cb) 2139 } 2140 } 2141 return nil, nil 2142 } 2143 2144 func CheckArgOverwritten(pass *analysis.Pass) (interface{}, error) { 2145 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2146 cb := func(node ast.Node) bool { 2147 var typ *ast.FuncType 2148 var body *ast.BlockStmt 2149 switch fn := node.(type) { 2150 case *ast.FuncDecl: 2151 typ = fn.Type 2152 body = fn.Body 2153 case *ast.FuncLit: 2154 typ = fn.Type 2155 body = fn.Body 2156 } 2157 if body == nil { 2158 return true 2159 } 2160 if len(typ.Params.List) == 0 { 2161 return true 2162 } 2163 for _, field := range typ.Params.List { 2164 for _, arg := range field.Names { 2165 obj := pass.TypesInfo.ObjectOf(arg) 2166 var irobj *ir.Parameter 2167 for _, param := range fn.Params { 2168 if param.Object() == obj { 2169 irobj = param 2170 break 2171 } 2172 } 2173 if irobj == nil { 2174 continue 2175 } 2176 refs := irobj.Referrers() 2177 if refs == nil { 2178 continue 2179 } 2180 if len(irutil.FilterDebug(*refs)) != 0 { 2181 continue 2182 } 2183 2184 var assignment ast.Node 2185 ast.Inspect(body, func(node ast.Node) bool { 2186 if assignment != nil { 2187 return false 2188 } 2189 assign, ok := node.(*ast.AssignStmt) 2190 if !ok { 2191 return true 2192 } 2193 for _, lhs := range assign.Lhs { 2194 ident, ok := lhs.(*ast.Ident) 2195 if !ok { 2196 continue 2197 } 2198 if pass.TypesInfo.ObjectOf(ident) == obj { 2199 assignment = assign 2200 return false 2201 } 2202 } 2203 return true 2204 }) 2205 if assignment != nil { 2206 report.Report(pass, arg, fmt.Sprintf("argument %s is overwritten before first use", arg), 2207 report.Related(assignment, fmt.Sprintf("assignment to %s", arg))) 2208 } 2209 } 2210 } 2211 return true 2212 } 2213 if source := fn.Source(); source != nil { 2214 ast.Inspect(source, cb) 2215 } 2216 } 2217 return nil, nil 2218 } 2219 2220 func CheckIneffectiveLoop(pass *analysis.Pass) (interface{}, error) { 2221 // This check detects some, but not all unconditional loop exits. 2222 // We give up in the following cases: 2223 // 2224 // - a goto anywhere in the loop. The goto might skip over our 2225 // return, and we don't check that it doesn't. 2226 // 2227 // - any nested, unlabelled continue, even if it is in another 2228 // loop or closure. 2229 fn := func(node ast.Node) { 2230 var body *ast.BlockStmt 2231 switch fn := node.(type) { 2232 case *ast.FuncDecl: 2233 body = fn.Body 2234 case *ast.FuncLit: 2235 body = fn.Body 2236 default: 2237 lint.ExhaustiveTypeSwitch(node) 2238 } 2239 if body == nil { 2240 return 2241 } 2242 labels := map[types.Object]ast.Stmt{} 2243 ast.Inspect(body, func(node ast.Node) bool { 2244 label, ok := node.(*ast.LabeledStmt) 2245 if !ok { 2246 return true 2247 } 2248 labels[pass.TypesInfo.ObjectOf(label.Label)] = label.Stmt 2249 return true 2250 }) 2251 2252 ast.Inspect(body, func(node ast.Node) bool { 2253 var loop ast.Node 2254 var body *ast.BlockStmt 2255 switch node := node.(type) { 2256 case *ast.ForStmt: 2257 body = node.Body 2258 loop = node 2259 case *ast.RangeStmt: 2260 ok := typeutil.All(pass.TypesInfo.TypeOf(node.X), func(term *types.Term) bool { 2261 switch term.Type().Underlying().(type) { 2262 case *types.Slice, *types.Chan, *types.Basic, *types.Pointer, *types.Array: 2263 return true 2264 case *types.Map: 2265 // looping once over a map is a valid pattern for 2266 // getting an arbitrary element. 2267 return false 2268 default: 2269 lint.ExhaustiveTypeSwitch(term.Type().Underlying()) 2270 return false 2271 } 2272 }) 2273 if !ok { 2274 return true 2275 } 2276 body = node.Body 2277 loop = node 2278 default: 2279 return true 2280 } 2281 if len(body.List) < 2 { 2282 // TODO(dh): is this check needed? when body.List < 2, 2283 // then we can't find both an unconditional exit and a 2284 // branching statement (if, ...). and we don't flag 2285 // unconditional exits if there has been no branching 2286 // in the loop body. 2287 2288 // avoid flagging the somewhat common pattern of using 2289 // a range loop to get the first element in a slice, 2290 // or the first rune in a string. 2291 return true 2292 } 2293 var unconditionalExit ast.Node 2294 hasBranching := false 2295 for _, stmt := range body.List { 2296 switch stmt := stmt.(type) { 2297 case *ast.BranchStmt: 2298 switch stmt.Tok { 2299 case token.BREAK: 2300 if stmt.Label == nil || labels[pass.TypesInfo.ObjectOf(stmt.Label)] == loop { 2301 unconditionalExit = stmt 2302 } 2303 case token.CONTINUE: 2304 if stmt.Label == nil || labels[pass.TypesInfo.ObjectOf(stmt.Label)] == loop { 2305 unconditionalExit = nil 2306 return false 2307 } 2308 } 2309 case *ast.ReturnStmt: 2310 unconditionalExit = stmt 2311 case *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.SelectStmt: 2312 hasBranching = true 2313 } 2314 } 2315 if unconditionalExit == nil || !hasBranching { 2316 return false 2317 } 2318 ast.Inspect(body, func(node ast.Node) bool { 2319 if branch, ok := node.(*ast.BranchStmt); ok { 2320 2321 switch branch.Tok { 2322 case token.GOTO: 2323 unconditionalExit = nil 2324 return false 2325 case token.CONTINUE: 2326 if branch.Label != nil && labels[pass.TypesInfo.ObjectOf(branch.Label)] != loop { 2327 return true 2328 } 2329 unconditionalExit = nil 2330 return false 2331 } 2332 } 2333 return true 2334 }) 2335 if unconditionalExit != nil { 2336 report.Report(pass, unconditionalExit, "the surrounding loop is unconditionally terminated") 2337 } 2338 return true 2339 }) 2340 } 2341 code.Preorder(pass, fn, (*ast.FuncDecl)(nil), (*ast.FuncLit)(nil)) 2342 return nil, nil 2343 } 2344 2345 var checkNilContextQ = pattern.MustParse(`(CallExpr fun@(Symbol _) (Builtin "nil"):_)`) 2346 2347 func CheckNilContext(pass *analysis.Pass) (interface{}, error) { 2348 todo := &ast.CallExpr{ 2349 Fun: edit.Selector("context", "TODO"), 2350 } 2351 bg := &ast.CallExpr{ 2352 Fun: edit.Selector("context", "Background"), 2353 } 2354 fn := func(node ast.Node) { 2355 m, ok := code.Match(pass, checkNilContextQ, node) 2356 if !ok { 2357 return 2358 } 2359 2360 call := node.(*ast.CallExpr) 2361 fun, ok := m.State["fun"].(*types.Func) 2362 if !ok { 2363 // it might also be a builtin 2364 return 2365 } 2366 sig := fun.Type().(*types.Signature) 2367 if sig.Params().Len() == 0 { 2368 // Our CallExpr might've matched a method expression, like 2369 // (*T).Foo(nil) – here, nil isn't the first argument of 2370 // the Foo method, but the method receiver. 2371 return 2372 } 2373 if !typeutil.IsType(sig.Params().At(0).Type(), "context.Context") { 2374 return 2375 } 2376 report.Report(pass, call.Args[0], 2377 "do not pass a nil Context, even if a function permits it; pass context.TODO if you are unsure about which Context to use", report.Fixes( 2378 edit.Fix("use context.TODO", edit.ReplaceWithNode(pass.Fset, call.Args[0], todo)), 2379 edit.Fix("use context.Background", edit.ReplaceWithNode(pass.Fset, call.Args[0], bg)))) 2380 } 2381 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 2382 return nil, nil 2383 } 2384 2385 var ( 2386 checkSeekerQ = pattern.MustParse(`(CallExpr fun@(SelectorExpr _ (Ident "Seek")) [arg1@(SelectorExpr _ (Symbol (Or "io.SeekStart" "io.SeekCurrent" "io.SeekEnd"))) arg2])`) 2387 checkSeekerR = pattern.MustParse(`(CallExpr fun [arg2 arg1])`) 2388 ) 2389 2390 func CheckSeeker(pass *analysis.Pass) (interface{}, error) { 2391 fn := func(node ast.Node) { 2392 if m, edits, ok := code.MatchAndEdit(pass, checkSeekerQ, checkSeekerR, node); ok { 2393 if !code.IsMethod(pass, m.State["fun"].(*ast.SelectorExpr), "Seek", knowledge.Signatures["(io.Seeker).Seek"]) { 2394 return 2395 } 2396 report.Report(pass, node, "the first argument of io.Seeker is the offset, but an io.Seek* constant is being used instead", 2397 report.Fixes(edit.Fix("swap arguments", edits...))) 2398 } 2399 } 2400 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 2401 return nil, nil 2402 } 2403 2404 func CheckIneffectiveAppend(pass *analysis.Pass) (interface{}, error) { 2405 isAppend := func(ins ir.Value) bool { 2406 call, ok := ins.(*ir.Call) 2407 if !ok { 2408 return false 2409 } 2410 if call.Call.IsInvoke() { 2411 return false 2412 } 2413 if builtin, ok := call.Call.Value.(*ir.Builtin); !ok || builtin.Name() != "append" { 2414 return false 2415 } 2416 return true 2417 } 2418 2419 // We have to be careful about aliasing. 2420 // Multiple slices may refer to the same backing array, 2421 // making appends observable even when we don't see the result of append be used anywhere. 2422 // 2423 // We will have to restrict ourselves to slices that have been allocated within the function, 2424 // haven't been sliced, 2425 // and haven't been passed anywhere that could retain them (such as function calls or memory stores). 2426 // 2427 // We check whether an append should be flagged in two steps. 2428 // 2429 // In the first step, we look at the data flow graph, starting in reverse from the argument to append, till we reach the root. 2430 // This graph must only consist of the following instructions: 2431 // 2432 // - phi 2433 // - sigma 2434 // - slice 2435 // - const nil 2436 // - MakeSlice 2437 // - Alloc 2438 // - calls to append 2439 // 2440 // If this step succeeds, we look at all referrers of the values found in the first step, recursively. 2441 // These referrers must either be in the set of values found in the first step, 2442 // be DebugRefs, 2443 // or fulfill the same type requirements as step 1, with the exception of appends, which are forbidden. 2444 // 2445 // If both steps succeed then we know that the backing array hasn't been aliased in an observable manner. 2446 // 2447 // We could relax these restrictions by making use of additional information: 2448 // - if we passed the slice to a function that doesn't retain the slice then we can still flag it 2449 // - if a slice has been sliced but is dead afterwards, we can flag appends to the new slice 2450 2451 // OPT(dh): We could cache the results of both validate functions. 2452 // However, we only use these functions on values that we otherwise want to flag, which are very few. 2453 // Not caching values hasn't increased the runtimes for the standard library nor k8s. 2454 var validateArgument func(v ir.Value, seen map[ir.Value]struct{}) bool 2455 validateArgument = func(v ir.Value, seen map[ir.Value]struct{}) bool { 2456 if _, ok := seen[v]; ok { 2457 // break cycle 2458 return true 2459 } 2460 seen[v] = struct{}{} 2461 switch v := v.(type) { 2462 case *ir.Phi: 2463 for _, edge := range v.Edges { 2464 if !validateArgument(edge, seen) { 2465 return false 2466 } 2467 } 2468 return true 2469 case *ir.Sigma: 2470 return validateArgument(v.X, seen) 2471 case *ir.Slice: 2472 return validateArgument(v.X, seen) 2473 case *ir.Const: 2474 return true 2475 case *ir.MakeSlice: 2476 return true 2477 case *ir.Alloc: 2478 return true 2479 case *ir.Call: 2480 if isAppend(v) { 2481 return validateArgument(v.Call.Args[0], seen) 2482 } 2483 return false 2484 default: 2485 return false 2486 } 2487 } 2488 2489 var validateReferrers func(v ir.Value, seen map[ir.Instruction]struct{}) bool 2490 validateReferrers = func(v ir.Value, seen map[ir.Instruction]struct{}) bool { 2491 for _, ref := range *v.Referrers() { 2492 if _, ok := seen[ref]; ok { 2493 continue 2494 } 2495 2496 seen[ref] = struct{}{} 2497 switch ref.(type) { 2498 case *ir.Phi: 2499 case *ir.Sigma: 2500 case *ir.Slice: 2501 case *ir.Const: 2502 case *ir.MakeSlice: 2503 case *ir.Alloc: 2504 case *ir.DebugRef: 2505 default: 2506 return false 2507 } 2508 2509 if ref, ok := ref.(ir.Value); ok { 2510 if !validateReferrers(ref, seen) { 2511 return false 2512 } 2513 } 2514 } 2515 return true 2516 } 2517 2518 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2519 for _, block := range fn.Blocks { 2520 for _, ins := range block.Instrs { 2521 val, ok := ins.(ir.Value) 2522 if !ok || !isAppend(val) { 2523 continue 2524 } 2525 2526 isUsed := false 2527 visited := map[ir.Instruction]bool{} 2528 var walkRefs func(refs []ir.Instruction) 2529 walkRefs = func(refs []ir.Instruction) { 2530 loop: 2531 for _, ref := range refs { 2532 if visited[ref] { 2533 continue 2534 } 2535 visited[ref] = true 2536 if _, ok := ref.(*ir.DebugRef); ok { 2537 continue 2538 } 2539 switch ref := ref.(type) { 2540 case *ir.Phi: 2541 walkRefs(*ref.Referrers()) 2542 case *ir.Sigma: 2543 walkRefs(*ref.Referrers()) 2544 case ir.Value: 2545 if !isAppend(ref) { 2546 isUsed = true 2547 } else { 2548 walkRefs(*ref.Referrers()) 2549 } 2550 case ir.Instruction: 2551 isUsed = true 2552 break loop 2553 } 2554 } 2555 } 2556 2557 refs := val.Referrers() 2558 if refs == nil { 2559 continue 2560 } 2561 walkRefs(*refs) 2562 2563 if isUsed { 2564 continue 2565 } 2566 2567 seen := map[ir.Value]struct{}{} 2568 if !validateArgument(ins.(*ir.Call).Call.Args[0], seen) { 2569 continue 2570 } 2571 2572 seen2 := map[ir.Instruction]struct{}{} 2573 for k := range seen { 2574 // the only values we allow are also instructions, so this type assertion cannot fail 2575 seen2[k.(ir.Instruction)] = struct{}{} 2576 } 2577 seen2[ins] = struct{}{} 2578 failed := false 2579 for v := range seen { 2580 if !validateReferrers(v, seen2) { 2581 failed = true 2582 break 2583 } 2584 } 2585 if !failed { 2586 report.Report(pass, ins, "this result of append is never used, except maybe in other appends") 2587 } 2588 } 2589 } 2590 } 2591 return nil, nil 2592 } 2593 2594 func CheckConcurrentTesting(pass *analysis.Pass) (interface{}, error) { 2595 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2596 for _, block := range fn.Blocks { 2597 for _, ins := range block.Instrs { 2598 gostmt, ok := ins.(*ir.Go) 2599 if !ok { 2600 continue 2601 } 2602 var fn *ir.Function 2603 switch val := gostmt.Call.Value.(type) { 2604 case *ir.Function: 2605 fn = val 2606 case *ir.MakeClosure: 2607 fn = val.Fn.(*ir.Function) 2608 default: 2609 continue 2610 } 2611 if fn.Blocks == nil { 2612 continue 2613 } 2614 for _, block := range fn.Blocks { 2615 for _, ins := range block.Instrs { 2616 call, ok := ins.(*ir.Call) 2617 if !ok { 2618 continue 2619 } 2620 if call.Call.IsInvoke() { 2621 continue 2622 } 2623 callee := call.Call.StaticCallee() 2624 if callee == nil { 2625 continue 2626 } 2627 recv := callee.Signature.Recv() 2628 if recv == nil { 2629 continue 2630 } 2631 if !typeutil.IsType(recv.Type(), "*testing.common") { 2632 continue 2633 } 2634 fn, ok := call.Call.StaticCallee().Object().(*types.Func) 2635 if !ok { 2636 continue 2637 } 2638 name := fn.Name() 2639 switch name { 2640 case "FailNow", "Fatal", "Fatalf", "SkipNow", "Skip", "Skipf": 2641 default: 2642 continue 2643 } 2644 // TODO(dh): don't report multiple diagnostics 2645 // for multiple calls to T.Fatal, but do 2646 // collect all of them as related information 2647 report.Report(pass, gostmt, fmt.Sprintf("the goroutine calls T.%s, which must be called in the same goroutine as the test", name), 2648 report.Related(call, fmt.Sprintf("call to T.%s", name))) 2649 } 2650 } 2651 } 2652 } 2653 } 2654 return nil, nil 2655 } 2656 2657 func eachCall(fn *ir.Function, cb func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function)) { 2658 for _, b := range fn.Blocks { 2659 for _, instr := range b.Instrs { 2660 if site, ok := instr.(ir.CallInstruction); ok { 2661 if g := site.Common().StaticCallee(); g != nil { 2662 cb(fn, site, g) 2663 } 2664 } 2665 } 2666 } 2667 } 2668 2669 func CheckCyclicFinalizer(pass *analysis.Pass) (interface{}, error) { 2670 cb := func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) { 2671 if callee.RelString(nil) != "runtime.SetFinalizer" { 2672 return 2673 } 2674 arg0 := site.Common().Args[knowledge.Arg("runtime.SetFinalizer.obj")] 2675 if iface, ok := arg0.(*ir.MakeInterface); ok { 2676 arg0 = iface.X 2677 } 2678 load, ok := arg0.(*ir.Load) 2679 if !ok { 2680 return 2681 } 2682 v, ok := load.X.(*ir.Alloc) 2683 if !ok { 2684 return 2685 } 2686 arg1 := site.Common().Args[knowledge.Arg("runtime.SetFinalizer.finalizer")] 2687 if iface, ok := arg1.(*ir.MakeInterface); ok { 2688 arg1 = iface.X 2689 } 2690 mc, ok := arg1.(*ir.MakeClosure) 2691 if !ok { 2692 return 2693 } 2694 for _, b := range mc.Bindings { 2695 if b == v { 2696 pos := report.DisplayPosition(pass.Fset, mc.Fn.Pos()) 2697 report.Report(pass, site, fmt.Sprintf("the finalizer closes over the object, preventing the finalizer from ever running (at %s)", pos)) 2698 } 2699 } 2700 } 2701 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2702 eachCall(fn, cb) 2703 } 2704 return nil, nil 2705 } 2706 2707 /* 2708 func CheckSliceOutOfBounds(pass *analysis.Pass) (interface{}, error) { 2709 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2710 for _, block := range fn.Blocks { 2711 for _, ins := range block.Instrs { 2712 ia, ok := ins.(*ir.IndexAddr) 2713 if !ok { 2714 continue 2715 } 2716 if _, ok := ia.X.Type().Underlying().(*types.Slice); !ok { 2717 continue 2718 } 2719 sr, ok1 := c.funcDescs.Get(fn).Ranges[ia.X].(vrp.SliceInterval) 2720 idxr, ok2 := c.funcDescs.Get(fn).Ranges[ia.Index].(vrp.IntInterval) 2721 if !ok1 || !ok2 || !sr.IsKnown() || !idxr.IsKnown() || sr.Length.Empty() || idxr.Empty() { 2722 continue 2723 } 2724 if idxr.Lower.Cmp(sr.Length.Upper) >= 0 { 2725 report.Nodef(pass, ia, "index out of bounds") 2726 } 2727 } 2728 } 2729 } 2730 return nil, nil 2731 } 2732 */ 2733 2734 func CheckDeferLock(pass *analysis.Pass) (interface{}, error) { 2735 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2736 for _, block := range fn.Blocks { 2737 instrs := irutil.FilterDebug(block.Instrs) 2738 if len(instrs) < 2 { 2739 continue 2740 } 2741 for i, ins := range instrs[:len(instrs)-1] { 2742 call, ok := ins.(*ir.Call) 2743 if !ok { 2744 continue 2745 } 2746 if !irutil.IsCallToAny(call.Common(), "(*sync.Mutex).Lock", "(*sync.RWMutex).RLock") { 2747 continue 2748 } 2749 nins, ok := instrs[i+1].(*ir.Defer) 2750 if !ok { 2751 continue 2752 } 2753 if !irutil.IsCallToAny(&nins.Call, "(*sync.Mutex).Lock", "(*sync.RWMutex).RLock") { 2754 continue 2755 } 2756 if call.Common().Args[0] != nins.Call.Args[0] { 2757 continue 2758 } 2759 name := shortCallName(call.Common()) 2760 alt := "" 2761 switch name { 2762 case "Lock": 2763 alt = "Unlock" 2764 case "RLock": 2765 alt = "RUnlock" 2766 } 2767 report.Report(pass, nins, fmt.Sprintf("deferring %s right after having locked already; did you mean to defer %s?", name, alt)) 2768 } 2769 } 2770 } 2771 return nil, nil 2772 } 2773 2774 func CheckNaNComparison(pass *analysis.Pass) (interface{}, error) { 2775 isNaN := func(v ir.Value) bool { 2776 call, ok := v.(*ir.Call) 2777 if !ok { 2778 return false 2779 } 2780 return irutil.IsCallTo(call.Common(), "math.NaN") 2781 } 2782 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2783 for _, block := range fn.Blocks { 2784 for _, ins := range block.Instrs { 2785 ins, ok := ins.(*ir.BinOp) 2786 if !ok { 2787 continue 2788 } 2789 if isNaN(irutil.Flatten(ins.X)) || isNaN(irutil.Flatten(ins.Y)) { 2790 report.Report(pass, ins, "no value is equal to NaN, not even NaN itself") 2791 } 2792 } 2793 } 2794 } 2795 return nil, nil 2796 } 2797 2798 func CheckInfiniteRecursion(pass *analysis.Pass) (interface{}, error) { 2799 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2800 eachCall(fn, func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) { 2801 if callee != fn { 2802 return 2803 } 2804 if _, ok := site.(*ir.Go); ok { 2805 // Recursively spawning goroutines doesn't consume 2806 // stack space infinitely, so don't flag it. 2807 return 2808 } 2809 2810 block := site.Block() 2811 for _, b := range fn.Blocks { 2812 if block.Dominates(b) { 2813 continue 2814 } 2815 if len(b.Instrs) == 0 { 2816 continue 2817 } 2818 if _, ok := b.Control().(*ir.Return); ok { 2819 return 2820 } 2821 } 2822 report.Report(pass, site, "infinite recursive call") 2823 }) 2824 } 2825 return nil, nil 2826 } 2827 2828 func CheckLeakyTimeTick(pass *analysis.Pass) (interface{}, error) { 2829 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 2830 if code.IsMainLike(pass) || code.IsInTest(pass, fn) { 2831 continue 2832 } 2833 for _, block := range fn.Blocks { 2834 for _, ins := range block.Instrs { 2835 call, ok := ins.(*ir.Call) 2836 if !ok || !irutil.IsCallTo(call.Common(), "time.Tick") { 2837 continue 2838 } 2839 if !irutil.Terminates(call.Parent()) { 2840 continue 2841 } 2842 report.Report(pass, call, "using time.Tick leaks the underlying ticker, consider using it only in endless functions, tests and the main package, and use time.NewTicker here") 2843 } 2844 } 2845 } 2846 return nil, nil 2847 } 2848 2849 var checkDoubleNegationQ = pattern.MustParse(`(UnaryExpr "!" single@(UnaryExpr "!" x))`) 2850 2851 func CheckDoubleNegation(pass *analysis.Pass) (interface{}, error) { 2852 fn := func(node ast.Node) { 2853 if m, ok := code.Match(pass, checkDoubleNegationQ, node); ok { 2854 report.Report(pass, node, "negating a boolean twice has no effect; is this a typo?", report.Fixes( 2855 edit.Fix("turn into single negation", edit.ReplaceWithNode(pass.Fset, node, m.State["single"].(ast.Node))), 2856 edit.Fix("remove double negation", edit.ReplaceWithNode(pass.Fset, node, m.State["x"].(ast.Node))))) 2857 } 2858 } 2859 code.Preorder(pass, fn, (*ast.UnaryExpr)(nil)) 2860 return nil, nil 2861 } 2862 2863 func CheckRepeatedIfElse(pass *analysis.Pass) (interface{}, error) { 2864 seen := map[ast.Node]bool{} 2865 2866 var collectConds func(ifstmt *ast.IfStmt, conds []ast.Expr) ([]ast.Expr, bool) 2867 collectConds = func(ifstmt *ast.IfStmt, conds []ast.Expr) ([]ast.Expr, bool) { 2868 seen[ifstmt] = true 2869 // Bail if any if-statement has an Init statement or side effects in its condition 2870 if ifstmt.Init != nil { 2871 return nil, false 2872 } 2873 if code.MayHaveSideEffects(pass, ifstmt.Cond, nil) { 2874 return nil, false 2875 } 2876 2877 conds = append(conds, ifstmt.Cond) 2878 if elsestmt, ok := ifstmt.Else.(*ast.IfStmt); ok { 2879 return collectConds(elsestmt, conds) 2880 } 2881 return conds, true 2882 } 2883 fn := func(node ast.Node) { 2884 ifstmt := node.(*ast.IfStmt) 2885 if seen[ifstmt] { 2886 // this if-statement is part of an if/else-if chain that we've already processed 2887 return 2888 } 2889 if ifstmt.Else == nil { 2890 // there can be at most one condition 2891 return 2892 } 2893 conds, ok := collectConds(ifstmt, nil) 2894 if !ok { 2895 return 2896 } 2897 if len(conds) < 2 { 2898 return 2899 } 2900 counts := map[string]int{} 2901 for _, cond := range conds { 2902 s := report.Render(pass, cond) 2903 counts[s]++ 2904 if counts[s] == 2 { 2905 report.Report(pass, cond, "this condition occurs multiple times in this if/else if chain") 2906 } 2907 } 2908 } 2909 code.Preorder(pass, fn, (*ast.IfStmt)(nil)) 2910 return nil, nil 2911 } 2912 2913 func CheckSillyBitwiseOps(pass *analysis.Pass) (interface{}, error) { 2914 fn := func(node ast.Node) { 2915 binop := node.(*ast.BinaryExpr) 2916 if !typeutil.All(pass.TypesInfo.TypeOf(binop), func(term *types.Term) bool { 2917 b, ok := term.Type().Underlying().(*types.Basic) 2918 if !ok { 2919 return false 2920 } 2921 return (b.Info() & types.IsInteger) != 0 2922 }) { 2923 return 2924 } 2925 switch binop.Op { 2926 case token.AND, token.OR, token.XOR: 2927 default: 2928 // we do not flag shifts because too often, x<<0 is part 2929 // of a pattern, x<<0, x<<8, x<<16, ... 2930 return 2931 } 2932 if y, ok := binop.Y.(*ast.Ident); ok { 2933 obj, ok := pass.TypesInfo.ObjectOf(y).(*types.Const) 2934 if !ok { 2935 return 2936 } 2937 if obj.Pkg() != pass.Pkg { 2938 // identifier was dot-imported 2939 return 2940 } 2941 if v, _ := constant.Int64Val(obj.Val()); v != 0 { 2942 return 2943 } 2944 path, _ := astutil.PathEnclosingInterval(code.File(pass, obj), obj.Pos(), obj.Pos()) 2945 if len(path) < 2 { 2946 return 2947 } 2948 spec, ok := path[1].(*ast.ValueSpec) 2949 if !ok { 2950 return 2951 } 2952 if len(spec.Names) != 1 || len(spec.Values) != 1 { 2953 // TODO(dh): we could support this 2954 return 2955 } 2956 ident, ok := spec.Values[0].(*ast.Ident) 2957 if !ok { 2958 return 2959 } 2960 if !isIota(pass.TypesInfo.ObjectOf(ident)) { 2961 return 2962 } 2963 switch binop.Op { 2964 case token.AND: 2965 report.Report(pass, node, 2966 fmt.Sprintf("%s always equals 0; %s is defined as iota and has value 0, maybe %s is meant to be 1 << iota?", report.Render(pass, binop), report.Render(pass, binop.Y), report.Render(pass, binop.Y))) 2967 case token.OR, token.XOR: 2968 report.Report(pass, node, 2969 fmt.Sprintf("%s always equals %s; %s is defined as iota and has value 0, maybe %s is meant to be 1 << iota?", report.Render(pass, binop), report.Render(pass, binop.X), report.Render(pass, binop.Y), report.Render(pass, binop.Y))) 2970 } 2971 } else if code.IsIntegerLiteral(pass, binop.Y, constant.MakeInt64(0)) { 2972 switch binop.Op { 2973 case token.AND: 2974 report.Report(pass, node, fmt.Sprintf("%s always equals 0", report.Render(pass, binop))) 2975 case token.OR, token.XOR: 2976 report.Report(pass, node, fmt.Sprintf("%s always equals %s", report.Render(pass, binop), report.Render(pass, binop.X))) 2977 } 2978 } 2979 } 2980 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 2981 return nil, nil 2982 } 2983 2984 func isIota(obj types.Object) bool { 2985 if obj.Name() != "iota" { 2986 return false 2987 } 2988 c, ok := obj.(*types.Const) 2989 if !ok { 2990 return false 2991 } 2992 return c.Pkg() == nil 2993 } 2994 2995 func CheckNonOctalFileMode(pass *analysis.Pass) (interface{}, error) { 2996 fn := func(node ast.Node) { 2997 call := node.(*ast.CallExpr) 2998 for _, arg := range call.Args { 2999 lit, ok := arg.(*ast.BasicLit) 3000 if !ok { 3001 continue 3002 } 3003 if !typeutil.IsType(pass.TypesInfo.TypeOf(lit), "os.FileMode") && 3004 !typeutil.IsType(pass.TypesInfo.TypeOf(lit), "io/fs.FileMode") { 3005 continue 3006 } 3007 if len(lit.Value) == 3 && 3008 lit.Value[0] != '0' && 3009 lit.Value[0] >= '0' && lit.Value[0] <= '7' && 3010 lit.Value[1] >= '0' && lit.Value[1] <= '7' && 3011 lit.Value[2] >= '0' && lit.Value[2] <= '7' { 3012 3013 v, err := strconv.ParseInt(lit.Value, 10, 64) 3014 if err != nil { 3015 continue 3016 } 3017 report.Report(pass, arg, fmt.Sprintf("file mode '%s' evaluates to %#o; did you mean '0%s'?", lit.Value, v, lit.Value), 3018 report.Fixes(edit.Fix("fix octal literal", edit.ReplaceWithString(arg, "0"+lit.Value)))) 3019 } 3020 } 3021 } 3022 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 3023 return nil, nil 3024 } 3025 3026 func CheckSideEffectFreeCalls(pass *analysis.Pass) (interface{}, error) { 3027 pure := pass.ResultOf[purity.Analyzer].(purity.Result) 3028 3029 fnLoop: 3030 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3031 if code.IsInTest(pass, fn) { 3032 params := fn.Signature.Params() 3033 for i := 0; i < params.Len(); i++ { 3034 param := params.At(i) 3035 if typeutil.IsType(param.Type(), "*testing.B") { 3036 // Ignore discarded pure functions in code related 3037 // to benchmarks. Instead of matching BenchmarkFoo 3038 // functions, we match any function accepting a 3039 // *testing.B. Benchmarks sometimes call generic 3040 // functions for doing the actual work, and 3041 // checking for the parameter is a lot easier and 3042 // faster than analyzing call trees. 3043 continue fnLoop 3044 } 3045 } 3046 } 3047 3048 for _, b := range fn.Blocks { 3049 for _, ins := range b.Instrs { 3050 ins, ok := ins.(*ir.Call) 3051 if !ok { 3052 continue 3053 } 3054 refs := ins.Referrers() 3055 if refs == nil || len(irutil.FilterDebug(*refs)) > 0 { 3056 continue 3057 } 3058 3059 callee := ins.Common().StaticCallee() 3060 if callee == nil { 3061 continue 3062 } 3063 if callee.Object() == nil { 3064 // TODO(dh): support anonymous functions 3065 continue 3066 } 3067 if _, ok := pure[callee.Object().(*types.Func)]; ok { 3068 if pass.Pkg.Path() == "fmt_test" && callee.Object().(*types.Func).FullName() == "fmt.Sprintf" { 3069 // special case for benchmarks in the fmt package 3070 continue 3071 } 3072 report.Report(pass, ins, fmt.Sprintf("%s doesn't have side effects and its return value is ignored", callee.Object().Name())) 3073 } 3074 } 3075 } 3076 } 3077 return nil, nil 3078 } 3079 3080 func CheckDeprecated(pass *analysis.Pass) (interface{}, error) { 3081 deprs := pass.ResultOf[deprecated.Analyzer].(deprecated.Result) 3082 3083 // Selectors can appear outside of function literals, e.g. when 3084 // declaring package level variables. 3085 3086 isStdlibPath := func(path string) bool { 3087 // Modules with no dot in the first path element are reserved for the standard library and tooling. 3088 // This is the best we can currently do. 3089 // Nobody tells us which import paths are part of the standard library. 3090 // 3091 // We check the entire path instead of just the first path element, because the standard library doesn't contain paths with any dots, anyway. 3092 3093 return !strings.Contains(path, ".") 3094 } 3095 3096 handleDeprecation := func(depr *deprecated.IsDeprecated, node ast.Node, deprecatedObjName string, pkgPath string, tfn types.Object) { 3097 // Note: gopls doesn't correctly run analyzers on 3098 // dependencies, so we'll never be able to find deprecated 3099 // objects in imported code. We've experimented with 3100 // lifting the stdlib handling out of the general check, 3101 // to at least work for deprecated objects in the stdlib, 3102 // but we gave up on that, because we wouldn't have access 3103 // to the deprecation message. 3104 std, ok := knowledge.StdlibDeprecations[deprecatedObjName] 3105 if !ok && isStdlibPath(pkgPath) { 3106 // Deprecated object in the standard library, but we don't know the details of the deprecation. 3107 // Don't flag it at all, to avoid flagging an object that was deprecated in 1.N when targeting 1.N-1. 3108 // See https://staticcheck.io/issues/1108 for the background on this. 3109 return 3110 } 3111 if ok { 3112 // In the past, we made use of the AlternativeAvailableSince field. If a function was deprecated in Go 3113 // 1.6 and an alternative had been available in Go 1.0, then we'd recommend using the alternative even 3114 // if targeting Go 1.2. The idea was to suggest writing future-proof code by using already-existing 3115 // alternatives. This had a major flaw, however: the user would need to use at least Go 1.6 for 3116 // Staticcheck to know that the function had been deprecated. Thus, targeting Go 1.2 and using Go 1.2 3117 // would behave differently from targeting Go 1.2 and using Go 1.6. This is especially a problem if the 3118 // user tries to ignore the warning. Depending on the Go version in use, the ignore directive may or may 3119 // not match, causing a warning of its own. 3120 // 3121 // To avoid this issue, we no longer try to be smart. We now only compare the targeted version against 3122 // the version that deprecated an object. 3123 // 3124 // Unfortunately, this issue also applies to AlternativeAvailableSince == DeprecatedNeverUse. Even though it 3125 // is only applied to seriously flawed API, such as broken cryptography, users may wish to ignore those 3126 // warnings. 3127 // 3128 // See also https://staticcheck.io/issues/1318. 3129 if !code.IsGoVersion(pass, std.DeprecatedSince) { 3130 return 3131 } 3132 } 3133 3134 if tfn != nil { 3135 if _, ok := deprs.Objects[tfn]; ok { 3136 // functions that are deprecated may use deprecated 3137 // symbols 3138 return 3139 } 3140 } 3141 3142 if ok { 3143 switch std.AlternativeAvailableSince { 3144 case knowledge.DeprecatedNeverUse: 3145 report.Report(pass, node, 3146 fmt.Sprintf("%s has been deprecated since Go 1.%d because it shouldn't be used: %s", 3147 report.Render(pass, node), std.DeprecatedSince, depr.Msg)) 3148 case std.DeprecatedSince, knowledge.DeprecatedUseNoLonger: 3149 report.Report(pass, node, 3150 fmt.Sprintf("%s has been deprecated since Go 1.%d: %s", 3151 report.Render(pass, node), std.DeprecatedSince, depr.Msg)) 3152 default: 3153 report.Report(pass, node, 3154 fmt.Sprintf("%s has been deprecated since Go 1.%d and an alternative has been available since Go 1.%d: %s", 3155 report.Render(pass, node), std.DeprecatedSince, std.AlternativeAvailableSince, depr.Msg)) 3156 } 3157 } else { 3158 report.Report(pass, node, fmt.Sprintf("%s is deprecated: %s", report.Render(pass, node), depr.Msg)) 3159 } 3160 } 3161 3162 var tfn types.Object 3163 stack := 0 3164 fn := func(node ast.Node, push bool) bool { 3165 if !push { 3166 stack-- 3167 return false 3168 } 3169 stack++ 3170 if stack == 1 { 3171 tfn = nil 3172 } 3173 if fn, ok := node.(*ast.FuncDecl); ok { 3174 tfn = pass.TypesInfo.ObjectOf(fn.Name) 3175 } 3176 3177 // FIXME(dh): this misses dot-imported objects 3178 sel, ok := node.(*ast.SelectorExpr) 3179 if !ok { 3180 return true 3181 } 3182 3183 obj := pass.TypesInfo.ObjectOf(sel.Sel) 3184 if obj_, ok := obj.(*types.Func); ok { 3185 obj = obj_.Origin() 3186 } 3187 if obj.Pkg() == nil { 3188 return true 3189 } 3190 3191 if obj.Pkg() == pass.Pkg { 3192 // A package is allowed to use its own deprecated objects 3193 return true 3194 } 3195 3196 // A package "foo" has two related packages "foo_test" and "foo.test", for external tests and the package main 3197 // generated by 'go test' respectively. "foo_test" can import and use "foo", "foo.test" imports and uses "foo" 3198 // and "foo_test". 3199 3200 if strings.TrimSuffix(pass.Pkg.Path(), "_test") == obj.Pkg().Path() { 3201 // foo_test (the external tests of foo) can use objects from foo. 3202 return true 3203 } 3204 if strings.TrimSuffix(pass.Pkg.Path(), ".test") == obj.Pkg().Path() { 3205 // foo.test (the main package of foo's tests) can use objects from foo. 3206 return true 3207 } 3208 if strings.TrimSuffix(pass.Pkg.Path(), ".test") == strings.TrimSuffix(obj.Pkg().Path(), "_test") { 3209 // foo.test (the main package of foo's tests) can use objects from foo's external tests. 3210 return true 3211 } 3212 3213 if depr, ok := deprs.Objects[obj]; ok { 3214 handleDeprecation(depr, sel, code.SelectorName(pass, sel), obj.Pkg().Path(), tfn) 3215 } 3216 return true 3217 } 3218 3219 fn2 := func(node ast.Node) { 3220 spec := node.(*ast.ImportSpec) 3221 var imp *types.Package 3222 if spec.Name != nil { 3223 imp = pass.TypesInfo.ObjectOf(spec.Name).(*types.PkgName).Imported() 3224 } else { 3225 imp = pass.TypesInfo.Implicits[spec].(*types.PkgName).Imported() 3226 } 3227 3228 p := spec.Path.Value 3229 path := p[1 : len(p)-1] 3230 if depr, ok := deprs.Packages[imp]; ok { 3231 if path == "github.com/golang/protobuf/proto" { 3232 gen, ok := code.Generator(pass, spec.Path.Pos()) 3233 if ok && gen == generated.ProtocGenGo { 3234 return 3235 } 3236 } 3237 3238 if strings.TrimSuffix(pass.Pkg.Path(), "_test") == path { 3239 // foo_test can import foo 3240 return 3241 } 3242 if strings.TrimSuffix(pass.Pkg.Path(), ".test") == path { 3243 // foo.test can import foo 3244 return 3245 } 3246 if strings.TrimSuffix(pass.Pkg.Path(), ".test") == strings.TrimSuffix(path, "_test") { 3247 // foo.test can import foo_test 3248 return 3249 } 3250 3251 handleDeprecation(depr, spec.Path, path, path, nil) 3252 } 3253 } 3254 pass.ResultOf[inspect.Analyzer].(*inspector.Inspector).Nodes(nil, fn) 3255 code.Preorder(pass, fn2, (*ast.ImportSpec)(nil)) 3256 return nil, nil 3257 } 3258 3259 func callChecker(rules map[string]CallCheck) func(pass *analysis.Pass) (interface{}, error) { 3260 return func(pass *analysis.Pass) (interface{}, error) { 3261 return checkCalls(pass, rules) 3262 } 3263 } 3264 3265 func checkCalls(pass *analysis.Pass, rules map[string]CallCheck) (interface{}, error) { 3266 cb := func(caller *ir.Function, site ir.CallInstruction, callee *ir.Function) { 3267 obj, ok := callee.Object().(*types.Func) 3268 if !ok { 3269 return 3270 } 3271 3272 r, ok := rules[typeutil.FuncName(obj)] 3273 if !ok { 3274 return 3275 } 3276 var args []*Argument 3277 irargs := site.Common().Args 3278 if callee.Signature.Recv() != nil { 3279 irargs = irargs[1:] 3280 } 3281 for _, arg := range irargs { 3282 if iarg, ok := arg.(*ir.MakeInterface); ok { 3283 arg = iarg.X 3284 } 3285 args = append(args, &Argument{Value: Value{arg}}) 3286 } 3287 call := &Call{ 3288 Pass: pass, 3289 Instr: site, 3290 Args: args, 3291 Parent: site.Parent(), 3292 } 3293 r(call) 3294 3295 var astcall *ast.CallExpr 3296 switch source := site.Source().(type) { 3297 case *ast.CallExpr: 3298 astcall = source 3299 case *ast.DeferStmt: 3300 astcall = source.Call 3301 case *ast.GoStmt: 3302 astcall = source.Call 3303 case nil: 3304 // TODO(dh): I am not sure this can actually happen. If it 3305 // can't, we should remove this case, and also stop 3306 // checking for astcall == nil in the code that follows. 3307 default: 3308 panic(fmt.Sprintf("unhandled case %T", source)) 3309 } 3310 3311 for idx, arg := range call.Args { 3312 for _, e := range arg.invalids { 3313 if astcall != nil { 3314 if idx < len(astcall.Args) { 3315 report.Report(pass, astcall.Args[idx], e) 3316 } else { 3317 // this is an instance of fn1(fn2()) where fn2 3318 // returns multiple values. Report the error 3319 // at the next-best position that we have, the 3320 // first argument. An example of a check that 3321 // triggers this is checkEncodingBinaryRules. 3322 report.Report(pass, astcall.Args[0], e) 3323 } 3324 } else { 3325 report.Report(pass, site, e) 3326 } 3327 } 3328 } 3329 for _, e := range call.invalids { 3330 report.Report(pass, call.Instr, e) 3331 } 3332 } 3333 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3334 eachCall(fn, cb) 3335 } 3336 return nil, nil 3337 } 3338 3339 func shortCallName(call *ir.CallCommon) string { 3340 if call.IsInvoke() { 3341 return "" 3342 } 3343 switch v := call.Value.(type) { 3344 case *ir.Function: 3345 fn, ok := v.Object().(*types.Func) 3346 if !ok { 3347 return "" 3348 } 3349 return fn.Name() 3350 case *ir.Builtin: 3351 return v.Name() 3352 } 3353 return "" 3354 } 3355 3356 func CheckWriterBufferModified(pass *analysis.Pass) (interface{}, error) { 3357 // TODO(dh): this might be a good candidate for taint analysis. 3358 // Taint the argument as MUST_NOT_MODIFY, then propagate that 3359 // through functions like bytes.Split 3360 3361 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3362 sig := fn.Signature 3363 if fn.Name() != "Write" || sig.Recv() == nil || sig.Params().Len() != 1 || sig.Results().Len() != 2 { 3364 continue 3365 } 3366 tArg, ok := sig.Params().At(0).Type().(*types.Slice) 3367 if !ok { 3368 continue 3369 } 3370 if basic, ok := tArg.Elem().(*types.Basic); !ok || basic.Kind() != types.Byte { 3371 continue 3372 } 3373 if basic, ok := sig.Results().At(0).Type().(*types.Basic); !ok || basic.Kind() != types.Int { 3374 continue 3375 } 3376 if named, ok := sig.Results().At(1).Type().(*types.Named); !ok || !typeutil.IsType(named, "error") { 3377 continue 3378 } 3379 3380 for _, block := range fn.Blocks { 3381 for _, ins := range block.Instrs { 3382 switch ins := ins.(type) { 3383 case *ir.Store: 3384 addr, ok := ins.Addr.(*ir.IndexAddr) 3385 if !ok { 3386 continue 3387 } 3388 if addr.X != fn.Params[1] { 3389 continue 3390 } 3391 report.Report(pass, ins, "io.Writer.Write must not modify the provided buffer, not even temporarily") 3392 case *ir.Call: 3393 if !irutil.IsCallTo(ins.Common(), "append") { 3394 continue 3395 } 3396 if ins.Common().Args[0] != fn.Params[1] { 3397 continue 3398 } 3399 report.Report(pass, ins, "io.Writer.Write must not modify the provided buffer, not even temporarily") 3400 } 3401 } 3402 } 3403 } 3404 return nil, nil 3405 } 3406 3407 func loopedRegexp(name string) CallCheck { 3408 return func(call *Call) { 3409 if extractConst(call.Args[0].Value.Value) == nil { 3410 return 3411 } 3412 if !isInLoop(call.Instr.Block()) { 3413 return 3414 } 3415 call.Invalid(fmt.Sprintf("calling %s in a loop has poor performance, consider using regexp.Compile", name)) 3416 } 3417 } 3418 3419 func CheckEmptyBranch(pass *analysis.Pass) (interface{}, error) { 3420 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3421 if fn.Source() == nil { 3422 continue 3423 } 3424 if irutil.IsExample(fn) { 3425 continue 3426 } 3427 cb := func(node ast.Node) bool { 3428 ifstmt, ok := node.(*ast.IfStmt) 3429 if !ok { 3430 return true 3431 } 3432 if ifstmt.Else != nil { 3433 b, ok := ifstmt.Else.(*ast.BlockStmt) 3434 if !ok || len(b.List) != 0 { 3435 return true 3436 } 3437 report.Report(pass, ifstmt.Else, "empty branch", report.FilterGenerated(), report.ShortRange()) 3438 } 3439 if len(ifstmt.Body.List) != 0 { 3440 return true 3441 } 3442 report.Report(pass, ifstmt, "empty branch", report.FilterGenerated(), report.ShortRange()) 3443 return true 3444 } 3445 if source := fn.Source(); source != nil { 3446 ast.Inspect(source, cb) 3447 } 3448 } 3449 return nil, nil 3450 } 3451 3452 func CheckMapBytesKey(pass *analysis.Pass) (interface{}, error) { 3453 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3454 for _, b := range fn.Blocks { 3455 insLoop: 3456 for _, ins := range b.Instrs { 3457 // find []byte -> string conversions 3458 conv, ok := ins.(*ir.Convert) 3459 if !ok || conv.Type() != types.Universe.Lookup("string").Type() { 3460 continue 3461 } 3462 tset := typeutil.NewTypeSet(conv.X.Type()) 3463 // If at least one of the types is []byte, then it's more efficient to inline the conversion 3464 if !tset.Any(func(term *types.Term) bool { 3465 s, ok := term.Type().Underlying().(*types.Slice) 3466 return ok && s.Elem().Underlying() == types.Universe.Lookup("byte").Type() 3467 }) { 3468 continue 3469 } 3470 refs := conv.Referrers() 3471 // need at least two (DebugRef) references: the 3472 // conversion and the *ast.Ident 3473 if refs == nil || len(*refs) < 2 { 3474 continue 3475 } 3476 ident := false 3477 // skip first reference, that's the conversion itself 3478 for _, ref := range (*refs)[1:] { 3479 switch ref := ref.(type) { 3480 case *ir.DebugRef: 3481 if _, ok := ref.Expr.(*ast.Ident); !ok { 3482 // the string seems to be used somewhere 3483 // unexpected; the default branch should 3484 // catch this already, but be safe 3485 continue insLoop 3486 } else { 3487 ident = true 3488 } 3489 case *ir.MapLookup: 3490 default: 3491 // the string is used somewhere else than a 3492 // map lookup 3493 continue insLoop 3494 } 3495 } 3496 3497 // the result of the conversion wasn't assigned to an 3498 // identifier 3499 if !ident { 3500 continue 3501 } 3502 report.Report(pass, conv, "m[string(key)] would be more efficient than k := string(key); m[k]") 3503 } 3504 } 3505 } 3506 return nil, nil 3507 } 3508 3509 func CheckRangeStringRunes(pass *analysis.Pass) (interface{}, error) { 3510 return sharedcheck.CheckRangeStringRunes(pass) 3511 } 3512 3513 func CheckSelfAssignment(pass *analysis.Pass) (interface{}, error) { 3514 pure := pass.ResultOf[purity.Analyzer].(purity.Result) 3515 3516 fn := func(node ast.Node) { 3517 assign := node.(*ast.AssignStmt) 3518 if assign.Tok != token.ASSIGN || len(assign.Lhs) != len(assign.Rhs) { 3519 return 3520 } 3521 for i, lhs := range assign.Lhs { 3522 rhs := assign.Rhs[i] 3523 if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) { 3524 continue 3525 } 3526 if code.MayHaveSideEffects(pass, lhs, pure) || code.MayHaveSideEffects(pass, rhs, pure) { 3527 continue 3528 } 3529 3530 rlh := report.Render(pass, lhs) 3531 rrh := report.Render(pass, rhs) 3532 if rlh == rrh { 3533 report.Report(pass, assign, fmt.Sprintf("self-assignment of %s to %s", rrh, rlh), report.FilterGenerated()) 3534 } 3535 } 3536 } 3537 code.Preorder(pass, fn, (*ast.AssignStmt)(nil)) 3538 return nil, nil 3539 } 3540 3541 func buildTagsIdentical(s1, s2 []string) bool { 3542 if len(s1) != len(s2) { 3543 return false 3544 } 3545 s1s := make([]string, len(s1)) 3546 copy(s1s, s1) 3547 sort.Strings(s1s) 3548 s2s := make([]string, len(s2)) 3549 copy(s2s, s2) 3550 sort.Strings(s2s) 3551 for i, s := range s1s { 3552 if s != s2s[i] { 3553 return false 3554 } 3555 } 3556 return true 3557 } 3558 3559 func CheckDuplicateBuildConstraints(pass *analysis.Pass) (interface{}, error) { 3560 for _, f := range pass.Files { 3561 constraints := buildTags(f) 3562 for i, constraint1 := range constraints { 3563 for j, constraint2 := range constraints { 3564 if i >= j { 3565 continue 3566 } 3567 if buildTagsIdentical(constraint1, constraint2) { 3568 msg := fmt.Sprintf("identical build constraints %q and %q", 3569 strings.Join(constraint1, " "), 3570 strings.Join(constraint2, " ")) 3571 report.Report(pass, f, msg, report.FilterGenerated(), report.ShortRange()) 3572 } 3573 } 3574 } 3575 } 3576 return nil, nil 3577 } 3578 3579 func CheckSillyRegexp(pass *analysis.Pass) (interface{}, error) { 3580 // We could use the rule checking engine for this, but the 3581 // arguments aren't really invalid. 3582 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3583 for _, b := range fn.Blocks { 3584 for _, ins := range b.Instrs { 3585 call, ok := ins.(*ir.Call) 3586 if !ok { 3587 continue 3588 } 3589 if !irutil.IsCallToAny(call.Common(), "regexp.MustCompile", "regexp.Compile", "regexp.Match", "regexp.MatchReader", "regexp.MatchString") { 3590 continue 3591 } 3592 c, ok := call.Common().Args[0].(*ir.Const) 3593 if !ok { 3594 continue 3595 } 3596 s := constant.StringVal(c.Value) 3597 re, err := syntax.Parse(s, 0) 3598 if err != nil { 3599 continue 3600 } 3601 if re.Op != syntax.OpLiteral && re.Op != syntax.OpEmptyMatch { 3602 continue 3603 } 3604 report.Report(pass, call, "regular expression does not contain any meta characters") 3605 } 3606 } 3607 } 3608 return nil, nil 3609 } 3610 3611 func CheckMissingEnumTypesInDeclaration(pass *analysis.Pass) (interface{}, error) { 3612 convertibleTo := func(V, T types.Type) bool { 3613 if types.ConvertibleTo(V, T) { 3614 return true 3615 } 3616 // Go <1.16 returns false for untyped string to string conversion 3617 if V, ok := V.(*types.Basic); ok && V.Kind() == types.UntypedString { 3618 if T, ok := T.Underlying().(*types.Basic); ok && T.Kind() == types.String { 3619 return true 3620 } 3621 } 3622 return false 3623 } 3624 fn := func(node ast.Node) { 3625 decl := node.(*ast.GenDecl) 3626 if !decl.Lparen.IsValid() { 3627 return 3628 } 3629 if decl.Tok != token.CONST { 3630 return 3631 } 3632 3633 groups := astutil.GroupSpecs(pass.Fset, decl.Specs) 3634 groupLoop: 3635 for _, group := range groups { 3636 if len(group) < 2 { 3637 continue 3638 } 3639 if group[0].(*ast.ValueSpec).Type == nil { 3640 // first constant doesn't have a type 3641 continue groupLoop 3642 } 3643 3644 firstType := pass.TypesInfo.TypeOf(group[0].(*ast.ValueSpec).Values[0]) 3645 for i, spec := range group { 3646 spec := spec.(*ast.ValueSpec) 3647 if i > 0 && spec.Type != nil { 3648 continue groupLoop 3649 } 3650 if len(spec.Names) != 1 || len(spec.Values) != 1 { 3651 continue groupLoop 3652 } 3653 3654 if !convertibleTo(pass.TypesInfo.TypeOf(spec.Values[0]), firstType) { 3655 continue groupLoop 3656 } 3657 3658 switch v := spec.Values[0].(type) { 3659 case *ast.BasicLit: 3660 case *ast.UnaryExpr: 3661 if _, ok := v.X.(*ast.BasicLit); !ok { 3662 continue groupLoop 3663 } 3664 default: 3665 // if it's not a literal it might be typed, such as 3666 // time.Microsecond = 1000 * Nanosecond 3667 continue groupLoop 3668 } 3669 } 3670 var edits []analysis.TextEdit 3671 typ := group[0].(*ast.ValueSpec).Type 3672 for _, spec := range group[1:] { 3673 nspec := *spec.(*ast.ValueSpec) 3674 nspec.Type = typ 3675 // The position of `spec` node excludes comments (if any). 3676 // However, on generating the source back from the node, the comments are included. Setting `Comment` to nil ensures deduplication of comments. 3677 nspec.Comment = nil 3678 edits = append(edits, edit.ReplaceWithNode(pass.Fset, spec, &nspec)) 3679 } 3680 report.Report(pass, group[0], "only the first constant in this group has an explicit type", report.Fixes(edit.Fix("add type to all constants in group", edits...))) 3681 } 3682 } 3683 code.Preorder(pass, fn, (*ast.GenDecl)(nil)) 3684 return nil, nil 3685 } 3686 3687 func CheckTimerResetReturnValue(pass *analysis.Pass) (interface{}, error) { 3688 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 3689 for _, block := range fn.Blocks { 3690 for _, ins := range block.Instrs { 3691 call, ok := ins.(*ir.Call) 3692 if !ok { 3693 continue 3694 } 3695 if !irutil.IsCallTo(call.Common(), "(*time.Timer).Reset") { 3696 continue 3697 } 3698 refs := call.Referrers() 3699 if refs == nil { 3700 continue 3701 } 3702 for _, ref := range irutil.FilterDebug(*refs) { 3703 ifstmt, ok := ref.(*ir.If) 3704 if !ok { 3705 continue 3706 } 3707 3708 found := false 3709 for _, succ := range ifstmt.Block().Succs { 3710 if len(succ.Preds) != 1 { 3711 // Merge point, not a branch in the 3712 // syntactical sense. 3713 3714 // FIXME(dh): this is broken for if 3715 // statements a la "if x || y" 3716 continue 3717 } 3718 irutil.Walk(succ, func(b *ir.BasicBlock) bool { 3719 if !succ.Dominates(b) { 3720 // We've reached the end of the branch 3721 return false 3722 } 3723 for _, ins := range b.Instrs { 3724 // TODO(dh): we should check that 3725 // we're receiving from the channel of 3726 // a time.Timer to further reduce 3727 // false positives. Not a key 3728 // priority, considering the rarity of 3729 // Reset and the tiny likeliness of a 3730 // false positive 3731 if ins, ok := ins.(*ir.Recv); ok && typeutil.IsType(ins.Chan.Type(), "<-chan time.Time") { 3732 found = true 3733 return false 3734 } 3735 } 3736 return true 3737 }) 3738 } 3739 3740 if found { 3741 report.Report(pass, call, "it is not possible to use Reset's return value correctly, as there is a race condition between draining the channel and the new timer expiring") 3742 } 3743 } 3744 } 3745 } 3746 } 3747 return nil, nil 3748 } 3749 3750 var ( 3751 checkToLowerToUpperComparisonQ = pattern.MustParse(` 3752 (BinaryExpr 3753 (CallExpr fun@(Symbol (Or "strings.ToLower" "strings.ToUpper")) [a]) 3754 tok@(Or "==" "!=") 3755 (CallExpr fun [b]))`) 3756 checkToLowerToUpperComparisonR = pattern.MustParse(`(CallExpr (SelectorExpr (Ident "strings") (Ident "EqualFold")) [a b])`) 3757 ) 3758 3759 func CheckToLowerToUpperComparison(pass *analysis.Pass) (interface{}, error) { 3760 fn := func(node ast.Node) { 3761 m, ok := code.Match(pass, checkToLowerToUpperComparisonQ, node) 3762 if !ok { 3763 return 3764 } 3765 rn := pattern.NodeToAST(checkToLowerToUpperComparisonR.Root, m.State).(ast.Expr) 3766 if m.State["tok"].(token.Token) == token.NEQ { 3767 rn = &ast.UnaryExpr{ 3768 Op: token.NOT, 3769 X: rn, 3770 } 3771 } 3772 3773 report.Report(pass, node, "should use strings.EqualFold instead", report.Fixes(edit.Fix("replace with strings.EqualFold", edit.ReplaceWithNode(pass.Fset, node, rn)))) 3774 } 3775 3776 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 3777 return nil, nil 3778 } 3779 3780 func CheckUnreachableTypeCases(pass *analysis.Pass) (interface{}, error) { 3781 // Check if T subsumes V in a type switch. T subsumes V if T is an interface and T's method set is a subset of V's method set. 3782 subsumes := func(T, V types.Type) bool { 3783 if typeparams.IsTypeParam(T) { 3784 return false 3785 } 3786 tIface, ok := T.Underlying().(*types.Interface) 3787 if !ok { 3788 return false 3789 } 3790 3791 return types.Implements(V, tIface) 3792 } 3793 3794 subsumesAny := func(Ts, Vs []types.Type) (types.Type, types.Type, bool) { 3795 for _, T := range Ts { 3796 for _, V := range Vs { 3797 if subsumes(T, V) { 3798 return T, V, true 3799 } 3800 } 3801 } 3802 3803 return nil, nil, false 3804 } 3805 3806 fn := func(node ast.Node) { 3807 tsStmt := node.(*ast.TypeSwitchStmt) 3808 3809 type ccAndTypes struct { 3810 cc *ast.CaseClause 3811 types []types.Type 3812 } 3813 3814 // All asserted types in the order of case clauses. 3815 ccs := make([]ccAndTypes, 0, len(tsStmt.Body.List)) 3816 for _, stmt := range tsStmt.Body.List { 3817 cc, _ := stmt.(*ast.CaseClause) 3818 3819 // Exclude the 'default' case. 3820 if len(cc.List) == 0 { 3821 continue 3822 } 3823 3824 Ts := make([]types.Type, 0, len(cc.List)) 3825 for _, expr := range cc.List { 3826 // Exclude the 'nil' value from any 'case' statement (it is always reachable). 3827 if typ := pass.TypesInfo.TypeOf(expr); typ != types.Typ[types.UntypedNil] { 3828 Ts = append(Ts, typ) 3829 } 3830 } 3831 3832 ccs = append(ccs, ccAndTypes{cc: cc, types: Ts}) 3833 } 3834 3835 if len(ccs) <= 1 { 3836 // Zero or one case clauses, nothing to check. 3837 return 3838 } 3839 3840 // Check if case clauses following cc have types that are subsumed by cc. 3841 for i, cc := range ccs[:len(ccs)-1] { 3842 for _, next := range ccs[i+1:] { 3843 if T, V, yes := subsumesAny(cc.types, next.types); yes { 3844 report.Report(pass, next.cc, fmt.Sprintf("unreachable case clause: %s will always match before %s", T.String(), V.String()), 3845 report.ShortRange()) 3846 } 3847 } 3848 } 3849 } 3850 3851 code.Preorder(pass, fn, (*ast.TypeSwitchStmt)(nil)) 3852 return nil, nil 3853 } 3854 3855 var checkSingleArgAppendQ = pattern.MustParse(`(CallExpr (Builtin "append") [_])`) 3856 3857 func CheckSingleArgAppend(pass *analysis.Pass) (interface{}, error) { 3858 fn := func(node ast.Node) { 3859 _, ok := code.Match(pass, checkSingleArgAppendQ, node) 3860 if !ok { 3861 return 3862 } 3863 report.Report(pass, node, "x = append(y) is equivalent to x = y", report.FilterGenerated()) 3864 } 3865 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 3866 return nil, nil 3867 } 3868 3869 func CheckStructTags(pass *analysis.Pass) (interface{}, error) { 3870 importsGoFlags := false 3871 3872 // we use the AST instead of (*types.Package).Imports to work 3873 // around vendored packages in GOPATH mode. A vendored package's 3874 // path will include the vendoring subtree as a prefix. 3875 for _, f := range pass.Files { 3876 for _, imp := range f.Imports { 3877 v := imp.Path.Value 3878 if v[1:len(v)-1] == "github.com/jessevdk/go-flags" { 3879 importsGoFlags = true 3880 break 3881 } 3882 } 3883 } 3884 3885 fn := func(node ast.Node) { 3886 structNode := node.(*ast.StructType) 3887 T := pass.TypesInfo.Types[structNode].Type.(*types.Struct) 3888 rt := fakereflect.TypeAndCanAddr{ 3889 Type: T, 3890 } 3891 for i, field := range structNode.Fields.List { 3892 if field.Tag == nil { 3893 continue 3894 } 3895 tags, err := parseStructTag(field.Tag.Value[1 : len(field.Tag.Value)-1]) 3896 if err != nil { 3897 report.Report(pass, field.Tag, fmt.Sprintf("unparseable struct tag: %s", err)) 3898 continue 3899 } 3900 for k, v := range tags { 3901 if len(v) > 1 { 3902 isGoFlagsTag := importsGoFlags && 3903 (k == "choice" || k == "optional-value" || k == "default") 3904 if !isGoFlagsTag { 3905 report.Report(pass, field.Tag, fmt.Sprintf("duplicate struct tag %q", k)) 3906 } 3907 } 3908 3909 switch k { 3910 case "json": 3911 checkJSONTag(pass, field, v[0]) 3912 case "xml": 3913 if _, err := fakexml.StructFieldInfo(rt.Field(i)); err != nil { 3914 report.Report(pass, field.Tag, fmt.Sprintf("invalid XML tag: %s", err)) 3915 } 3916 checkXMLTag(pass, field, v[0]) 3917 } 3918 } 3919 } 3920 } 3921 code.Preorder(pass, fn, (*ast.StructType)(nil)) 3922 return nil, nil 3923 } 3924 3925 func checkJSONTag(pass *analysis.Pass, field *ast.Field, tag string) { 3926 if pass.Pkg.Path() == "encoding/json" || pass.Pkg.Path() == "encoding/json_test" { 3927 // don't flag malformed JSON tags in the encoding/json 3928 // package; it knows what it is doing, and it is testing 3929 // itself. 3930 return 3931 } 3932 //lint:ignore SA9003 TODO(dh): should we flag empty tags? 3933 if len(tag) == 0 { 3934 } 3935 if i := strings.Index(tag, ",format:"); i >= 0 { 3936 tag = tag[:i] 3937 } 3938 fields := strings.Split(tag, ",") 3939 for _, r := range fields[0] { 3940 if !unicode.IsLetter(r) && !unicode.IsDigit(r) && !strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", r) { 3941 report.Report(pass, field.Tag, fmt.Sprintf("invalid JSON field name %q", fields[0])) 3942 } 3943 } 3944 options := make(map[string]int) 3945 for _, s := range fields[1:] { 3946 switch s { 3947 case "": 3948 // allow stuff like "-," 3949 case "string": 3950 // only for string, floating point, integer and bool 3951 options[s]++ 3952 tset := typeutil.NewTypeSet(pass.TypesInfo.TypeOf(field.Type)) 3953 if len(tset.Terms) == 0 { 3954 // TODO(dh): improve message, call out the use of type parameters 3955 report.Report(pass, field.Tag, "the JSON string option only applies to fields of type string, floating point, integer or bool, or pointers to those") 3956 continue 3957 } 3958 for _, term := range tset.Terms { 3959 T := typeutil.Dereference(term.Type().Underlying()) 3960 for _, term2 := range typeutil.NewTypeSet(T).Terms { 3961 basic, ok := term2.Type().Underlying().(*types.Basic) 3962 if !ok || (basic.Info()&(types.IsBoolean|types.IsInteger|types.IsFloat|types.IsString)) == 0 { 3963 // TODO(dh): improve message, show how we arrived at the type 3964 report.Report(pass, field.Tag, "the JSON string option only applies to fields of type string, floating point, integer or bool, or pointers to those") 3965 } 3966 } 3967 } 3968 case "omitzero", "omitempty", "nocase", "inline", "unknown": 3969 options[s]++ 3970 default: 3971 report.Report(pass, field.Tag, fmt.Sprintf("unknown JSON option %q", s)) 3972 } 3973 } 3974 var duplicates []string 3975 for option, n := range options { 3976 if n > 1 { 3977 duplicates = append(duplicates, option) 3978 } 3979 } 3980 if len(duplicates) > 0 { 3981 sort.Strings(duplicates) 3982 for _, option := range duplicates { 3983 report.Report(pass, field.Tag, fmt.Sprintf("duplicate JSON option %q", option)) 3984 } 3985 } 3986 } 3987 3988 func checkXMLTag(pass *analysis.Pass, field *ast.Field, tag string) { 3989 //lint:ignore SA9003 TODO(dh): should we flag empty tags? 3990 if len(tag) == 0 { 3991 } 3992 fields := strings.Split(tag, ",") 3993 counts := map[string]int{} 3994 for _, s := range fields[1:] { 3995 switch s { 3996 case "attr", "chardata", "cdata", "innerxml", "comment": 3997 counts[s]++ 3998 case "omitempty", "any": 3999 counts[s]++ 4000 case "": 4001 default: 4002 report.Report(pass, field.Tag, fmt.Sprintf("invalid XML tag: unknown option %q", s)) 4003 } 4004 } 4005 for k, v := range counts { 4006 if v > 1 { 4007 report.Report(pass, field.Tag, fmt.Sprintf("invalid XML tag: duplicate option %q", k)) 4008 } 4009 } 4010 } 4011 4012 func CheckImpossibleTypeAssertion(pass *analysis.Pass) (interface{}, error) { 4013 type entry struct { 4014 l, r *types.Func 4015 } 4016 4017 msc := &pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg.Prog.MethodSets 4018 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 4019 for _, b := range fn.Blocks { 4020 for _, instr := range b.Instrs { 4021 assert, ok := instr.(*ir.TypeAssert) 4022 if !ok { 4023 continue 4024 } 4025 var wrong []entry 4026 left := assert.X.Type() 4027 right := assert.AssertedType 4028 righti, ok := right.Underlying().(*types.Interface) 4029 4030 if !ok { 4031 // We only care about interface->interface 4032 // assertions. The Go compiler already catches 4033 // impossible interface->concrete assertions. 4034 continue 4035 } 4036 4037 ms := msc.MethodSet(left) 4038 for i := 0; i < righti.NumMethods(); i++ { 4039 mr := righti.Method(i).Origin() 4040 sel := ms.Lookup(mr.Pkg(), mr.Name()) 4041 if sel == nil { 4042 continue 4043 } 4044 ml := sel.Obj().(*types.Func).Origin() 4045 if types.AssignableTo(ml.Type(), mr.Type()) { 4046 continue 4047 } 4048 4049 wrong = append(wrong, entry{ml, mr}) 4050 } 4051 4052 if len(wrong) != 0 { 4053 s := fmt.Sprintf("impossible type assertion; %s and %s contradict each other:", 4054 types.TypeString(left, types.RelativeTo(pass.Pkg)), 4055 types.TypeString(right, types.RelativeTo(pass.Pkg))) 4056 for _, e := range wrong { 4057 s += fmt.Sprintf("\n\twrong type for %s method", e.l.Name()) 4058 s += fmt.Sprintf("\n\t\thave %s", e.l.Type()) 4059 s += fmt.Sprintf("\n\t\twant %s", e.r.Type()) 4060 } 4061 report.Report(pass, assert, s) 4062 } 4063 } 4064 } 4065 } 4066 return nil, nil 4067 } 4068 4069 func checkWithValueKey(call *Call) { 4070 arg := call.Args[1] 4071 T := arg.Value.Value.Type() 4072 if T, ok := T.(*types.Basic); ok { 4073 arg.Invalid( 4074 fmt.Sprintf("should not use built-in type %s as key for value; define your own type to avoid collisions", T)) 4075 } 4076 if !types.Comparable(T) { 4077 arg.Invalid(fmt.Sprintf("keys used with context.WithValue must be comparable, but type %s is not comparable", T)) 4078 } 4079 } 4080 4081 func CheckMaybeNil(pass *analysis.Pass) (interface{}, error) { 4082 // This is an extremely trivial check that doesn't try to reason 4083 // about control flow. That is, phis and sigmas do not propagate 4084 // any information. As such, we can flag this: 4085 // 4086 // _ = *x 4087 // if x == nil { return } 4088 // 4089 // but we cannot flag this: 4090 // 4091 // if x == nil { println(x) } 4092 // _ = *x 4093 // 4094 // but we can flag this, because the if's body doesn't use x: 4095 // 4096 // if x == nil { println("this is bad") } 4097 // _ = *x 4098 // 4099 // nor many other variations of conditional uses of or assignments to x. 4100 // 4101 // However, even this trivial implementation finds plenty of 4102 // real-world bugs, such as dereference before nil pointer check, 4103 // or using t.Error instead of t.Fatal when encountering nil 4104 // pointers. 4105 // 4106 // On the flip side, our naive implementation avoids false positives in branches, such as 4107 // 4108 // if x != nil { _ = *x } 4109 // 4110 // due to the same lack of propagating information through sigma 4111 // nodes. x inside the branch will be independent of the x in the 4112 // nil pointer check. 4113 // 4114 // 4115 // We could implement a more powerful check, but then we'd be 4116 // getting false positives instead of false negatives because 4117 // we're incapable of deducing relationships between variables. 4118 // For example, a function might return a pointer and an error, 4119 // and the error being nil guarantees that the pointer is not nil. 4120 // Depending on the surrounding code, the pointer may still end up 4121 // being checked against nil in one place, and guarded by a check 4122 // on the error in another, which would lead to us marking some 4123 // loads as unsafe. 4124 // 4125 // Unfortunately, simply hard-coding the relationship between 4126 // return values wouldn't eliminate all false positives, either. 4127 // Many other more subtle relationships exist. An abridged example 4128 // from real code: 4129 // 4130 // if a == nil && b == nil { return } 4131 // c := fn(a) 4132 // if c != "" { _ = *a } 4133 // 4134 // where `fn` is guaranteed to return a non-empty string if a 4135 // isn't nil. 4136 // 4137 // We choose to err on the side of false negatives. 4138 4139 isNilConst := func(v ir.Value) bool { 4140 if typeutil.IsPointerLike(v.Type()) { 4141 if k, ok := v.(*ir.Const); ok { 4142 return k.IsNil() 4143 } 4144 } 4145 return false 4146 } 4147 4148 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 4149 maybeNil := map[ir.Value]ir.Instruction{} 4150 for _, b := range fn.Blocks { 4151 for _, instr := range b.Instrs { 4152 // Originally we looked at all ir.BinOp, but that would lead to calls like 'assert(x != nil)' causing false positives. 4153 // Restrict ourselves to actual if statements, as these are more likely to affect control flow in a way we can observe. 4154 if instr, ok := instr.(*ir.If); ok { 4155 if cond, ok := instr.Cond.(*ir.BinOp); ok { 4156 var ptr ir.Value 4157 if isNilConst(cond.X) { 4158 ptr = cond.Y 4159 } else if isNilConst(cond.Y) { 4160 ptr = cond.X 4161 } 4162 maybeNil[ptr] = cond 4163 } 4164 } 4165 } 4166 } 4167 4168 for _, b := range fn.Blocks { 4169 for _, instr := range b.Instrs { 4170 var ptr ir.Value 4171 switch instr := instr.(type) { 4172 case *ir.Load: 4173 ptr = instr.X 4174 case *ir.Store: 4175 ptr = instr.Addr 4176 case *ir.IndexAddr: 4177 ptr = instr.X 4178 if typeutil.All(ptr.Type(), func(term *types.Term) bool { 4179 if _, ok := term.Type().Underlying().(*types.Slice); ok { 4180 return true 4181 } 4182 return false 4183 }) { 4184 // indexing a nil slice does not cause a nil pointer panic 4185 // 4186 // Note: This also works around the bad lowering of range loops over slices 4187 // (https://github.com/dominikh/go-tools/issues/1053) 4188 continue 4189 } 4190 case *ir.FieldAddr: 4191 ptr = instr.X 4192 } 4193 if ptr != nil { 4194 switch ptr.(type) { 4195 case *ir.Alloc, *ir.FieldAddr, *ir.IndexAddr: 4196 // these cannot be nil 4197 continue 4198 } 4199 if r, ok := maybeNil[ptr]; ok { 4200 report.Report(pass, instr, "possible nil pointer dereference", 4201 report.Related(r, "this check suggests that the pointer can be nil")) 4202 } 4203 } 4204 } 4205 } 4206 } 4207 4208 return nil, nil 4209 } 4210 4211 var checkAddressIsNilQ = pattern.MustParse( 4212 `(BinaryExpr 4213 (UnaryExpr "&" _) 4214 (Or "==" "!=") 4215 (Builtin "nil"))`) 4216 4217 func CheckAddressIsNil(pass *analysis.Pass) (interface{}, error) { 4218 fn := func(node ast.Node) { 4219 _, ok := code.Match(pass, checkAddressIsNilQ, node) 4220 if !ok { 4221 return 4222 } 4223 report.Report(pass, node, "the address of a variable cannot be nil") 4224 } 4225 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 4226 return nil, nil 4227 } 4228 4229 var ( 4230 checkFixedLengthTypeShiftQ = pattern.MustParse(` 4231 (Or 4232 (AssignStmt _ (Or ">>=" "<<=") _) 4233 (BinaryExpr _ (Or ">>" "<<") _)) 4234 `) 4235 ) 4236 4237 func CheckStaticBitShift(pass *analysis.Pass) (interface{}, error) { 4238 isDubiousShift := func(x, y ast.Expr) (int64, int64, bool) { 4239 typ, ok := pass.TypesInfo.TypeOf(x).Underlying().(*types.Basic) 4240 if !ok { 4241 return 0, 0, false 4242 } 4243 switch typ.Kind() { 4244 case types.Int8, types.Int16, types.Int32, types.Int64, 4245 types.Uint8, types.Uint16, types.Uint32, types.Uint64: 4246 // We're only interested in fixed–size types. 4247 default: 4248 return 0, 0, false 4249 } 4250 4251 const bitsInByte = 8 4252 typeBits := pass.TypesSizes.Sizeof(typ) * bitsInByte 4253 4254 shiftLength, ok := code.ExprToInt(pass, y) 4255 if !ok { 4256 return 0, 0, false 4257 } 4258 4259 return typeBits, shiftLength, shiftLength >= typeBits 4260 } 4261 4262 fn := func(node ast.Node) { 4263 if _, ok := code.Match(pass, checkFixedLengthTypeShiftQ, node); !ok { 4264 return 4265 } 4266 4267 switch e := node.(type) { 4268 case *ast.AssignStmt: 4269 if size, shift, yes := isDubiousShift(e.Lhs[0], e.Rhs[0]); yes { 4270 report.Report(pass, e, fmt.Sprintf("shifting %d-bit value by %d bits will always clear it", size, shift)) 4271 } 4272 case *ast.BinaryExpr: 4273 if size, shift, yes := isDubiousShift(e.X, e.Y); yes { 4274 report.Report(pass, e, fmt.Sprintf("shifting %d-bit value by %d bits will always clear it", size, shift)) 4275 } 4276 } 4277 } 4278 code.Preorder(pass, fn, (*ast.AssignStmt)(nil), (*ast.BinaryExpr)(nil)) 4279 4280 return nil, nil 4281 } 4282 4283 func findSliceLenChecks(pass *analysis.Pass) { 4284 // mark all function parameters that have to be of even length 4285 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 4286 for _, b := range fn.Blocks { 4287 // all paths go through this block 4288 if !b.Dominates(fn.Exit) { 4289 continue 4290 } 4291 4292 // if foo % 2 != 0 4293 ifi, ok := b.Control().(*ir.If) 4294 if !ok { 4295 continue 4296 } 4297 cmp, ok := ifi.Cond.(*ir.BinOp) 4298 if !ok { 4299 continue 4300 } 4301 var needle uint64 4302 switch cmp.Op { 4303 case token.NEQ: 4304 // look for != 0 4305 needle = 0 4306 case token.EQL: 4307 // look for == 1 4308 needle = 1 4309 default: 4310 continue 4311 } 4312 4313 rem, ok1 := cmp.X.(*ir.BinOp) 4314 k, ok2 := cmp.Y.(*ir.Const) 4315 if ok1 != ok2 { 4316 continue 4317 } 4318 if !ok1 { 4319 rem, ok1 = cmp.Y.(*ir.BinOp) 4320 k, ok2 = cmp.X.(*ir.Const) 4321 } 4322 if !ok1 || !ok2 || rem.Op != token.REM || k.Value.Kind() != constant.Int || k.Uint64() != needle { 4323 continue 4324 } 4325 k, ok = rem.Y.(*ir.Const) 4326 if !ok || k.Value.Kind() != constant.Int || k.Uint64() != 2 { 4327 continue 4328 } 4329 4330 // if len(foo) % 2 != 0 4331 call, ok := rem.X.(*ir.Call) 4332 if !ok || !irutil.IsCallTo(call.Common(), "len") { 4333 continue 4334 } 4335 4336 // we're checking the length of a parameter that is a slice 4337 // TODO(dh): support parameters that have flown through sigmas and phis 4338 param, ok := call.Call.Args[0].(*ir.Parameter) 4339 if !ok { 4340 continue 4341 } 4342 if !typeutil.All(param.Type(), typeutil.IsSlice) { 4343 continue 4344 } 4345 4346 // if len(foo) % 2 != 0 then panic 4347 if _, ok := b.Succs[0].Control().(*ir.Panic); !ok { 4348 continue 4349 } 4350 4351 pass.ExportObjectFact(param.Object(), new(evenElements)) 4352 } 4353 } 4354 } 4355 4356 func findIndirectSliceLenChecks(pass *analysis.Pass) { 4357 seen := map[*ir.Function]struct{}{} 4358 4359 var doFunction func(fn *ir.Function) 4360 doFunction = func(fn *ir.Function) { 4361 if _, ok := seen[fn]; ok { 4362 return 4363 } 4364 seen[fn] = struct{}{} 4365 4366 for _, b := range fn.Blocks { 4367 // all paths go through this block 4368 if !b.Dominates(fn.Exit) { 4369 continue 4370 } 4371 4372 for _, instr := range b.Instrs { 4373 call, ok := instr.(*ir.Call) 4374 if !ok { 4375 continue 4376 } 4377 callee := call.Call.StaticCallee() 4378 if callee == nil { 4379 continue 4380 } 4381 4382 if callee.Pkg == fn.Pkg || callee.Pkg == nil { 4383 doFunction(callee) 4384 } 4385 4386 for argi, arg := range call.Call.Args { 4387 if callee.Signature.Recv() != nil { 4388 if argi == 0 { 4389 continue 4390 } 4391 argi-- 4392 } 4393 4394 // TODO(dh): support parameters that have flown through length-preserving instructions 4395 param, ok := arg.(*ir.Parameter) 4396 if !ok { 4397 continue 4398 } 4399 if !typeutil.All(param.Type(), typeutil.IsSlice) { 4400 continue 4401 } 4402 4403 // We can't use callee.Params to look up the 4404 // parameter, because Params is not populated for 4405 // external functions. In our modular analysis. 4406 // any function in any package that isn't the 4407 // current package is considered "external", as it 4408 // has been loaded from export data only. 4409 sigParams := callee.Signature.Params() 4410 4411 if !pass.ImportObjectFact(sigParams.At(argi), new(evenElements)) { 4412 continue 4413 } 4414 pass.ExportObjectFact(param.Object(), new(evenElements)) 4415 } 4416 } 4417 } 4418 } 4419 4420 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 4421 doFunction(fn) 4422 } 4423 } 4424 4425 func findSliceLength(v ir.Value) int { 4426 // TODO(dh): VRP would help here 4427 4428 v = irutil.Flatten(v) 4429 val := func(v ir.Value) int { 4430 if v, ok := v.(*ir.Const); ok { 4431 return int(v.Int64()) 4432 } 4433 return -1 4434 } 4435 switch v := v.(type) { 4436 case *ir.Slice: 4437 low := 0 4438 high := -1 4439 if v.Low != nil { 4440 low = val(v.Low) 4441 } 4442 if v.High != nil { 4443 high = val(v.High) 4444 } else { 4445 switch vv := v.X.(type) { 4446 case *ir.Alloc: 4447 high = int(typeutil.Dereference(vv.Type()).Underlying().(*types.Array).Len()) 4448 case *ir.Slice: 4449 high = findSliceLength(vv) 4450 } 4451 } 4452 if low == -1 || high == -1 { 4453 return -1 4454 } 4455 return high - low 4456 default: 4457 return -1 4458 } 4459 } 4460 4461 type evenElements struct{} 4462 4463 func (evenElements) AFact() {} 4464 4465 func (evenElements) String() string { return "needs even elements" } 4466 4467 func flagSliceLens(pass *analysis.Pass) { 4468 var tag evenElements 4469 4470 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 4471 for _, b := range fn.Blocks { 4472 for _, instr := range b.Instrs { 4473 call, ok := instr.(ir.CallInstruction) 4474 if !ok { 4475 continue 4476 } 4477 callee := call.Common().StaticCallee() 4478 if callee == nil { 4479 continue 4480 } 4481 for argi, arg := range call.Common().Args { 4482 if callee.Signature.Recv() != nil { 4483 if argi == 0 { 4484 continue 4485 } 4486 argi-- 4487 } 4488 4489 _, ok := arg.Type().Underlying().(*types.Slice) 4490 if !ok { 4491 continue 4492 } 4493 param := callee.Signature.Params().At(argi) 4494 if !pass.ImportObjectFact(param, &tag) { 4495 continue 4496 } 4497 4498 // TODO handle stubs 4499 4500 // we know the argument has to have even length. 4501 // now let's try to find its length 4502 if n := findSliceLength(arg); n > -1 && n%2 != 0 { 4503 src := call.Source().(*ast.CallExpr).Args[argi] 4504 sig := call.Common().Signature() 4505 var label string 4506 if argi == sig.Params().Len()-1 && sig.Variadic() { 4507 label = "variadic argument" 4508 } else { 4509 label = "argument" 4510 } 4511 // Note that param.Name() is guaranteed to not 4512 // be empty, otherwise the function couldn't 4513 // have enforced its length. 4514 report.Report(pass, src, fmt.Sprintf("%s %q is expected to have even number of elements, but has %d elements", label, param.Name(), n)) 4515 } 4516 } 4517 } 4518 } 4519 } 4520 } 4521 4522 func CheckEvenSliceLength(pass *analysis.Pass) (interface{}, error) { 4523 findSliceLenChecks(pass) 4524 findIndirectSliceLenChecks(pass) 4525 flagSliceLens(pass) 4526 4527 return nil, nil 4528 } 4529 4530 func CheckTypedNilInterface(pass *analysis.Pass) (interface{}, error) { 4531 // The comparison 'fn() == nil' can never be true if fn() returns 4532 // an interface value and only returns typed nils. This is usually 4533 // a mistake in the function itself, but all we can say for 4534 // certain is that the comparison is pointless. 4535 // 4536 // Flag results if no untyped nils are being returned, but either 4537 // known typed nils, or typed unknown nilness are being returned. 4538 4539 irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR) 4540 typedness := pass.ResultOf[typedness.Analysis].(*typedness.Result) 4541 nilness := pass.ResultOf[nilness.Analysis].(*nilness.Result) 4542 for _, fn := range irpkg.SrcFuncs { 4543 for _, b := range fn.Blocks { 4544 for _, instr := range b.Instrs { 4545 binop, ok := instr.(*ir.BinOp) 4546 if !ok || !(binop.Op == token.EQL || binop.Op == token.NEQ) { 4547 continue 4548 } 4549 if _, ok := binop.X.Type().Underlying().(*types.Interface); !ok || typeparams.IsTypeParam(binop.X.Type()) { 4550 // TODO support swapped X and Y 4551 continue 4552 } 4553 4554 k, ok := binop.Y.(*ir.Const) 4555 if !ok || !k.IsNil() { 4556 // if binop.X is an interface, then binop.Y can 4557 // only be a Const if its untyped. A typed nil 4558 // constant would first be passed to 4559 // MakeInterface. 4560 continue 4561 } 4562 4563 var idx int 4564 var obj *types.Func 4565 switch x := irutil.Flatten(binop.X).(type) { 4566 case *ir.Call: 4567 callee := x.Call.StaticCallee() 4568 if callee == nil { 4569 continue 4570 } 4571 obj, _ = callee.Object().(*types.Func) 4572 idx = 0 4573 case *ir.Extract: 4574 call, ok := irutil.Flatten(x.Tuple).(*ir.Call) 4575 if !ok { 4576 continue 4577 } 4578 callee := call.Call.StaticCallee() 4579 if callee == nil { 4580 continue 4581 } 4582 obj, _ = callee.Object().(*types.Func) 4583 idx = x.Index 4584 case *ir.MakeInterface: 4585 var qualifier string 4586 switch binop.Op { 4587 case token.EQL: 4588 qualifier = "never" 4589 case token.NEQ: 4590 qualifier = "always" 4591 default: 4592 panic("unreachable") 4593 } 4594 4595 terms, err := typeparams.NormalTerms(x.X.Type()) 4596 if len(terms) == 0 || err != nil { 4597 // Type is a type parameter with no type terms (or we couldn't determine the terms). Such a type 4598 // _can_ be nil when put in an interface value. 4599 continue 4600 } 4601 4602 if report.HasRange(x.X) { 4603 report.Report(pass, binop, fmt.Sprintf("this comparison is %s true", qualifier), 4604 report.Related(x.X, "the lhs of the comparison gets its value from here and has a concrete type")) 4605 } else { 4606 // we can't generate related information for this, so make the diagnostic itself slightly more useful 4607 report.Report(pass, binop, fmt.Sprintf("this comparison is %s true; the lhs of the comparison has been assigned a concretely typed value", qualifier)) 4608 } 4609 continue 4610 } 4611 if obj == nil { 4612 continue 4613 } 4614 4615 isNil, onlyGlobal := nilness.MayReturnNil(obj, idx) 4616 if typedness.MustReturnTyped(obj, idx) && isNil && !onlyGlobal && !code.IsInTest(pass, binop) { 4617 // Don't flag these comparisons in tests. Tests 4618 // may be explicitly enforcing the invariant that 4619 // a value isn't nil. 4620 4621 var qualifier string 4622 switch binop.Op { 4623 case token.EQL: 4624 qualifier = "never" 4625 case token.NEQ: 4626 qualifier = "always" 4627 default: 4628 panic("unreachable") 4629 } 4630 report.Report(pass, binop, fmt.Sprintf("this comparison is %s true", qualifier), 4631 // TODO support swapped X and Y 4632 report.Related(binop.X, fmt.Sprintf("the lhs of the comparison is the %s return value of this function call", report.Ordinal(idx+1))), 4633 report.Related(obj, fmt.Sprintf("%s never returns a nil interface value", typeutil.FuncName(obj)))) 4634 } 4635 } 4636 } 4637 } 4638 4639 return nil, nil 4640 } 4641 4642 var builtinLessThanZeroQ = pattern.MustParse(` 4643 (Or 4644 (BinaryExpr 4645 (IntegerLiteral "0") 4646 ">" 4647 (CallExpr builtin@(Builtin (Or "len" "cap")) _)) 4648 (BinaryExpr 4649 (CallExpr builtin@(Builtin (Or "len" "cap")) _) 4650 "<" 4651 (IntegerLiteral "0"))) 4652 `) 4653 4654 func CheckBuiltinZeroComparison(pass *analysis.Pass) (interface{}, error) { 4655 fn := func(node ast.Node) { 4656 matcher, ok := code.Match(pass, builtinLessThanZeroQ, node) 4657 if !ok { 4658 return 4659 } 4660 4661 builtin := matcher.State["builtin"].(*ast.Ident) 4662 report.Report(pass, node, fmt.Sprintf("builtin function %s does not return negative values", builtin.Name)) 4663 } 4664 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 4665 4666 return nil, nil 4667 } 4668 4669 var integerDivisionQ = pattern.MustParse(`(BinaryExpr (IntegerLiteral _) "/" (IntegerLiteral _))`) 4670 4671 func CheckIntegerDivisionEqualsZero(pass *analysis.Pass) (interface{}, error) { 4672 fn := func(node ast.Node) { 4673 _, ok := code.Match(pass, integerDivisionQ, node) 4674 if !ok { 4675 return 4676 } 4677 4678 val := constant.ToInt(pass.TypesInfo.Types[node.(ast.Expr)].Value) 4679 if v, ok := constant.Uint64Val(val); ok && v == 0 { 4680 report.Report(pass, node, fmt.Sprintf("the integer division '%s' results in zero", report.Render(pass, node))) 4681 } 4682 4683 // TODO: we could offer a suggested fix here, but I am not 4684 // sure what it should be. There are many options to choose 4685 // from. 4686 4687 // Note: we experimented with flagging divisions that truncate 4688 // (e.g. 4 / 3), but it ran into false positives in Go's 4689 // 'time' package, which does this, deliberately: 4690 // 4691 // unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay 4692 // 4693 // The check also found a real bug in other code, but I don't 4694 // think we can outright ban this kind of division. 4695 } 4696 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 4697 4698 return nil, nil 4699 } 4700 4701 func CheckIneffectiveFieldAssignments(pass *analysis.Pass) (interface{}, error) { 4702 // The analysis only considers the receiver and its first level 4703 // fields. It doesn't look at other parameters, nor at nested 4704 // fields. 4705 // 4706 // The analysis does not detect all kinds of dead stores, only 4707 // those of fields that are never read after the write. That is, 4708 // we do not flag 'a.x = 1; a.x = 2; _ = a.x'. We might explore 4709 // this again if we add support for SROA to go/ir and implement 4710 // https://github.com/dominikh/go-tools/issues/191. 4711 4712 irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR) 4713 fnLoop: 4714 for _, fn := range irpkg.SrcFuncs { 4715 if recv := fn.Signature.Recv(); recv == nil { 4716 continue 4717 } else if _, ok := recv.Type().Underlying().(*types.Struct); !ok { 4718 continue 4719 } 4720 4721 recv := fn.Params[0] 4722 refs := irutil.FilterDebug(*recv.Referrers()) 4723 if len(refs) != 1 { 4724 continue 4725 } 4726 store, ok := refs[0].(*ir.Store) 4727 if !ok { 4728 continue 4729 } 4730 alloc, ok := store.Addr.(*ir.Alloc) 4731 if !ok || alloc.Heap { 4732 continue 4733 } 4734 4735 reads := map[int][]ir.Instruction{} 4736 writes := map[int][]ir.Instruction{} 4737 for _, ref := range *alloc.Referrers() { 4738 switch ref := ref.(type) { 4739 case *ir.FieldAddr: 4740 for _, refref := range *ref.Referrers() { 4741 switch refref.(type) { 4742 case *ir.Store: 4743 writes[ref.Field] = append(writes[ref.Field], refref) 4744 case *ir.Load: 4745 reads[ref.Field] = append(reads[ref.Field], refref) 4746 case *ir.DebugRef: 4747 continue 4748 default: 4749 // this should be safe… if the field address 4750 // escapes, then alloc.Heap will be true. 4751 // there should be no instructions left that, 4752 // given this FieldAddr, without escaping, can 4753 // effect a load or store. 4754 continue 4755 } 4756 } 4757 case *ir.Store: 4758 // we could treat this as a store to every field, but 4759 // we don't want to decide the semantics of partial 4760 // struct initializers. should `v = t{x: 1}` also mark 4761 // v.y as being written to? 4762 if ref != store { 4763 continue fnLoop 4764 } 4765 case *ir.Load: 4766 // a load of the entire struct loads every field 4767 for i := 0; i < recv.Type().Underlying().(*types.Struct).NumFields(); i++ { 4768 reads[i] = append(reads[i], ref) 4769 } 4770 case *ir.DebugRef: 4771 continue 4772 default: 4773 continue fnLoop 4774 } 4775 } 4776 4777 offset := func(instr ir.Instruction) int { 4778 for i, other := range instr.Block().Instrs { 4779 if instr == other { 4780 return i 4781 } 4782 } 4783 panic("couldn't find instruction in its block") 4784 } 4785 4786 for field, ws := range writes { 4787 rs := reads[field] 4788 wLoop: 4789 for _, w := range ws { 4790 for _, r := range rs { 4791 if w.Block() == r.Block() { 4792 if offset(r) > offset(w) { 4793 // found a reachable read of our write 4794 continue wLoop 4795 } 4796 } else if irutil.Reachable(w.Block(), r.Block()) { 4797 // found a reachable read of our write 4798 continue wLoop 4799 } 4800 } 4801 fieldName := recv.Type().Underlying().(*types.Struct).Field(field).Name() 4802 report.Report(pass, w, fmt.Sprintf("ineffective assignment to field %s.%s", recv.Type().(*types.Named).Obj().Name(), fieldName)) 4803 } 4804 } 4805 } 4806 return nil, nil 4807 } 4808 4809 var negativeZeroFloatQ = pattern.MustParse(` 4810 (Or 4811 (UnaryExpr 4812 "-" 4813 (BasicLit "FLOAT" "0.0")) 4814 4815 (UnaryExpr 4816 "-" 4817 (CallExpr conv@(Object (Or "float32" "float64")) lit@(Or (BasicLit "INT" "0") (BasicLit "FLOAT" "0.0")))) 4818 4819 (CallExpr 4820 conv@(Object (Or "float32" "float64")) 4821 (UnaryExpr "-" lit@(BasicLit "INT" "0"))))`) 4822 4823 func CheckNegativeZeroFloat(pass *analysis.Pass) (interface{}, error) { 4824 fn := func(node ast.Node) { 4825 m, ok := code.Match(pass, negativeZeroFloatQ, node) 4826 if !ok { 4827 return 4828 } 4829 4830 if conv, ok := m.State["conv"].(*types.TypeName); ok { 4831 var replacement string 4832 // TODO(dh): how does this handle type aliases? 4833 if conv.Name() == "float32" { 4834 replacement = `float32(math.Copysign(0, -1))` 4835 } else { 4836 replacement = `math.Copysign(0, -1)` 4837 } 4838 report.Report(pass, node, 4839 fmt.Sprintf("in Go, the floating-point expression '%s' is the same as '%s(%s)', it does not produce a negative zero", 4840 report.Render(pass, node), 4841 conv.Name(), 4842 report.Render(pass, m.State["lit"])), 4843 report.Fixes(edit.Fix("use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement)))) 4844 } else { 4845 const replacement = `math.Copysign(0, -1)` 4846 report.Report(pass, node, 4847 "in Go, the floating-point literal '-0.0' is the same as '0.0', it does not produce a negative zero", 4848 report.Fixes(edit.Fix("use math.Copysign to create negative zero", edit.ReplaceWithString(node, replacement)))) 4849 } 4850 } 4851 code.Preorder(pass, fn, (*ast.UnaryExpr)(nil), (*ast.CallExpr)(nil)) 4852 return nil, nil 4853 } 4854 4855 var ineffectiveURLQueryAddQ = pattern.MustParse(`(CallExpr (SelectorExpr (CallExpr (SelectorExpr recv (Ident "Query")) []) (Ident meth)) _)`) 4856 4857 func CheckIneffectiveURLQueryModification(pass *analysis.Pass) (interface{}, error) { 4858 // TODO(dh): We could make this check more complex and detect 4859 // pointless modifications of net/url.Values in general, but that 4860 // requires us to get the state machine correct, else we'll cause 4861 // false positives. 4862 4863 fn := func(node ast.Node) { 4864 m, ok := code.Match(pass, ineffectiveURLQueryAddQ, node) 4865 if !ok { 4866 return 4867 } 4868 if !code.IsOfType(pass, m.State["recv"].(ast.Expr), "*net/url.URL") { 4869 return 4870 } 4871 switch m.State["meth"].(string) { 4872 case "Add", "Del", "Set": 4873 default: 4874 return 4875 } 4876 report.Report(pass, node, "(*net/url.URL).Query returns a copy, modifying it doesn't change the URL") 4877 } 4878 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 4879 return nil, nil 4880 } 4881 4882 func CheckBadRemoveAll(pass *analysis.Pass) (interface{}, error) { 4883 for _, fn := range pass.ResultOf[buildir.Analyzer].(*buildir.IR).SrcFuncs { 4884 for _, b := range fn.Blocks { 4885 for _, instr := range b.Instrs { 4886 call, ok := instr.(ir.CallInstruction) 4887 if !ok { 4888 continue 4889 } 4890 if !irutil.IsCallTo(call.Common(), "os.RemoveAll") { 4891 continue 4892 } 4893 4894 kind := "" 4895 ex := "" 4896 callName := "" 4897 arg := irutil.Flatten(call.Common().Args[0]) 4898 switch arg := arg.(type) { 4899 case *ir.Call: 4900 callName = irutil.CallName(&arg.Call) 4901 if callName != "os.TempDir" { 4902 continue 4903 } 4904 kind = "temporary" 4905 ex = os.TempDir() 4906 case *ir.Extract: 4907 if arg.Index != 0 { 4908 continue 4909 } 4910 first, ok := arg.Tuple.(*ir.Call) 4911 if !ok { 4912 continue 4913 } 4914 callName = irutil.CallName(&first.Call) 4915 switch callName { 4916 case "os.UserCacheDir": 4917 kind = "cache" 4918 ex, _ = os.UserCacheDir() 4919 case "os.UserConfigDir": 4920 kind = "config" 4921 ex, _ = os.UserConfigDir() 4922 case "os.UserHomeDir": 4923 kind = "home" 4924 ex, _ = os.UserHomeDir() 4925 default: 4926 continue 4927 } 4928 default: 4929 continue 4930 } 4931 4932 if ex == "" { 4933 report.Report(pass, call, fmt.Sprintf("this call to os.RemoveAll deletes the user's entire %s directory, not a subdirectory therein", kind), 4934 report.Related(arg, fmt.Sprintf("this call to %s returns the user's %s directory", callName, kind))) 4935 } else { 4936 report.Report(pass, call, fmt.Sprintf("this call to os.RemoveAll deletes the user's entire %s directory, not a subdirectory therein", kind), 4937 report.Related(arg, fmt.Sprintf("this call to %s returns the user's %s directory, for example %s", callName, kind, ex))) 4938 } 4939 } 4940 } 4941 } 4942 return nil, nil 4943 } 4944 4945 var moduloOneQ = pattern.MustParse(`(BinaryExpr _ "%" (IntegerLiteral "1"))`) 4946 4947 func CheckModuloOne(pass *analysis.Pass) (interface{}, error) { 4948 fn := func(node ast.Node) { 4949 _, ok := code.Match(pass, moduloOneQ, node) 4950 if !ok { 4951 return 4952 } 4953 report.Report(pass, node, "x % 1 is always zero") 4954 } 4955 code.Preorder(pass, fn, (*ast.BinaryExpr)(nil)) 4956 return nil, nil 4957 } 4958 4959 var typeAssertionShadowingElseQ = pattern.MustParse(`(IfStmt (AssignStmt [obj@(Ident _) ok@(Ident _)] ":=" assert@(TypeAssertExpr obj _)) ok _ elseBranch)`) 4960 4961 func CheckTypeAssertionShadowingElse(pass *analysis.Pass) (interface{}, error) { 4962 // TODO(dh): without the IR-based verification, this check is able 4963 // to find more bugs, but also more prone to false positives. It 4964 // would be a good candidate for the 'codereview' category of 4965 // checks. 4966 4967 irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg 4968 fn := func(node ast.Node) { 4969 m, ok := code.Match(pass, typeAssertionShadowingElseQ, node) 4970 if !ok { 4971 return 4972 } 4973 shadow := pass.TypesInfo.ObjectOf(m.State["obj"].(*ast.Ident)) 4974 shadowed := m.State["assert"].(*ast.TypeAssertExpr).X 4975 4976 path, exact := astutil.PathEnclosingInterval(code.File(pass, shadow), shadow.Pos(), shadow.Pos()) 4977 if !exact { 4978 // TODO(dh): when can this happen? 4979 return 4980 } 4981 irfn := ir.EnclosingFunction(irpkg, path) 4982 if irfn == nil { 4983 // For example for functions named "_", because we don't generate IR for them. 4984 return 4985 } 4986 4987 shadoweeIR, isAddr := irfn.ValueForExpr(m.State["obj"].(*ast.Ident)) 4988 if shadoweeIR == nil || isAddr { 4989 // TODO(dh): is this possible? 4990 return 4991 } 4992 4993 var branch ast.Node 4994 switch br := m.State["elseBranch"].(type) { 4995 case ast.Node: 4996 branch = br 4997 case []ast.Stmt: 4998 branch = &ast.BlockStmt{List: br} 4999 case nil: 5000 return 5001 default: 5002 panic(fmt.Sprintf("unexpected type %T", br)) 5003 } 5004 5005 ast.Inspect(branch, func(node ast.Node) bool { 5006 ident, ok := node.(*ast.Ident) 5007 if !ok { 5008 return true 5009 } 5010 if pass.TypesInfo.ObjectOf(ident) != shadow { 5011 return true 5012 } 5013 5014 v, isAddr := irfn.ValueForExpr(ident) 5015 if v == nil || isAddr { 5016 return true 5017 } 5018 if irutil.Flatten(v) != shadoweeIR { 5019 // Same types.Object, but different IR value. This 5020 // either means that the variable has been 5021 // assigned to since the type assertion, or that 5022 // the variable has escaped to the heap. Either 5023 // way, we shouldn't flag reads of it. 5024 return true 5025 } 5026 5027 report.Report(pass, ident, 5028 fmt.Sprintf("%s refers to the result of a failed type assertion and is a zero value, not the value that was being type-asserted", report.Render(pass, ident)), 5029 report.Related(shadow, "this is the variable being read"), 5030 report.Related(shadowed, "this is the variable being shadowed")) 5031 return true 5032 }) 5033 } 5034 code.Preorder(pass, fn, (*ast.IfStmt)(nil)) 5035 return nil, nil 5036 } 5037 5038 var ineffectiveSortQ = pattern.MustParse(`(AssignStmt target@(Ident _) "=" (CallExpr typ@(Symbol (Or "sort.Float64Slice" "sort.IntSlice" "sort.StringSlice")) [target]))`) 5039 5040 func CheckIneffectiveSort(pass *analysis.Pass) (interface{}, error) { 5041 fn := func(node ast.Node) { 5042 m, ok := code.Match(pass, ineffectiveSortQ, node) 5043 if !ok { 5044 return 5045 } 5046 5047 _, ok = pass.TypesInfo.TypeOf(m.State["target"].(ast.Expr)).(*types.Slice) 5048 if !ok { 5049 // Avoid flagging 'x = sort.StringSlice(x)' where TypeOf(x) == sort.StringSlice 5050 return 5051 } 5052 5053 var alternative string 5054 typeName := types.TypeString(m.State["typ"].(*types.TypeName).Type(), nil) 5055 switch typeName { 5056 case "sort.Float64Slice": 5057 alternative = "Float64s" 5058 case "sort.IntSlice": 5059 alternative = "Ints" 5060 case "sort.StringSlice": 5061 alternative = "Strings" 5062 default: 5063 panic(fmt.Sprintf("unreachable: %q", typeName)) 5064 } 5065 5066 r := &ast.CallExpr{ 5067 Fun: &ast.SelectorExpr{ 5068 X: &ast.Ident{Name: "sort"}, 5069 Sel: &ast.Ident{Name: alternative}, 5070 }, 5071 Args: []ast.Expr{m.State["target"].(ast.Expr)}, 5072 } 5073 5074 report.Report(pass, node, 5075 fmt.Sprintf("%s is a type, not a function, and %s doesn't sort your values; consider using sort.%s instead", 5076 typeName, 5077 report.Render(pass, node.(*ast.AssignStmt).Rhs[0]), 5078 alternative), 5079 report.Fixes(edit.Fix(fmt.Sprintf("replace with call to sort.%s", alternative), edit.ReplaceWithNode(pass.Fset, node, r)))) 5080 } 5081 code.Preorder(pass, fn, (*ast.AssignStmt)(nil)) 5082 return nil, nil 5083 } 5084 5085 var ineffectiveRandIntQ = pattern.MustParse(` 5086 (CallExpr 5087 (Symbol 5088 name@(Or 5089 "math/rand.Int31n" 5090 "math/rand.Int63n" 5091 "math/rand.Intn" 5092 "(*math/rand.Rand).Int31n" 5093 "(*math/rand.Rand).Int63n" 5094 "(*math/rand.Rand).Intn")) 5095 [(IntegerLiteral "1")])`) 5096 5097 func CheckIneffectiveRandInt(pass *analysis.Pass) (interface{}, error) { 5098 fn := func(node ast.Node) { 5099 m, ok := code.Match(pass, ineffectiveRandIntQ, node) 5100 if !ok { 5101 return 5102 } 5103 5104 report.Report(pass, node, 5105 fmt.Sprintf("%s(n) generates a random value 0 <= x < n; that is, the generated values don't include n; %s therefore always returns 0", 5106 m.State["name"], report.Render(pass, node))) 5107 } 5108 5109 code.Preorder(pass, fn, (*ast.CallExpr)(nil)) 5110 return nil, nil 5111 } 5112 5113 var allocationNilCheckQ = pattern.MustParse(`(IfStmt _ cond@(BinaryExpr lhs op@(Or "==" "!=") (Builtin "nil")) _ _)`) 5114 5115 func CheckAllocationNilCheck(pass *analysis.Pass) (interface{}, error) { 5116 irpkg := pass.ResultOf[buildir.Analyzer].(*buildir.IR).Pkg 5117 5118 var path []ast.Node 5119 fn := func(node ast.Node, stack []ast.Node) { 5120 m, ok := code.Match(pass, allocationNilCheckQ, node) 5121 if !ok { 5122 return 5123 } 5124 cond := m.State["cond"].(ast.Node) 5125 if _, ok := code.Match(pass, checkAddressIsNilQ, cond); ok { 5126 // Don't duplicate diagnostics reported by SA4022 5127 return 5128 } 5129 lhs := m.State["lhs"].(ast.Expr) 5130 path = path[:0] 5131 for i := len(stack) - 1; i >= 0; i-- { 5132 path = append(path, stack[i]) 5133 } 5134 irfn := ir.EnclosingFunction(irpkg, path) 5135 if irfn == nil { 5136 // For example for functions named "_", because we don't generate IR for them. 5137 return 5138 } 5139 v, isAddr := irfn.ValueForExpr(lhs) 5140 if isAddr { 5141 return 5142 } 5143 5144 seen := map[ir.Value]struct{}{} 5145 var values []ir.Value 5146 var neverNil func(v ir.Value, track bool) bool 5147 neverNil = func(v ir.Value, track bool) bool { 5148 if _, ok := seen[v]; ok { 5149 return true 5150 } 5151 seen[v] = struct{}{} 5152 switch v := v.(type) { 5153 case *ir.MakeClosure, *ir.Function: 5154 if track { 5155 values = append(values, v) 5156 } 5157 return true 5158 case *ir.MakeChan, *ir.MakeMap, *ir.MakeSlice, *ir.Alloc: 5159 if track { 5160 values = append(values, v) 5161 } 5162 return true 5163 case *ir.Slice: 5164 if track { 5165 values = append(values, v) 5166 } 5167 return neverNil(v.X, false) 5168 case *ir.FieldAddr: 5169 if track { 5170 values = append(values, v) 5171 } 5172 return neverNil(v.X, false) 5173 case *ir.Sigma: 5174 return neverNil(v.X, true) 5175 case *ir.Phi: 5176 for _, e := range v.Edges { 5177 if !neverNil(e, true) { 5178 return false 5179 } 5180 } 5181 return true 5182 default: 5183 return false 5184 } 5185 } 5186 5187 if !neverNil(v, true) { 5188 return 5189 } 5190 5191 var qualifier string 5192 if op := m.State["op"].(token.Token); op == token.EQL { 5193 qualifier = "never" 5194 } else { 5195 qualifier = "always" 5196 } 5197 fallback := fmt.Sprintf("this nil check is %s true", qualifier) 5198 5199 sort.Slice(values, func(i, j int) bool { return values[i].Pos() < values[j].Pos() }) 5200 5201 if ident, ok := m.State["lhs"].(*ast.Ident); ok { 5202 if _, ok := pass.TypesInfo.ObjectOf(ident).(*types.Var); ok { 5203 var opts []report.Option 5204 if v.Parent() == irfn { 5205 if len(values) == 1 { 5206 opts = append(opts, report.Related(values[0], fmt.Sprintf("this is the value of %s", ident.Name))) 5207 } else { 5208 for _, vv := range values { 5209 opts = append(opts, report.Related(vv, fmt.Sprintf("this is one of the value of %s", ident.Name))) 5210 } 5211 } 5212 } 5213 5214 switch v.(type) { 5215 case *ir.MakeClosure, *ir.Function: 5216 report.Report(pass, cond, "the checked variable contains a function and is never nil; did you mean to call it?", opts...) 5217 default: 5218 report.Report(pass, cond, fallback, opts...) 5219 } 5220 } else { 5221 if _, ok := v.(*ir.Function); ok { 5222 report.Report(pass, cond, "functions are never nil; did you mean to call it?") 5223 } else { 5224 report.Report(pass, cond, fallback) 5225 } 5226 } 5227 } else { 5228 if _, ok := v.(*ir.Function); ok { 5229 report.Report(pass, cond, "functions are never nil; did you mean to call it?") 5230 } else { 5231 report.Report(pass, cond, fallback) 5232 } 5233 } 5234 } 5235 code.PreorderStack(pass, fn, (*ast.IfStmt)(nil)) 5236 return nil, nil 5237 }