...
Source file src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
1
2
3
4
5
6
7 package unsafeptr
8
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
13
14 "golang.org/x/tools/go/analysis"
15 "golang.org/x/tools/go/analysis/passes/inspect"
16 "golang.org/x/tools/go/ast/inspector"
17 )
18
19 const Doc = `check for invalid conversions of uintptr to unsafe.Pointer
20
21 The unsafeptr analyzer reports likely incorrect uses of unsafe.Pointer
22 to convert integers to pointers. A conversion from uintptr to
23 unsafe.Pointer is invalid if it implies that there is a uintptr-typed
24 word in memory that holds a pointer value, because that word will be
25 invisible to stack copying and to the garbage collector.`
26
27 var Analyzer = &analysis.Analyzer{
28 Name: "unsafeptr",
29 Doc: Doc,
30 Requires: []*analysis.Analyzer{inspect.Analyzer},
31 Run: run,
32 }
33
34 func run(pass *analysis.Pass) (interface{}, error) {
35 inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
36
37 nodeFilter := []ast.Node{
38 (*ast.CallExpr)(nil),
39 }
40 inspect.Preorder(nodeFilter, func(n ast.Node) {
41 x := n.(*ast.CallExpr)
42 if len(x.Args) != 1 {
43 return
44 }
45 if hasBasicType(pass.TypesInfo, x.Fun, types.UnsafePointer) &&
46 hasBasicType(pass.TypesInfo, x.Args[0], types.Uintptr) &&
47 !isSafeUintptr(pass.TypesInfo, x.Args[0]) {
48 pass.Reportf(x.Pos(), "possible misuse of unsafe.Pointer")
49 }
50 })
51 return nil, nil
52 }
53
54
55
56
57
58
59 func isSafeUintptr(info *types.Info, x ast.Expr) bool {
60 switch x := x.(type) {
61 case *ast.ParenExpr:
62 return isSafeUintptr(info, x.X)
63
64 case *ast.SelectorExpr:
65 if x.Sel.Name != "Data" {
66 break
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80 pt, ok := info.Types[x.X].Type.(*types.Pointer)
81 if ok {
82 t, ok := pt.Elem().(*types.Named)
83 if ok && t.Obj().Pkg().Path() == "reflect" {
84 switch t.Obj().Name() {
85 case "StringHeader", "SliceHeader":
86 return true
87 }
88 }
89 }
90
91 case *ast.CallExpr:
92 switch len(x.Args) {
93 case 0:
94
95 sel, ok := x.Fun.(*ast.SelectorExpr)
96 if !ok {
97 break
98 }
99 switch sel.Sel.Name {
100 case "Pointer", "UnsafeAddr":
101 t, ok := info.Types[sel.X].Type.(*types.Named)
102 if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
103 return true
104 }
105 }
106
107 case 1:
108
109 return hasBasicType(info, x.Fun, types.Uintptr) &&
110 hasBasicType(info, x.Args[0], types.UnsafePointer)
111 }
112
113 case *ast.BinaryExpr:
114 switch x.Op {
115 case token.ADD, token.SUB, token.AND_NOT:
116 return isSafeUintptr(info, x.X) && !isSafeUintptr(info, x.Y)
117 }
118 }
119 return false
120 }
121
122
123 func hasBasicType(info *types.Info, x ast.Expr, kind types.BasicKind) bool {
124 t := info.Types[x].Type
125 if t != nil {
126 t = t.Underlying()
127 }
128 b, ok := t.(*types.Basic)
129 return ok && b.Kind() == kind
130 }
131
View as plain text