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. 4 5 // Check for invalid uintptr -> unsafe.Pointer conversions. 6 7 package main 8 9 import ( 10 "go/ast" 11 "go/token" 12 "go/types" 13 ) 14 15 func init() { 16 register("unsafeptr", 17 "check for misuse of unsafe.Pointer", 18 checkUnsafePointer, 19 callExpr) 20 } 21 22 func checkUnsafePointer(f *File, node ast.Node) { 23 x := node.(*ast.CallExpr) 24 if len(x.Args) != 1 { 25 return 26 } 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") 29 } 30 } 31 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) { 39 case *ast.ParenExpr: 40 return f.isSafeUintptr(x.X) 41 42 case *ast.SelectorExpr: 43 switch x.Sel.Name { 44 case "Data": 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: 48 // var x SliceHeader 49 // x.Data = uintptr(unsafe.Pointer(...)) 50 // ... use x ... 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 56 // but Header is not. 57 pt, ok := f.pkg.types[x.X].Type.(*types.Pointer) 58 if ok { 59 t, ok := pt.Elem().(*types.Named) 60 if ok && t.Obj().Pkg().Path() == "reflect" { 61 switch t.Obj().Name() { 62 case "StringHeader", "SliceHeader": 63 return true 64 } 65 } 66 } 67 } 68 69 case *ast.CallExpr: 70 switch len(x.Args) { 71 case 0: 72 // maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr. 73 sel, ok := x.Fun.(*ast.SelectorExpr) 74 if !ok { 75 break 76 } 77 switch sel.Sel.Name { 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" { 81 return true 82 } 83 } 84 85 case 1: 86 // maybe conversion of uintptr to unsafe.Pointer 87 return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer) 88 } 89 90 case *ast.BinaryExpr: 91 switch x.Op { 92 case token.ADD, token.SUB: 93 return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y) 94 } 95 } 96 return false 97 } 98