github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/staticcheck/sa1017/sa1017.go (about) 1 package sa1017 2 3 import ( 4 "go/constant" 5 6 "github.com/amarpal/go-tools/analysis/callcheck" 7 "github.com/amarpal/go-tools/analysis/lint" 8 "github.com/amarpal/go-tools/go/ir" 9 "github.com/amarpal/go-tools/internal/passes/buildir" 10 "github.com/amarpal/go-tools/knowledge" 11 12 "golang.org/x/tools/go/analysis" 13 ) 14 15 var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{ 16 Analyzer: &analysis.Analyzer{ 17 Name: "SA1017", 18 Requires: []*analysis.Analyzer{buildir.Analyzer}, 19 Run: callcheck.Analyzer(rules), 20 }, 21 Doc: &lint.Documentation{ 22 Title: `Channels used with \'os/signal.Notify\' should be buffered`, 23 Text: `The \'os/signal\' package uses non-blocking channel sends when delivering 24 signals. If the receiving end of the channel isn't ready and the 25 channel is either unbuffered or full, the signal will be dropped. To 26 avoid missing signals, the channel should be buffered and of the 27 appropriate size. For a channel used for notification of just one 28 signal value, a buffer of size 1 is sufficient.`, 29 Since: "2017.1", 30 Severity: lint.SeverityWarning, 31 MergeIf: lint.MergeIfAny, 32 }, 33 }) 34 35 var Analyzer = SCAnalyzer.Analyzer 36 37 var rules = map[string]callcheck.Check{ 38 "os/signal.Notify": func(call *callcheck.Call) { 39 arg := call.Args[knowledge.Arg("os/signal.Notify.c")] 40 if isUnbufferedChannel(arg.Value) { 41 arg.Invalid("the channel used with signal.Notify should be buffered") 42 } 43 }, 44 } 45 46 func isUnbufferedChannel(v callcheck.Value) bool { 47 // TODO(dh): this check of course misses many cases of unbuffered 48 // channels, such as any in phi or sigma nodes. We'll eventually 49 // replace this function. 50 val := v.Value 51 if ct, ok := val.(*ir.ChangeType); ok { 52 val = ct.X 53 } 54 mk, ok := val.(*ir.MakeChan) 55 if !ok { 56 return false 57 } 58 if k, ok := mk.Size.(*ir.Const); ok && k.Value.Kind() == constant.Int { 59 if v, ok := constant.Int64Val(k.Value); ok && v == 0 { 60 return true 61 } 62 } 63 return false 64 }