summaryrefslogtreecommitdiffstats
path: root/llgo/third_party/go.tools/cmd/vet/unsafeptr.go
diff options
context:
space:
mode:
Diffstat (limited to 'llgo/third_party/go.tools/cmd/vet/unsafeptr.go')
-rw-r--r--llgo/third_party/go.tools/cmd/vet/unsafeptr.go98
1 files changed, 98 insertions, 0 deletions
diff --git a/llgo/third_party/go.tools/cmd/vet/unsafeptr.go b/llgo/third_party/go.tools/cmd/vet/unsafeptr.go
new file mode 100644
index 00000000000..3e133fe0cfc
--- /dev/null
+++ b/llgo/third_party/go.tools/cmd/vet/unsafeptr.go
@@ -0,0 +1,98 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check for invalid uintptr -> unsafe.Pointer conversions.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+
+ "llvm.org/llgo/third_party/go.tools/go/types"
+)
+
+func init() {
+ register("unsafeptr",
+ "check for misuse of unsafe.Pointer",
+ checkUnsafePointer,
+ callExpr)
+}
+
+func checkUnsafePointer(f *File, node ast.Node) {
+ x := node.(*ast.CallExpr)
+ if len(x.Args) != 1 {
+ return
+ }
+ if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) {
+ f.Badf(x.Pos(), "possible misuse of unsafe.Pointer")
+ }
+}
+
+// isSafeUintptr reports whether x - already known to be a uintptr -
+// is safe to convert to unsafe.Pointer. It is safe if x is itself derived
+// directly from an unsafe.Pointer via conversion and pointer arithmetic
+// or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr
+// or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader.
+func (f *File) isSafeUintptr(x ast.Expr) bool {
+ switch x := x.(type) {
+ case *ast.ParenExpr:
+ return f.isSafeUintptr(x.X)
+
+ case *ast.SelectorExpr:
+ switch x.Sel.Name {
+ case "Data":
+ // reflect.SliceHeader and reflect.StringHeader are okay,
+ // but only if they are pointing at a real slice or string.
+ // It's not okay to do:
+ // var x SliceHeader
+ // x.Data = uintptr(unsafe.Pointer(...))
+ // ... use x ...
+ // p := unsafe.Pointer(x.Data)
+ // because in the middle the garbage collector doesn't
+ // see x.Data as a pointer and so x.Data may be dangling
+ // by the time we get to the conversion at the end.
+ // For now approximate by saying that *Header is okay
+ // but Header is not.
+ pt, ok := f.pkg.types[x.X].Type.(*types.Pointer)
+ if ok {
+ t, ok := pt.Elem().(*types.Named)
+ if ok && t.Obj().Pkg().Path() == "reflect" {
+ switch t.Obj().Name() {
+ case "StringHeader", "SliceHeader":
+ return true
+ }
+ }
+ }
+ }
+
+ case *ast.CallExpr:
+ switch len(x.Args) {
+ case 0:
+ // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr.
+ sel, ok := x.Fun.(*ast.SelectorExpr)
+ if !ok {
+ break
+ }
+ switch sel.Sel.Name {
+ case "Pointer", "UnsafeAddr":
+ t, ok := f.pkg.types[sel.X].Type.(*types.Named)
+ if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
+ return true
+ }
+ }
+
+ case 1:
+ // maybe conversion of uintptr to unsafe.Pointer
+ return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer)
+ }
+
+ case *ast.BinaryExpr:
+ switch x.Op {
+ case token.ADD, token.SUB:
+ return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
+ }
+ }
+ return false
+}
OpenPOWER on IntegriCloud