mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/cgo, runtime: exported Go functions can't return a Go pointer
Update #12416. Change-Id: Iccbcb12709d1ca9bea87274f44f93cfcebadb070 Reviewed-on: https://go-review.googlesource.com/17048 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
0fbf0955d4
commit
0e2c635788
6 changed files with 135 additions and 63 deletions
|
|
@ -209,6 +209,24 @@ var ptrTests = []ptrTest{
|
||||||
fail: true,
|
fail: true,
|
||||||
expensive: true,
|
expensive: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Exported functions may not return Go pointers.
|
||||||
|
name: "export1",
|
||||||
|
c: `extern unsigned char *GoFn();`,
|
||||||
|
support: `//export GoFn
|
||||||
|
func GoFn() *byte { return new(byte) }`,
|
||||||
|
body: `C.GoFn()`,
|
||||||
|
fail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Returning a C pointer is fine.
|
||||||
|
name: "exportok",
|
||||||
|
c: `#include <stdlib.h>
|
||||||
|
extern unsigned char *GoFn();`,
|
||||||
|
support: `//export GoFn
|
||||||
|
func GoFn() *byte { return (*byte)(C.malloc(1)) }`,
|
||||||
|
body: `C.GoFn()`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,6 @@ func testCallbackCallers(t *testing.T) {
|
||||||
pc := make([]uintptr, 100)
|
pc := make([]uintptr, 100)
|
||||||
n := 0
|
n := 0
|
||||||
name := []string{
|
name := []string{
|
||||||
"test.goCallback",
|
|
||||||
"runtime.call16",
|
"runtime.call16",
|
||||||
"runtime.cgocallbackg1",
|
"runtime.cgocallbackg1",
|
||||||
"runtime.cgocallbackg",
|
"runtime.cgocallbackg",
|
||||||
|
|
@ -193,10 +192,10 @@ func testCallbackCallers(t *testing.T) {
|
||||||
"runtime.goexit",
|
"runtime.goexit",
|
||||||
}
|
}
|
||||||
if unsafe.Sizeof((*byte)(nil)) == 8 {
|
if unsafe.Sizeof((*byte)(nil)) == 8 {
|
||||||
name[1] = "runtime.call32"
|
name[0] = "runtime.call32"
|
||||||
}
|
}
|
||||||
nestedCall(func() {
|
nestedCall(func() {
|
||||||
n = runtime.Callers(2, pc)
|
n = runtime.Callers(4, pc)
|
||||||
})
|
})
|
||||||
if n != len(name) {
|
if n != len(name) {
|
||||||
t.Errorf("expected %d frames, got %d", len(name), n)
|
t.Errorf("expected %d frames, got %d", len(name), n)
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
/*
|
/*
|
||||||
extern int *GoFn(void);
|
extern int *GoFn(int *);
|
||||||
|
|
||||||
// Yes, you can have definitions if you use //export, as long as they are weak.
|
// Yes, you can have definitions if you use //export, as long as they are weak.
|
||||||
int f(void) __attribute__ ((weak));
|
int f(void) __attribute__ ((weak));
|
||||||
|
|
||||||
int f() {
|
int f() {
|
||||||
int *p = GoFn();
|
int i;
|
||||||
|
int *p = GoFn(&i);
|
||||||
if (*p != 12345)
|
if (*p != 12345)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -20,9 +21,9 @@ int f() {
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
//export GoFn
|
//export GoFn
|
||||||
func GoFn() *C.int {
|
func GoFn(p *C.int) *C.int {
|
||||||
i := C.int(12345)
|
*p = C.int(12345)
|
||||||
return &i
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
|
|
@ -675,6 +675,7 @@ func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
|
||||||
// hasPointer is used by needsPointerCheck. If top is true it returns
|
// hasPointer is used by needsPointerCheck. If top is true it returns
|
||||||
// whether t is or contains a pointer that might point to a pointer.
|
// whether t is or contains a pointer that might point to a pointer.
|
||||||
// If top is false it returns whether t is or contains a pointer.
|
// If top is false it returns whether t is or contains a pointer.
|
||||||
|
// f may be nil.
|
||||||
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
case *ast.ArrayType:
|
case *ast.ArrayType:
|
||||||
|
|
@ -738,6 +739,10 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
|
||||||
// pointer.
|
// pointer.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if f == nil {
|
||||||
|
// Conservative approach: assume pointer.
|
||||||
|
return true
|
||||||
|
}
|
||||||
name := f.Name[t.Sel.Name]
|
name := f.Name[t.Sel.Name]
|
||||||
if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
|
if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
|
||||||
return p.hasPointer(f, name.Type.Go, top)
|
return p.hasPointer(f, name.Type.Go, top)
|
||||||
|
|
@ -768,7 +773,7 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
|
||||||
// This is the address of something that is not an
|
// This is the address of something that is not an
|
||||||
// index expression. We only need to examine the
|
// index expression. We only need to examine the
|
||||||
// single value to which it points.
|
// single value to which it points.
|
||||||
// TODO: what is true is shadowed?
|
// TODO: what if true is shadowed?
|
||||||
return append(args, ast.NewIdent("true"))
|
return append(args, ast.NewIdent("true"))
|
||||||
}
|
}
|
||||||
if !p.hasSideEffects(f, index.X) {
|
if !p.hasSideEffects(f, index.X) {
|
||||||
|
|
|
||||||
|
|
@ -811,12 +811,13 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgcc, "}\n")
|
fmt.Fprintf(fgcc, "}\n")
|
||||||
|
|
||||||
// Build the wrapper function compiled by gc.
|
// Build the wrapper function compiled by cmd/compile.
|
||||||
goname := exp.Func.Name.Name
|
goname := "_cgoexpwrap" + cPrefix + "_"
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
|
goname += fn.Recv.List[0].Names[0].Name + "_"
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
|
goname += exp.Func.Name.Name
|
||||||
|
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.Func.Name.Name)
|
||||||
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
||||||
|
|
@ -829,15 +830,25 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
|
|
||||||
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
||||||
|
|
||||||
// Calling a function with a receiver from C requires
|
// This code uses printer.Fprint, not conf.Fprint,
|
||||||
// a Go wrapper function.
|
// because we don't want //line comments in the middle
|
||||||
|
// of the function types.
|
||||||
|
fmt.Fprintf(fgo2, "\n")
|
||||||
|
fmt.Fprintf(fgo2, "func %s(", goname)
|
||||||
|
comma := false
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
fmt.Fprintf(fgo2, "func %s(recv ", goname)
|
fmt.Fprintf(fgo2, "recv ")
|
||||||
conf.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
||||||
|
comma = true
|
||||||
|
}
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
fmt.Fprintf(fgo2, ", p%d ", i)
|
if comma {
|
||||||
conf.Fprint(fgo2, fset, atype)
|
fmt.Fprintf(fgo2, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "p%d ", i)
|
||||||
|
printer.Fprint(fgo2, fset, atype)
|
||||||
|
comma = true
|
||||||
})
|
})
|
||||||
fmt.Fprintf(fgo2, ")")
|
fmt.Fprintf(fgo2, ")")
|
||||||
if gccResult != "void" {
|
if gccResult != "void" {
|
||||||
|
|
@ -847,16 +858,38 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Fprint(fgo2, ", ")
|
fmt.Fprint(fgo2, ", ")
|
||||||
}
|
}
|
||||||
conf.Fprint(fgo2, fset, atype)
|
fmt.Fprintf(fgo2, "r%d ", i)
|
||||||
|
printer.Fprint(fgo2, fset, atype)
|
||||||
})
|
})
|
||||||
fmt.Fprint(fgo2, ")")
|
fmt.Fprint(fgo2, ")")
|
||||||
}
|
}
|
||||||
fmt.Fprint(fgo2, " {\n")
|
fmt.Fprint(fgo2, " {\n")
|
||||||
|
if gccResult == "void" {
|
||||||
fmt.Fprint(fgo2, "\t")
|
fmt.Fprint(fgo2, "\t")
|
||||||
if gccResult != "void" {
|
} else {
|
||||||
fmt.Fprint(fgo2, "return ")
|
// Verify that any results don't contain any
|
||||||
|
// Go pointers.
|
||||||
|
addedDefer := false
|
||||||
|
forFieldList(fntype.Results,
|
||||||
|
func(i int, aname string, atype ast.Expr) {
|
||||||
|
if !p.hasPointer(nil, atype, false) {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name)
|
if !addedDefer {
|
||||||
|
fmt.Fprint(fgo2, "\tdefer func() {\n")
|
||||||
|
addedDefer = true
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
|
||||||
|
})
|
||||||
|
if addedDefer {
|
||||||
|
fmt.Fprint(fgo2, "\t}()\n")
|
||||||
|
}
|
||||||
|
fmt.Fprint(fgo2, "\treturn ")
|
||||||
|
}
|
||||||
|
if fn.Recv != nil {
|
||||||
|
fmt.Fprintf(fgo2, "recv.")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|
@ -867,7 +900,6 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprint(fgo2, ")\n")
|
fmt.Fprint(fgo2, ")\n")
|
||||||
fmt.Fprint(fgo2, "}\n")
|
fmt.Fprint(fgo2, "}\n")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
||||||
}
|
}
|
||||||
|
|
@ -1251,6 +1283,9 @@ func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
|
||||||
|
|
||||||
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
||||||
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
||||||
|
|
||||||
|
//go:linkname _cgoCheckResult runtime.cgoCheckResult
|
||||||
|
func _cgoCheckResult(interface{})
|
||||||
`
|
`
|
||||||
|
|
||||||
const goStringDef = `
|
const goStringDef = `
|
||||||
|
|
|
||||||
|
|
@ -366,7 +366,7 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
|
||||||
switch aep._type.kind & kindMask {
|
switch aep._type.kind & kindMask {
|
||||||
case kindBool:
|
case kindBool:
|
||||||
pt := (*ptrtype)(unsafe.Pointer(t))
|
pt := (*ptrtype)(unsafe.Pointer(t))
|
||||||
cgoCheckArg(pt.elem, p, true, false)
|
cgoCheckArg(pt.elem, p, true, false, cgoCheckPointerFail)
|
||||||
return ptr
|
return ptr
|
||||||
case kindSlice:
|
case kindSlice:
|
||||||
// Check the slice rather than the pointer.
|
// Check the slice rather than the pointer.
|
||||||
|
|
@ -384,17 +384,18 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cgoCheckArg(t, ep.data, t.kind&kindDirectIface == 0, top)
|
cgoCheckArg(t, ep.data, t.kind&kindDirectIface == 0, top, cgoCheckPointerFail)
|
||||||
return ptr
|
return ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
const cgoCheckPointerFail = "cgo argument has Go pointer to Go pointer"
|
const cgoCheckPointerFail = "cgo argument has Go pointer to Go pointer"
|
||||||
|
const cgoResultFail = "cgo result has Go pointer"
|
||||||
|
|
||||||
// cgoCheckArg is the real work of cgoCheckPointer. The argument p
|
// cgoCheckArg is the real work of cgoCheckPointer. The argument p
|
||||||
// is either a pointer to the value (of type t), or the value itself,
|
// is either a pointer to the value (of type t), or the value itself,
|
||||||
// depending on indir. The top parameter is whether we are at the top
|
// depending on indir. The top parameter is whether we are at the top
|
||||||
// level, where Go pointers are allowed.
|
// level, where Go pointers are allowed.
|
||||||
func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
|
||||||
if t.kind&kindNoPointers != 0 {
|
if t.kind&kindNoPointers != 0 {
|
||||||
// If the type has no pointers there is nothing to do.
|
// If the type has no pointers there is nothing to do.
|
||||||
return
|
return
|
||||||
|
|
@ -409,18 +410,18 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
||||||
if at.len != 1 {
|
if at.len != 1 {
|
||||||
throw("can't happen")
|
throw("can't happen")
|
||||||
}
|
}
|
||||||
cgoCheckArg(at.elem, p, at.elem.kind&kindDirectIface == 0, top)
|
cgoCheckArg(at.elem, p, at.elem.kind&kindDirectIface == 0, top, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := uintptr(0); i < at.len; i++ {
|
for i := uintptr(0); i < at.len; i++ {
|
||||||
cgoCheckArg(at.elem, p, true, top)
|
cgoCheckArg(at.elem, p, true, top, msg)
|
||||||
p = add(p, at.elem.size)
|
p = add(p, at.elem.size)
|
||||||
}
|
}
|
||||||
case kindChan, kindMap:
|
case kindChan, kindMap:
|
||||||
// These types contain internal pointers that will
|
// These types contain internal pointers that will
|
||||||
// always be allocated in the Go heap. It's never OK
|
// always be allocated in the Go heap. It's never OK
|
||||||
// to pass them to C.
|
// to pass them to C.
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
case kindFunc:
|
case kindFunc:
|
||||||
if indir {
|
if indir {
|
||||||
p = *(*unsafe.Pointer)(p)
|
p = *(*unsafe.Pointer)(p)
|
||||||
|
|
@ -428,7 +429,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
||||||
if !cgoIsGoPointer(p) {
|
if !cgoIsGoPointer(p) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
case kindInterface:
|
case kindInterface:
|
||||||
it := *(**_type)(p)
|
it := *(**_type)(p)
|
||||||
if it == nil {
|
if it == nil {
|
||||||
|
|
@ -438,16 +439,16 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
||||||
// constant. A type not known at compile time will be
|
// constant. A type not known at compile time will be
|
||||||
// in the heap and will not be OK.
|
// in the heap and will not be OK.
|
||||||
if inheap(uintptr(unsafe.Pointer(it))) {
|
if inheap(uintptr(unsafe.Pointer(it))) {
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
}
|
}
|
||||||
p = *(*unsafe.Pointer)(add(p, sys.PtrSize))
|
p = *(*unsafe.Pointer)(add(p, sys.PtrSize))
|
||||||
if !cgoIsGoPointer(p) {
|
if !cgoIsGoPointer(p) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !top {
|
if !top {
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
}
|
}
|
||||||
cgoCheckArg(it, p, it.kind&kindDirectIface == 0, false)
|
cgoCheckArg(it, p, it.kind&kindDirectIface == 0, false, msg)
|
||||||
case kindSlice:
|
case kindSlice:
|
||||||
st := (*slicetype)(unsafe.Pointer(t))
|
st := (*slicetype)(unsafe.Pointer(t))
|
||||||
s := (*slice)(p)
|
s := (*slice)(p)
|
||||||
|
|
@ -456,10 +457,10 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !top {
|
if !top {
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
}
|
}
|
||||||
for i := 0; i < s.cap; i++ {
|
for i := 0; i < s.cap; i++ {
|
||||||
cgoCheckArg(st.elem, p, true, false)
|
cgoCheckArg(st.elem, p, true, false, msg)
|
||||||
p = add(p, st.elem.size)
|
p = add(p, st.elem.size)
|
||||||
}
|
}
|
||||||
case kindStruct:
|
case kindStruct:
|
||||||
|
|
@ -468,11 +469,11 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
||||||
if len(st.fields) != 1 {
|
if len(st.fields) != 1 {
|
||||||
throw("can't happen")
|
throw("can't happen")
|
||||||
}
|
}
|
||||||
cgoCheckArg(st.fields[0].typ, p, st.fields[0].typ.kind&kindDirectIface == 0, top)
|
cgoCheckArg(st.fields[0].typ, p, st.fields[0].typ.kind&kindDirectIface == 0, top, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, f := range st.fields {
|
for _, f := range st.fields {
|
||||||
cgoCheckArg(f.typ, add(p, f.offset), true, top)
|
cgoCheckArg(f.typ, add(p, f.offset), true, top, msg)
|
||||||
}
|
}
|
||||||
case kindPtr, kindUnsafePointer:
|
case kindPtr, kindUnsafePointer:
|
||||||
if indir {
|
if indir {
|
||||||
|
|
@ -483,17 +484,17 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !top {
|
if !top {
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
cgoCheckUnknownPointer(p)
|
cgoCheckUnknownPointer(p, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cgoCheckUnknownPointer is called for an arbitrary pointer into Go
|
// cgoCheckUnknownPointer is called for an arbitrary pointer into Go
|
||||||
// memory. It checks whether that Go memory contains any other
|
// memory. It checks whether that Go memory contains any other
|
||||||
// pointer into Go memory. If it does, we panic.
|
// pointer into Go memory. If it does, we panic.
|
||||||
func cgoCheckUnknownPointer(p unsafe.Pointer) {
|
func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) {
|
||||||
if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) {
|
if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) {
|
||||||
if !inheap(uintptr(p)) {
|
if !inheap(uintptr(p)) {
|
||||||
// This pointer is either to a stack or to an
|
// This pointer is either to a stack or to an
|
||||||
|
|
@ -516,7 +517,7 @@ func cgoCheckUnknownPointer(p unsafe.Pointer) {
|
||||||
}
|
}
|
||||||
if bits&bitPointer != 0 {
|
if bits&bitPointer != 0 {
|
||||||
if cgoIsGoPointer(*(*unsafe.Pointer)(unsafe.Pointer(base + i))) {
|
if cgoIsGoPointer(*(*unsafe.Pointer)(unsafe.Pointer(base + i))) {
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hbits = hbits.next()
|
hbits = hbits.next()
|
||||||
|
|
@ -529,7 +530,7 @@ func cgoCheckUnknownPointer(p unsafe.Pointer) {
|
||||||
if cgoInRange(p, datap.data, datap.edata) || cgoInRange(p, datap.bss, datap.ebss) {
|
if cgoInRange(p, datap.data, datap.edata) || cgoInRange(p, datap.bss, datap.ebss) {
|
||||||
// We have no way to know the size of the object.
|
// We have no way to know the size of the object.
|
||||||
// We have to assume that it might contain a pointer.
|
// We have to assume that it might contain a pointer.
|
||||||
panic(errorString(cgoCheckPointerFail))
|
panic(errorString(msg))
|
||||||
}
|
}
|
||||||
// In the text or noptr sections, we know that the
|
// In the text or noptr sections, we know that the
|
||||||
// pointer does not point to a Go pointer.
|
// pointer does not point to a Go pointer.
|
||||||
|
|
@ -565,3 +566,16 @@ func cgoIsGoPointer(p unsafe.Pointer) bool {
|
||||||
func cgoInRange(p unsafe.Pointer, start, end uintptr) bool {
|
func cgoInRange(p unsafe.Pointer, start, end uintptr) bool {
|
||||||
return start <= uintptr(p) && uintptr(p) < end
|
return start <= uintptr(p) && uintptr(p) < end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cgoCheckResult is called to check the result parameter of an
|
||||||
|
// exported Go function. It panics if the result is or contains a Go
|
||||||
|
// pointer.
|
||||||
|
func cgoCheckResult(val interface{}) {
|
||||||
|
if debug.cgocheck == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := (*eface)(unsafe.Pointer(&val))
|
||||||
|
t := ep._type
|
||||||
|
cgoCheckArg(t, ep.data, t.kind&kindDirectIface == 0, false, cgoResultFail)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue