1
0
mirror of https://github.com/golang/go synced 2024-11-13 17:30:24 -07:00

runtime: check only up to ptrdata bytes for pointers

Fixes #14508.

Change-Id: I237d0c5a79a73e6c97bdb2077d8ede613128b978
Reviewed-on: https://go-review.googlesource.com/23224
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
Ian Lance Taylor 2016-05-18 13:19:24 -07:00
parent ebbe4f8db7
commit 538537a28d
2 changed files with 42 additions and 1 deletions

View File

@ -290,6 +290,30 @@ var ptrTests = []ptrTest{
}, },
fail: true, fail: true,
}, },
{
// Don't check non-pointer data.
// Uses unsafe code to get a pointer we shouldn't check.
// Although we use unsafe, the uintptr represents an integer
// that happens to have the same representation as a pointer;
// that is, we are testing something that is not unsafe.
name: "ptrdata1",
c: `#include <stdlib.h>
void f(void* p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; a [8*8]byte; u uintptr }`,
body: `i := 0; p := &S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f(unsafe.Pointer(q))`,
fail: false,
},
{
// Like ptrdata1, but with a type that uses a GC program.
name: "ptrdata2",
c: `#include <stdlib.h>
void f(void* p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
body: `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`,
fail: false,
},
} }
func main() { func main() {

View File

@ -94,6 +94,14 @@ func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
//go:nosplit //go:nosplit
//go:nowritebarrier //go:nowritebarrier
func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
// Anything past typ.ptrdata is not a pointer.
if typ.ptrdata <= off {
return
}
if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
size = ptrdataSize
}
if typ.kind&kindGCProg == 0 { if typ.kind&kindGCProg == 0 {
cgoCheckBits(src, typ.gcdata, off, size) cgoCheckBits(src, typ.gcdata, off, size)
return return
@ -184,7 +192,7 @@ func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
// cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch // cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch
// fall back to look for pointers in src using the type information. // fall back to look for pointers in src using the type information.
// We only this when looking at a value on the stack when the type // We only use this when looking at a value on the stack when the type
// uses a GC program, because otherwise it's more efficient to use the // uses a GC program, because otherwise it's more efficient to use the
// GC bits. This is called on the system stack. // GC bits. This is called on the system stack.
//go:nowritebarrier //go:nowritebarrier
@ -193,6 +201,15 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
if typ.kind&kindNoPointers != 0 { if typ.kind&kindNoPointers != 0 {
return return
} }
// Anything past typ.ptrdata is not a pointer.
if typ.ptrdata <= off {
return
}
if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
size = ptrdataSize
}
if typ.kind&kindGCProg == 0 { if typ.kind&kindGCProg == 0 {
cgoCheckBits(src, typ.gcdata, off, size) cgoCheckBits(src, typ.gcdata, off, size)
return return