]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime: check only up to ptrdata bytes for pointers
authorIan Lance Taylor <iant@golang.org>
Wed, 18 May 2016 20:19:24 +0000 (13:19 -0700)
committerIan Lance Taylor <iant@golang.org>
Wed, 18 May 2016 23:39:06 +0000 (23:39 +0000)
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>
misc/cgo/errors/ptr.go
src/runtime/cgocheck.go

index b6cec8e10d0fe28e087c122d6685c95aee65784a..27eb78e36cfbc0bc958ba2d08faa531365637a16 100644 (file)
@@ -290,6 +290,30 @@ var ptrTests = []ptrTest{
                },
                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() {
index d85d5fe5a8ba15fd1276f28a4fc2b71b98058f21..2d064145a415de3bf071ee10a5c1f0a92d3b74a7 100644 (file)
@@ -94,6 +94,14 @@ func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
 //go:nosplit
 //go:nowritebarrier
 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 {
                cgoCheckBits(src, typ.gcdata, off, size)
                return
@@ -184,7 +192,7 @@ func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
 
 // cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch
 // 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
 // GC bits. This is called on the system stack.
 //go:nowritebarrier
@@ -193,6 +201,15 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
        if typ.kind&kindNoPointers != 0 {
                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 {
                cgoCheckBits(src, typ.gcdata, off, size)
                return