rules.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. package staticcheck
  2. import (
  3. "fmt"
  4. "go/constant"
  5. "go/types"
  6. "net"
  7. "net/url"
  8. "regexp"
  9. "sort"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "unicode/utf8"
  14. "golang.org/x/tools/go/analysis"
  15. . "honnef.co/go/tools/lint/lintdsl"
  16. "honnef.co/go/tools/ssa"
  17. "honnef.co/go/tools/staticcheck/vrp"
  18. )
  19. const (
  20. MsgInvalidHostPort = "invalid port or service name in host:port pair"
  21. MsgInvalidUTF8 = "argument is not a valid UTF-8 encoded string"
  22. MsgNonUniqueCutset = "cutset contains duplicate characters"
  23. )
  24. type Call struct {
  25. Pass *analysis.Pass
  26. Instr ssa.CallInstruction
  27. Args []*Argument
  28. Parent *ssa.Function
  29. invalids []string
  30. }
  31. func (c *Call) Invalid(msg string) {
  32. c.invalids = append(c.invalids, msg)
  33. }
  34. type Argument struct {
  35. Value Value
  36. invalids []string
  37. }
  38. func (arg *Argument) Invalid(msg string) {
  39. arg.invalids = append(arg.invalids, msg)
  40. }
  41. type Value struct {
  42. Value ssa.Value
  43. Range vrp.Range
  44. }
  45. type CallCheck func(call *Call)
  46. func extractConsts(v ssa.Value) []*ssa.Const {
  47. switch v := v.(type) {
  48. case *ssa.Const:
  49. return []*ssa.Const{v}
  50. case *ssa.MakeInterface:
  51. return extractConsts(v.X)
  52. default:
  53. return nil
  54. }
  55. }
  56. func ValidateRegexp(v Value) error {
  57. for _, c := range extractConsts(v.Value) {
  58. if c.Value == nil {
  59. continue
  60. }
  61. if c.Value.Kind() != constant.String {
  62. continue
  63. }
  64. s := constant.StringVal(c.Value)
  65. if _, err := regexp.Compile(s); err != nil {
  66. return err
  67. }
  68. }
  69. return nil
  70. }
  71. func ValidateTimeLayout(v Value) error {
  72. for _, c := range extractConsts(v.Value) {
  73. if c.Value == nil {
  74. continue
  75. }
  76. if c.Value.Kind() != constant.String {
  77. continue
  78. }
  79. s := constant.StringVal(c.Value)
  80. s = strings.Replace(s, "_", " ", -1)
  81. s = strings.Replace(s, "Z", "-", -1)
  82. _, err := time.Parse(s, s)
  83. if err != nil {
  84. return err
  85. }
  86. }
  87. return nil
  88. }
  89. func ValidateURL(v Value) error {
  90. for _, c := range extractConsts(v.Value) {
  91. if c.Value == nil {
  92. continue
  93. }
  94. if c.Value.Kind() != constant.String {
  95. continue
  96. }
  97. s := constant.StringVal(c.Value)
  98. _, err := url.Parse(s)
  99. if err != nil {
  100. return fmt.Errorf("%q is not a valid URL: %s", s, err)
  101. }
  102. }
  103. return nil
  104. }
  105. func IntValue(v Value, z vrp.Z) bool {
  106. r, ok := v.Range.(vrp.IntInterval)
  107. if !ok || !r.IsKnown() {
  108. return false
  109. }
  110. if r.Lower != r.Upper {
  111. return false
  112. }
  113. if r.Lower.Cmp(z) == 0 {
  114. return true
  115. }
  116. return false
  117. }
  118. func InvalidUTF8(v Value) bool {
  119. for _, c := range extractConsts(v.Value) {
  120. if c.Value == nil {
  121. continue
  122. }
  123. if c.Value.Kind() != constant.String {
  124. continue
  125. }
  126. s := constant.StringVal(c.Value)
  127. if !utf8.ValidString(s) {
  128. return true
  129. }
  130. }
  131. return false
  132. }
  133. func UnbufferedChannel(v Value) bool {
  134. r, ok := v.Range.(vrp.ChannelInterval)
  135. if !ok || !r.IsKnown() {
  136. return false
  137. }
  138. if r.Size.Lower.Cmp(vrp.NewZ(0)) == 0 &&
  139. r.Size.Upper.Cmp(vrp.NewZ(0)) == 0 {
  140. return true
  141. }
  142. return false
  143. }
  144. func Pointer(v Value) bool {
  145. switch v.Value.Type().Underlying().(type) {
  146. case *types.Pointer, *types.Interface:
  147. return true
  148. }
  149. return false
  150. }
  151. func ConvertedFromInt(v Value) bool {
  152. conv, ok := v.Value.(*ssa.Convert)
  153. if !ok {
  154. return false
  155. }
  156. b, ok := conv.X.Type().Underlying().(*types.Basic)
  157. if !ok {
  158. return false
  159. }
  160. if (b.Info() & types.IsInteger) == 0 {
  161. return false
  162. }
  163. return true
  164. }
  165. func validEncodingBinaryType(pass *analysis.Pass, typ types.Type) bool {
  166. typ = typ.Underlying()
  167. switch typ := typ.(type) {
  168. case *types.Basic:
  169. switch typ.Kind() {
  170. case types.Uint8, types.Uint16, types.Uint32, types.Uint64,
  171. types.Int8, types.Int16, types.Int32, types.Int64,
  172. types.Float32, types.Float64, types.Complex64, types.Complex128, types.Invalid:
  173. return true
  174. case types.Bool:
  175. return IsGoVersion(pass, 8)
  176. }
  177. return false
  178. case *types.Struct:
  179. n := typ.NumFields()
  180. for i := 0; i < n; i++ {
  181. if !validEncodingBinaryType(pass, typ.Field(i).Type()) {
  182. return false
  183. }
  184. }
  185. return true
  186. case *types.Array:
  187. return validEncodingBinaryType(pass, typ.Elem())
  188. case *types.Interface:
  189. // we can't determine if it's a valid type or not
  190. return true
  191. }
  192. return false
  193. }
  194. func CanBinaryMarshal(pass *analysis.Pass, v Value) bool {
  195. typ := v.Value.Type().Underlying()
  196. if ttyp, ok := typ.(*types.Pointer); ok {
  197. typ = ttyp.Elem().Underlying()
  198. }
  199. if ttyp, ok := typ.(interface {
  200. Elem() types.Type
  201. }); ok {
  202. if _, ok := ttyp.(*types.Pointer); !ok {
  203. typ = ttyp.Elem()
  204. }
  205. }
  206. return validEncodingBinaryType(pass, typ)
  207. }
  208. func RepeatZeroTimes(name string, arg int) CallCheck {
  209. return func(call *Call) {
  210. arg := call.Args[arg]
  211. if IntValue(arg.Value, vrp.NewZ(0)) {
  212. arg.Invalid(fmt.Sprintf("calling %s with n == 0 will return no results, did you mean -1?", name))
  213. }
  214. }
  215. }
  216. func validateServiceName(s string) bool {
  217. if len(s) < 1 || len(s) > 15 {
  218. return false
  219. }
  220. if s[0] == '-' || s[len(s)-1] == '-' {
  221. return false
  222. }
  223. if strings.Contains(s, "--") {
  224. return false
  225. }
  226. hasLetter := false
  227. for _, r := range s {
  228. if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
  229. hasLetter = true
  230. continue
  231. }
  232. if r >= '0' && r <= '9' {
  233. continue
  234. }
  235. return false
  236. }
  237. return hasLetter
  238. }
  239. func validatePort(s string) bool {
  240. n, err := strconv.ParseInt(s, 10, 64)
  241. if err != nil {
  242. return validateServiceName(s)
  243. }
  244. return n >= 0 && n <= 65535
  245. }
  246. func ValidHostPort(v Value) bool {
  247. for _, k := range extractConsts(v.Value) {
  248. if k.Value == nil {
  249. continue
  250. }
  251. if k.Value.Kind() != constant.String {
  252. continue
  253. }
  254. s := constant.StringVal(k.Value)
  255. _, port, err := net.SplitHostPort(s)
  256. if err != nil {
  257. return false
  258. }
  259. // TODO(dh): check hostname
  260. if !validatePort(port) {
  261. return false
  262. }
  263. }
  264. return true
  265. }
  266. // ConvertedFrom reports whether value v was converted from type typ.
  267. func ConvertedFrom(v Value, typ string) bool {
  268. change, ok := v.Value.(*ssa.ChangeType)
  269. return ok && IsType(change.X.Type(), typ)
  270. }
  271. func UniqueStringCutset(v Value) bool {
  272. for _, c := range extractConsts(v.Value) {
  273. if c.Value == nil {
  274. continue
  275. }
  276. if c.Value.Kind() != constant.String {
  277. continue
  278. }
  279. s := constant.StringVal(c.Value)
  280. rs := runeSlice(s)
  281. if len(rs) < 2 {
  282. continue
  283. }
  284. sort.Sort(rs)
  285. for i, r := range rs[1:] {
  286. if rs[i] == r {
  287. return false
  288. }
  289. }
  290. }
  291. return true
  292. }