PR tree-optimization/86274 - SEGFAULT when logging std::to_string(NAN)
[official-gcc.git] / libgo / go / cmd / vet / unsafeptr.go
blobcb2cc818897aa474df00d258f182387923a9e81f
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.
7 package main
9 import (
10 "go/ast"
11 "go/token"
12 "go/types"
15 func init() {
16 register("unsafeptr",
17 "check for misuse of unsafe.Pointer",
18 checkUnsafePointer,
19 callExpr)
22 func checkUnsafePointer(f *File, node ast.Node) {
23 x := node.(*ast.CallExpr)
24 if len(x.Args) != 1 {
25 return
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) {
39 case *ast.ParenExpr:
40 return f.isSafeUintptr(x.X)
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
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
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
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)
90 case *ast.BinaryExpr:
91 switch x.Op {
92 case token.ADD, token.SUB, token.AND_NOT:
93 return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
96 return false