1// Copyright 2009 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// Cgo call and callback support. 6 7package runtime 8 9import ( 10 "runtime/internal/sys" 11 "unsafe" 12) 13 14// Functions called by cgo-generated code. 15//go:linkname cgoCheckPointer 16//go:linkname cgoCheckResult 17 18// Pointer checking for cgo code. 19 20// We want to detect all cases where a program that does not use 21// unsafe makes a cgo call passing a Go pointer to memory that 22// contains a Go pointer. Here a Go pointer is defined as a pointer 23// to memory allocated by the Go runtime. Programs that use unsafe 24// can evade this restriction easily, so we don't try to catch them. 25// The cgo program will rewrite all possibly bad pointer arguments to 26// call cgoCheckPointer, where we can catch cases of a Go pointer 27// pointing to a Go pointer. 28 29// Complicating matters, taking the address of a slice or array 30// element permits the C program to access all elements of the slice 31// or array. In that case we will see a pointer to a single element, 32// but we need to check the entire data structure. 33 34// The cgoCheckPointer call takes additional arguments indicating that 35// it was called on an address expression. An additional argument of 36// true means that it only needs to check a single element. An 37// additional argument of a slice or array means that it needs to 38// check the entire slice/array, but nothing else. Otherwise, the 39// pointer could be anything, and we check the entire heap object, 40// which is conservative but safe. 41 42// When and if we implement a moving garbage collector, 43// cgoCheckPointer will pin the pointer for the duration of the cgo 44// call. (This is necessary but not sufficient; the cgo program will 45// also have to change to pin Go pointers that cannot point to Go 46// pointers.) 47 48// cgoCheckPointer checks if the argument contains a Go pointer that 49// points to a Go pointer, and panics if it does. 50func cgoCheckPointer(ptr interface{}, arg interface{}) { 51 if debug.cgocheck == 0 { 52 return 53 } 54 55 ep := efaceOf(&ptr) 56 t := ep._type 57 58 top := true 59 if arg != nil && (t.kind&kindMask == kindPtr || t.kind&kindMask == kindUnsafePointer) { 60 p := ep.data 61 if t.kind&kindDirectIface == 0 { 62 p = *(*unsafe.Pointer)(p) 63 } 64 if p == nil || !cgoIsGoPointer(p) { 65 return 66 } 67 aep := efaceOf(&arg) 68 switch aep._type.kind & kindMask { 69 case kindBool: 70 if t.kind&kindMask == kindUnsafePointer { 71 // We don't know the type of the element. 72 break 73 } 74 pt := (*ptrtype)(unsafe.Pointer(t)) 75 cgoCheckArg(pt.elem, p, true, false, cgoCheckPointerFail) 76 return 77 case kindSlice: 78 // Check the slice rather than the pointer. 79 ep = aep 80 t = ep._type 81 case kindArray: 82 // Check the array rather than the pointer. 83 // Pass top as false since we have a pointer 84 // to the array. 85 ep = aep 86 t = ep._type 87 top = false 88 default: 89 throw("can't happen") 90 } 91 } 92 93 cgoCheckArg(t, ep.data, t.kind&kindDirectIface == 0, top, cgoCheckPointerFail) 94} 95 96const cgoCheckPointerFail = "cgo argument has Go pointer to Go pointer" 97const cgoResultFail = "cgo result has Go pointer" 98 99// cgoCheckArg is the real work of cgoCheckPointer. The argument p 100// is either a pointer to the value (of type t), or the value itself, 101// depending on indir. The top parameter is whether we are at the top 102// level, where Go pointers are allowed. 103func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { 104 if t.ptrdata == 0 || p == nil { 105 // If the type has no pointers there is nothing to do. 106 return 107 } 108 109 switch t.kind & kindMask { 110 default: 111 throw("can't happen") 112 case kindArray: 113 at := (*arraytype)(unsafe.Pointer(t)) 114 if !indir { 115 if at.len != 1 { 116 throw("can't happen") 117 } 118 cgoCheckArg(at.elem, p, at.elem.kind&kindDirectIface == 0, top, msg) 119 return 120 } 121 for i := uintptr(0); i < at.len; i++ { 122 cgoCheckArg(at.elem, p, true, top, msg) 123 p = add(p, at.elem.size) 124 } 125 case kindChan, kindMap: 126 // These types contain internal pointers that will 127 // always be allocated in the Go heap. It's never OK 128 // to pass them to C. 129 panic(errorString(msg)) 130 case kindFunc: 131 if indir { 132 p = *(*unsafe.Pointer)(p) 133 } 134 if !cgoIsGoPointer(p) { 135 return 136 } 137 panic(errorString(msg)) 138 case kindInterface: 139 it := *(**_type)(p) 140 if it == nil { 141 return 142 } 143 // A type known at compile time is OK since it's 144 // constant. A type not known at compile time will be 145 // in the heap and will not be OK. 146 if inheap(uintptr(unsafe.Pointer(it))) { 147 panic(errorString(msg)) 148 } 149 p = *(*unsafe.Pointer)(add(p, sys.PtrSize)) 150 if !cgoIsGoPointer(p) { 151 return 152 } 153 if !top { 154 panic(errorString(msg)) 155 } 156 cgoCheckArg(it, p, it.kind&kindDirectIface == 0, false, msg) 157 case kindSlice: 158 st := (*slicetype)(unsafe.Pointer(t)) 159 s := (*slice)(p) 160 p = s.array 161 if p == nil || !cgoIsGoPointer(p) { 162 return 163 } 164 if !top { 165 panic(errorString(msg)) 166 } 167 if st.elem.ptrdata == 0 { 168 return 169 } 170 for i := 0; i < s.cap; i++ { 171 cgoCheckArg(st.elem, p, true, false, msg) 172 p = add(p, st.elem.size) 173 } 174 case kindString: 175 ss := (*stringStruct)(p) 176 if !cgoIsGoPointer(ss.str) { 177 return 178 } 179 if !top { 180 panic(errorString(msg)) 181 } 182 case kindStruct: 183 st := (*structtype)(unsafe.Pointer(t)) 184 if !indir { 185 if len(st.fields) != 1 { 186 throw("can't happen") 187 } 188 cgoCheckArg(st.fields[0].typ, p, st.fields[0].typ.kind&kindDirectIface == 0, top, msg) 189 return 190 } 191 for _, f := range st.fields { 192 if f.typ.ptrdata == 0 { 193 continue 194 } 195 cgoCheckArg(f.typ, add(p, f.offset()), true, top, msg) 196 } 197 case kindPtr, kindUnsafePointer: 198 if indir { 199 p = *(*unsafe.Pointer)(p) 200 if p == nil { 201 return 202 } 203 } 204 205 if !cgoIsGoPointer(p) { 206 return 207 } 208 if !top { 209 panic(errorString(msg)) 210 } 211 212 cgoCheckUnknownPointer(p, msg) 213 } 214} 215 216// cgoCheckUnknownPointer is called for an arbitrary pointer into Go 217// memory. It checks whether that Go memory contains any other 218// pointer into Go memory. If it does, we panic. 219// The return values are unused but useful to see in panic tracebacks. 220func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) { 221 if inheap(uintptr(p)) { 222 b, span, _ := findObject(uintptr(p), 0, 0, false) 223 base = b 224 if base == 0 { 225 return 226 } 227 hbits := heapBitsForAddr(base) 228 n := span.elemsize 229 for i = uintptr(0); i < n; i += sys.PtrSize { 230 if i != 1*sys.PtrSize && !hbits.morePointers() { 231 // No more possible pointers. 232 break 233 } 234 if hbits.isPointer() && cgoIsGoPointer(*(*unsafe.Pointer)(unsafe.Pointer(base + i))) { 235 panic(errorString(msg)) 236 } 237 hbits = hbits.next() 238 } 239 240 return 241 } 242 243 lo := 0 244 hi := len(gcRootsIndex) 245 for lo < hi { 246 m := lo + (hi-lo)/2 247 pr := gcRootsIndex[m] 248 addr := uintptr(pr.decl) 249 if cgoInRange(p, addr, addr+pr.size) { 250 cgoCheckBits(pr.decl, pr.gcdata, 0, pr.ptrdata) 251 return 252 } 253 if uintptr(p) < addr { 254 hi = m 255 } else { 256 lo = m + 1 257 } 258 } 259 260 return 261} 262 263// cgoIsGoPointer reports whether the pointer is a Go pointer--a 264// pointer to Go memory. We only care about Go memory that might 265// contain pointers. 266//go:nosplit 267//go:nowritebarrierrec 268func cgoIsGoPointer(p unsafe.Pointer) bool { 269 if p == nil { 270 return false 271 } 272 273 if inHeapOrStack(uintptr(p)) { 274 return true 275 } 276 277 roots := gcRoots 278 for roots != nil { 279 for i := 0; i < roots.count; i++ { 280 pr := roots.roots[i] 281 addr := uintptr(pr.decl) 282 if cgoInRange(p, addr, addr+pr.size) { 283 return true 284 } 285 } 286 roots = roots.next 287 } 288 289 return false 290} 291 292// cgoInRange reports whether p is between start and end. 293//go:nosplit 294//go:nowritebarrierrec 295func cgoInRange(p unsafe.Pointer, start, end uintptr) bool { 296 return start <= uintptr(p) && uintptr(p) < end 297} 298 299// cgoCheckResult is called to check the result parameter of an 300// exported Go function. It panics if the result is or contains a Go 301// pointer. 302func cgoCheckResult(val interface{}) { 303 if debug.cgocheck == 0 { 304 return 305 } 306 307 ep := efaceOf(&val) 308 t := ep._type 309 cgoCheckArg(t, ep.data, t.kind&kindDirectIface == 0, false, cgoResultFail) 310} 311