1 // Copyright 2015 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 // Tests that cgo detects invalid pointer passing at runtime.
21 var tmp
= flag
.String("tmp", "", "use `dir` for temporary files and do not clean up")
23 // ptrTest is the tests without the boilerplate.
25 name
string // for reporting
26 c
string // the cgo comment
27 c1
string // cgo comment forced into non-export cgo file
28 imports
[]string // a list of imports
29 support
string // supporting functions
30 body
string // the body of the main function
31 extra
[]extra
// extra files
32 fail
bool // whether the test should fail
33 expensive
bool // whether the test requires the expensive check
41 var ptrTests
= []ptrTest
{
43 // Passing a pointer to a struct that contains a Go pointer.
45 c
: `typedef struct s1 { int *p; } s1; void f1(s1 *ps) {}`,
46 body
: `C.f1(&C.s1{new(C.int)})`,
50 // Passing a pointer to a struct that contains a Go pointer.
52 c
: `typedef struct s2 { int *p; } s2; void f2(s2 *ps) {}`,
53 body
: `p := &C.s2{new(C.int)}; C.f2(p)`,
57 // Passing a pointer to an int field of a Go struct
58 // that (irrelevantly) contains a Go pointer.
60 c
: `struct s3 { int i; int *p; }; void f3(int *p) {}`,
61 body
: `p := &C.struct_s3{i: 0, p: new(C.int)}; C.f3(&p.i)`,
65 // Passing a pointer to a pointer field of a Go struct.
67 c
: `struct s4 { int i; int *p; }; void f4(int **p) {}`,
68 body
: `p := &C.struct_s4{i: 0, p: new(C.int)}; C.f4(&p.p)`,
72 // Passing a pointer to a pointer field of a Go
73 // struct, where the field does not contain a Go
74 // pointer, but another field (irrelevantly) does.
76 c
: `struct s5 { int *p1; int *p2; }; void f5(int **p) {}`,
77 body
: `p := &C.struct_s5{p1: nil, p2: new(C.int)}; C.f5(&p.p1)`,
81 // Passing the address of a slice with no Go pointers.
83 c
: `void f6(void **p) {}`,
84 imports
: []string{"unsafe"},
85 body
: `s := []unsafe.Pointer{nil}; C.f6(&s[0])`,
89 // Passing the address of a slice with a Go pointer.
91 c
: `void f7(void **p) {}`,
92 imports
: []string{"unsafe"},
93 body
: `i := 0; s := []unsafe.Pointer{unsafe.Pointer(&i)}; C.f7(&s[0])`,
97 // Passing the address of a slice with a Go pointer,
98 // where we are passing the address of an element that
99 // is not a Go pointer.
101 c
: `void f8(void **p) {}`,
102 imports
: []string{"unsafe"},
103 body
: `i := 0; s := []unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f8(&s[0])`,
107 // Passing the address of a slice that is an element
108 // in a struct only looks at the slice.
110 c
: `void f9(void **p) {}`,
111 imports
: []string{"unsafe"},
112 support
: `type S9 struct { p *int; s []unsafe.Pointer }`,
113 body
: `i := 0; p := &S9{p:&i, s:[]unsafe.Pointer{nil}}; C.f9(&p.s[0])`,
117 // Passing the address of a slice of an array that is
118 // an element in a struct, with a type conversion.
120 c
: `void f10(void* p) {}`,
121 imports
: []string{"unsafe"},
122 support
: `type S10 struct { p *int; a [4]byte }`,
123 body
: `i := 0; p := &S10{p:&i}; s := p.a[:]; C.f10(unsafe.Pointer(&s[0]))`,
127 // Passing the address of a slice of an array that is
128 // an element in a struct, with a type conversion.
130 c
: `typedef void* PV11; void f11(PV11 p) {}`,
131 imports
: []string{"unsafe"},
132 support
: `type S11 struct { p *int; a [4]byte }`,
133 body
: `i := 0; p := &S11{p:&i}; C.f11(C.PV11(unsafe.Pointer(&p.a[0])))`,
137 // Passing the address of a static variable with no
138 // pointers doesn't matter.
140 c
: `void f12(char** parg) {}`,
141 support
: `var hello12 = [...]C.char{'h', 'e', 'l', 'l', 'o'}`,
142 body
: `parg := [1]*C.char{&hello12[0]}; C.f12(&parg[0])`,
146 // Passing the address of a static variable with
147 // pointers does matter.
149 c
: `void f13(char*** parg) {}`,
150 support
: `var hello13 = [...]*C.char{new(C.char)}`,
151 body
: `parg := [1]**C.char{&hello13[0]}; C.f13(&parg[0])`,
155 // Storing a Go pointer into C memory should fail.
157 c
: `#include <stdlib.h>
158 char **f14a() { return malloc(sizeof(char*)); }
159 void f14b(char **p) {}`,
160 body
: `p := C.f14a(); *p = new(C.char); C.f14b(p)`,
165 // Storing a Go pointer into C memory by assigning a
166 // large value should fail.
167 name
: "barrierstruct",
168 c
: `#include <stdlib.h>
169 struct s15 { char *a[10]; };
170 struct s15 *f15() { return malloc(sizeof(struct s15)); }
171 void f15b(struct s15 *p) {}`,
172 body
: `p := C.f15(); p.a = [10]*C.char{new(C.char)}; C.f15b(p)`,
177 // Storing a Go pointer into C memory using a slice
179 name
: "barrierslice",
180 c
: `#include <stdlib.h>
181 struct s16 { char *a[10]; };
182 struct s16 *f16() { return malloc(sizeof(struct s16)); }
183 void f16b(struct s16 *p) {}`,
184 body
: `p := C.f16(); copy(p.a[:], []*C.char{new(C.char)}); C.f16b(p)`,
189 // A very large value uses a GC program, which is a
190 // different code path.
191 name
: "barriergcprogarray",
192 c
: `#include <stdlib.h>
193 struct s17 { char *a[32769]; };
194 struct s17 *f17() { return malloc(sizeof(struct s17)); }
195 void f17b(struct s17 *p) {}`,
196 body
: `p := C.f17(); p.a = [32769]*C.char{new(C.char)}; C.f17b(p)`,
201 // Similar case, with a source on the heap.
202 name
: "barriergcprogarrayheap",
203 c
: `#include <stdlib.h>
204 struct s18 { char *a[32769]; };
205 struct s18 *f18() { return malloc(sizeof(struct s18)); }
206 void f18b(struct s18 *p) {}
207 void f18c(void *p) {}`,
208 imports
: []string{"unsafe"},
209 body
: `p := C.f18(); n := &[32769]*C.char{new(C.char)}; p.a = *n; C.f18b(p); n[0] = nil; C.f18c(unsafe.Pointer(n))`,
214 // A GC program with a struct.
215 name
: "barriergcprogstruct",
216 c
: `#include <stdlib.h>
217 struct s19a { char *a[32769]; };
218 struct s19b { struct s19a f; };
219 struct s19b *f19() { return malloc(sizeof(struct s19b)); }
220 void f19b(struct s19b *p) {}`,
221 body
: `p := C.f19(); p.f = C.struct_s19a{[32769]*C.char{new(C.char)}}; C.f19b(p)`,
226 // Similar case, with a source on the heap.
227 name
: "barriergcprogstructheap",
228 c
: `#include <stdlib.h>
229 struct s20a { char *a[32769]; };
230 struct s20b { struct s20a f; };
231 struct s20b *f20() { return malloc(sizeof(struct s20b)); }
232 void f20b(struct s20b *p) {}
233 void f20c(void *p) {}`,
234 imports
: []string{"unsafe"},
235 body
: `p := C.f20(); n := &C.struct_s20a{[32769]*C.char{new(C.char)}}; p.f = *n; C.f20b(p); n.a[0] = nil; C.f20c(unsafe.Pointer(n))`,
240 // Exported functions may not return Go pointers.
242 c
: `extern unsigned char *GoFn21();`,
243 support
: `//export GoFn21
244 func GoFn21() *byte { return new(byte) }`,
249 // Returning a C pointer is fine.
251 c
: `#include <stdlib.h>
252 extern unsigned char *GoFn22();`,
253 support
: `//export GoFn22
254 func GoFn22() *byte { return (*byte)(C.malloc(1)) }`,
258 // Passing a Go string is fine.
260 c
: `#include <stddef.h>
261 typedef struct { const char *p; ptrdiff_t n; } gostring23;
262 gostring23 f23(gostring23 s) { return s; }`,
263 imports
: []string{"unsafe"},
264 body
: `s := "a"; r := C.f23(*(*C.gostring23)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`,
267 // Passing a slice of Go strings fails.
268 name
: "passstringslice",
269 c
: `void f24(void *p) {}`,
270 imports
: []string{"strings", "unsafe"},
271 support
: `type S24 struct { a [1]string }`,
272 body
: `s := S24{a:[1]string{strings.Repeat("a", 2)}}; C.f24(unsafe.Pointer(&s.a[0]))`,
276 // Exported functions may not return strings.
278 c
: `extern void f25();`,
279 imports
: []string{"strings"},
280 support
: `//export GoStr25
281 func GoStr25() string { return strings.Repeat("a", 2) }`,
283 c1
: `#include <stddef.h>
284 typedef struct { const char *p; ptrdiff_t n; } gostring25;
285 extern gostring25 GoStr25();
286 void f25() { GoStr25(); }`,
290 // Don't check non-pointer data.
291 // Uses unsafe code to get a pointer we shouldn't check.
292 // Although we use unsafe, the uintptr represents an integer
293 // that happens to have the same representation as a pointer;
294 // that is, we are testing something that is not unsafe.
296 c
: `#include <stdlib.h>
297 void f26(void* p) {}`,
298 imports
: []string{"unsafe"},
299 support
: `type S26 struct { p *int; a [8*8]byte; u uintptr }`,
300 body
: `i := 0; p := &S26{u:uintptr(unsafe.Pointer(&i))}; q := (*S26)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f26(unsafe.Pointer(q))`,
304 // Like ptrdata1, but with a type that uses a GC program.
306 c
: `#include <stdlib.h>
307 void f27(void* p) {}`,
308 imports
: []string{"unsafe"},
309 support
: `type S27 struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
310 body
: `i := 0; p := S27{u:uintptr(unsafe.Pointer(&i))}; q := (*S27)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f27(unsafe.Pointer(q))`,
314 // Check deferred pointers when they are used, not
315 // when the defer statement is run.
317 c
: `typedef struct s28 { int *p; } s28; void f28(s28 *ps) {}`,
318 body
: `p := &C.s28{}; defer C.f28(p); p.p = new(C.int)`,
322 // Check a pointer to a union if the union has any
325 c
: `typedef union { char **p; unsigned long i; } u29; void f29(u29 *pu) {}`,
326 imports
: []string{"unsafe"},
327 body
: `var b C.char; p := &b; C.f29((*C.u29)(unsafe.Pointer(&p)))`,
331 // Don't check a pointer to a union if the union does
332 // not have any pointer fields.
333 // Like ptrdata1 above, the uintptr represents an
334 // integer that happens to have the same
335 // representation as a pointer.
337 c
: `typedef union { unsigned long i; } u39; void f39(u39 *pu) {}`,
338 imports
: []string{"unsafe"},
339 body
: `var b C.char; p := &b; C.f39((*C.u39)(unsafe.Pointer(&p)))`,
343 // Test preemption while entering a cgo call. Issue #21306.
344 name
: "preemptduringcall",
346 imports
: []string{"runtime", "sync"},
347 body
: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f30(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`,
351 // Test poller deadline with cgocheck=2. Issue #23435.
353 c
: `#define US31 10`,
354 imports
: []string{"os", "time"},
355 body
: `r, _, _ := os.Pipe(); r.SetDeadline(time.Now().Add(C.US31 * time.Microsecond))`,
359 // Test for double evaluation of channel receive.
361 c
: `void f32(char** p) {}`,
362 imports
: []string{"time"},
363 body
: `c := make(chan []*C.char, 2); c <- make([]*C.char, 1); go func() { time.Sleep(10 * time.Second); panic("received twice from chan") }(); C.f32(&(<-c)[0]);`,
367 // Test that converting the address of a struct field
368 // to unsafe.Pointer still just checks that field.
371 c
: `void f33(void* p) {}`,
372 imports
: []string{"unsafe"},
373 support
: `type S33 struct { p *int; a [8]byte; u uintptr }`,
374 body
: `s := &S33{p: new(int)}; C.f33(unsafe.Pointer(&s.a))`,
378 // Test that converting multiple struct field
379 // addresses to unsafe.Pointer still just checks those
380 // fields. Issue #25941.
381 name
: "structfield2",
382 c
: `void f34(void* p, int r, void* s) {}`,
383 imports
: []string{"unsafe"},
384 support
: `type S34 struct { a [8]byte; p *int; b int64; }`,
385 body
: `s := &S34{p: new(int)}; C.f34(unsafe.Pointer(&s.a), 32, unsafe.Pointer(&s.b))`,
389 // Test that second argument to cgoCheckPointer is
390 // evaluated when a deferred function is deferred, not
393 c
: `void f35(char **pc) {}`,
394 support
: `type S35a struct { s []*C.char }; type S35b struct { ps *S35a }`,
395 body
: `p := &S35b{&S35a{[]*C.char{nil}}}; defer C.f35(&p.ps.s[0]); p.ps = nil`,
399 // Test that indexing into a function call still
400 // examines only the slice being indexed.
402 c
: `void f36(void *p) {}`,
403 imports
: []string{"bytes", "unsafe"},
404 body
: `var b bytes.Buffer; b.WriteString("a"); C.f36(unsafe.Pointer(&b.Bytes()[0]))`,
408 // Test that bgsweep releasing a finalizer is OK.
410 c
: `// Nothing to declare.`,
411 imports
: []string{"os"},
412 support
: `func open37() { os.Open(os.Args[0]) }; var G37 [][]byte`,
413 body
: `for i := 0; i < 10000; i++ { G37 = append(G37, make([]byte, 4096)); if i % 100 == 0 { G37 = nil; open37() } }`,
417 // Test that converting generated struct to interface is OK.
419 c
: `// Nothing to declare.`,
420 imports
: []string{"reflect"},
421 support
: `type MyInt38 int; func (i MyInt38) Get() int { return int(i) }; type Getter38 interface { Get() int }`,
422 body
: `t := reflect.StructOf([]reflect.StructField{{Name: "MyInt38", Type: reflect.TypeOf(MyInt38(0)), Anonymous: true}}); v := reflect.New(t).Elem(); v.Interface().(Getter38).Get()`,
426 // Test that a converted address of a struct field results
427 // in a check for just that field and not the whole struct.
428 name
: "structfieldcast",
429 c
: `struct S40i { int i; int* p; }; void f40(struct S40i* p) {}`,
430 support
: `type S40 struct { p *int; a C.struct_S40i }`,
431 body
: `s := &S40{p: new(int)}; C.f40((*C.struct_S40i)(&s.a))`,
436 func TestPointerChecks(t
*testing
.T
) {
437 dir
, exe
:= buildPtrTests(t
)
439 // We (TestPointerChecks) return before the parallel subtest functions do,
440 // so we can't just defer os.RemoveAll(dir). Instead we have to wait for
441 // the parallel subtests to finish. This code looks racy but is not:
442 // the add +1 run in serial before testOne blocks. The -1 run in parallel
443 // after testOne finishes.
445 for _
, pt
:= range ptrTests
{
447 t
.Run(pt
.name
, func(t
*testing
.T
) {
448 atomic
.AddInt32(&pending
, +1)
450 if atomic
.AddInt32(&pending
, -1) == 0 {
459 func buildPtrTests(t
*testing
.T
) (dir
, exe
string) {
465 d
, err
:= os
.MkdirTemp("", filepath
.Base(t
.Name()))
473 src
:= filepath
.Join(gopath
, "src", "ptrtest")
474 if err
:= os
.MkdirAll(src
, 0777); err
!= nil {
477 if err
:= os
.WriteFile(filepath
.Join(src
, "go.mod"), []byte("module ptrtest"), 0666); err
!= nil {
481 // Prepare two cgo inputs: one for standard cgo and one for //export cgo.
482 // (The latter cannot have C definitions, only declarations.)
483 var cgo1
, cgo2 bytes
.Buffer
484 fmt
.Fprintf(&cgo1
, "package main\n\n/*\n")
485 fmt
.Fprintf(&cgo2
, "package main\n\n/*\n")
488 for _
, pt
:= range ptrTests
{
490 if strings
.Contains(pt
.support
, "//export") {
493 fmt
.Fprintf(cgo
, "%s\n", pt
.c
)
494 fmt
.Fprintf(&cgo1
, "%s\n", pt
.c1
)
496 fmt
.Fprintf(&cgo1
, "*/\nimport \"C\"\n\n")
497 fmt
.Fprintf(&cgo2
, "*/\nimport \"C\"\n\n")
500 did1
:= make(map[string]bool)
501 did2
:= make(map[string]bool)
502 did1
["os"] = true // for ptrTestMain
503 fmt
.Fprintf(&cgo1
, "import \"os\"\n")
505 for _
, pt
:= range ptrTests
{
508 if strings
.Contains(pt
.support
, "//export") {
512 for _
, imp
:= range pt
.imports
{
515 fmt
.Fprintf(cgo
, "import %q\n", imp
)
520 // Func support and bodies.
521 for _
, pt
:= range ptrTests
{
523 if strings
.Contains(pt
.support
, "//export") {
526 fmt
.Fprintf(cgo
, "%s\nfunc %s() {\n%s\n}\n", pt
.support
, pt
.name
, pt
.body
)
529 // Func list and main dispatch.
530 fmt
.Fprintf(&cgo1
, "var funcs = map[string]func() {\n")
531 for _
, pt
:= range ptrTests
{
532 fmt
.Fprintf(&cgo1
, "\t%q: %s,\n", pt
.name
, pt
.name
)
534 fmt
.Fprintf(&cgo1
, "}\n\n")
535 fmt
.Fprintf(&cgo1
, "%s\n", ptrTestMain
)
537 if err
:= os
.WriteFile(filepath
.Join(src
, "cgo1.go"), cgo1
.Bytes(), 0666); err
!= nil {
540 if err
:= os
.WriteFile(filepath
.Join(src
, "cgo2.go"), cgo2
.Bytes(), 0666); err
!= nil {
544 cmd
:= exec
.Command("go", "build", "-o", "ptrtest.exe")
546 cmd
.Env
= append(os
.Environ(), "GOPATH="+gopath
)
547 out
, err
:= cmd
.CombinedOutput()
549 t
.Fatalf("go build: %v\n%s", err
, out
)
552 return dir
, filepath
.Join(src
, "ptrtest.exe")
555 const ptrTestMain
= `
557 for _, arg := range os.Args[1:] {
560 panic("missing func "+arg)
567 var csem
= make(chan bool, 16)
569 func testOne(t
*testing
.T
, pt ptrTest
, exe
string) {
572 // Run the tests in parallel, but don't run too many
573 // executions in parallel, to avoid overloading the system.
574 runcmd
:= func(cgocheck
string) ([]byte, error
) {
576 defer func() { <-csem
}()
577 cmd
:= exec
.Command(exe
, pt
.name
)
578 cmd
.Env
= append(os
.Environ(), "GODEBUG=cgocheck="+cgocheck
)
579 return cmd
.CombinedOutput()
583 buf
, err
:= runcmd("1")
587 t
.Fatalf("test marked expensive, but failed when not expensive: %v", err
)
589 t
.Errorf("failed unexpectedly with GODEBUG=cgocheck=1: %v", err
)
600 buf
, err
:= runcmd(cgocheck
)
604 t
.Fatalf("did not fail as expected")
605 } else if !bytes
.Contains(buf
, []byte("Go pointer")) {
607 t
.Fatalf("did not print expected error (failed with %v)", err
)
612 t
.Fatalf("failed unexpectedly: %v", err
)
616 // Make sure it passes with the expensive checks.
617 buf
, err
:= runcmd("2")
620 t
.Fatalf("failed unexpectedly with expensive checks: %v", err
)
626 buf
, err
:= runcmd("0")
629 t
.Fatalf("failed unexpectedly with GODEBUG=cgocheck=0: %v", err
)