1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Check for invalid uintptr -> unsafe.Pointer conversions.
17 "check for misuse of unsafe.Pointer",
22 func checkUnsafePointer(f
*File
, node ast
.Node
) {
23 x
:= node
.(*ast
.CallExpr
)
27 if f
.hasBasicType(x
.Fun
, types
.UnsafePointer
) && f
.hasBasicType(x
.Args
[0], types
.Uintptr
) && !f
.isSafeUintptr(x
.Args
[0]) {
28 f
.Badf(x
.Pos(), "possible misuse of unsafe.Pointer")
32 // isSafeUintptr reports whether x - already known to be a uintptr -
33 // is safe to convert to unsafe.Pointer. It is safe if x is itself derived
34 // directly from an unsafe.Pointer via conversion and pointer arithmetic
35 // or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr
36 // or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader.
37 func (f
*File
) isSafeUintptr(x ast
.Expr
) bool {
38 switch x
:= x
.(type) {
40 return f
.isSafeUintptr(x
.X
)
42 case *ast
.SelectorExpr
:
45 // reflect.SliceHeader and reflect.StringHeader are okay,
46 // but only if they are pointing at a real slice or string.
47 // It's not okay to do:
49 // x.Data = uintptr(unsafe.Pointer(...))
51 // p := unsafe.Pointer(x.Data)
52 // because in the middle the garbage collector doesn't
53 // see x.Data as a pointer and so x.Data may be dangling
54 // by the time we get to the conversion at the end.
55 // For now approximate by saying that *Header is okay
57 pt
, ok
:= f
.pkg
.types
[x
.X
].Type
.(*types
.Pointer
)
59 t
, ok
:= pt
.Elem().(*types
.Named
)
60 if ok
&& t
.Obj().Pkg().Path() == "reflect" {
61 switch t
.Obj().Name() {
62 case "StringHeader", "SliceHeader":
72 // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr.
73 sel
, ok
:= x
.Fun
.(*ast
.SelectorExpr
)
78 case "Pointer", "UnsafeAddr":
79 t
, ok
:= f
.pkg
.types
[sel
.X
].Type
.(*types
.Named
)
80 if ok
&& t
.Obj().Pkg().Path() == "reflect" && t
.Obj().Name() == "Value" {
86 // maybe conversion of uintptr to unsafe.Pointer
87 return f
.hasBasicType(x
.Fun
, types
.Uintptr
) && f
.hasBasicType(x
.Args
[0], types
.UnsafePointer
)
92 case token
.ADD
, token
.SUB
, token
.AND_NOT
:
93 return f
.isSafeUintptr(x
.X
) && !f
.isSafeUintptr(x
.Y
)