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.
23 var tmp = flag.String("tmp", "", "use `dir` for temporary files and do not clean up")
25 // ptrTest is the tests without the boilerplate.
27 name string // for reporting
28 c string // the cgo comment
29 c1 string // cgo comment forced into non-export cgo file
30 imports []string // a list of imports
31 support string // supporting functions
32 body string // the body of the main function
33 extra []extra // extra files
34 fail bool // whether the test should fail
35 expensive bool // whether the test requires the expensive check
43 var ptrTests = []ptrTest{
45 // Passing a pointer to a struct that contains a Go pointer.
47 c: `typedef struct s1 { int *p; } s1; void f1(s1 *ps) {}`,
48 body: `C.f1(&C.s1{new(C.int)})`,
52 // Passing a pointer to a struct that contains a Go pointer.
54 c: `typedef struct s2 { int *p; } s2; void f2(s2 *ps) {}`,
55 body: `p := &C.s2{new(C.int)}; C.f2(p)`,
59 // Passing a pointer to an int field of a Go struct
60 // that (irrelevantly) contains a Go pointer.
62 c: `struct s3 { int i; int *p; }; void f3(int *p) {}`,
63 body: `p := &C.struct_s3{i: 0, p: new(C.int)}; C.f3(&p.i)`,
67 // Passing a pointer to a pointer field of a Go struct.
69 c: `struct s4 { int i; int *p; }; void f4(int **p) {}`,
70 body: `p := &C.struct_s4{i: 0, p: new(C.int)}; C.f4(&p.p)`,
74 // Passing a pointer to a pointer field of a Go
75 // struct, where the field does not contain a Go
76 // pointer, but another field (irrelevantly) does.
78 c: `struct s5 { int *p1; int *p2; }; void f5(int **p) {}`,
79 body: `p := &C.struct_s5{p1: nil, p2: new(C.int)}; C.f5(&p.p1)`,
83 // Passing the address of a slice with no Go pointers.
85 c: `void f6(void **p) {}`,
86 imports: []string{"unsafe"},
87 body: `s := []unsafe.Pointer{nil}; C.f6(&s[0])`,
91 // Passing the address of a slice with a Go pointer.
93 c: `void f7(void **p) {}`,
94 imports: []string{"unsafe"},
95 body: `i := 0; s := []unsafe.Pointer{unsafe.Pointer(&i)}; C.f7(&s[0])`,
99 // Passing the address of a slice with a Go pointer,
100 // where we are passing the address of an element that
101 // is not a Go pointer.
103 c: `void f8(void **p) {}`,
104 imports: []string{"unsafe"},
105 body: `i := 0; s := []unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f8(&s[0])`,
109 // Passing the address of a slice that is an element
110 // in a struct only looks at the slice.
112 c: `void f9(void **p) {}`,
113 imports: []string{"unsafe"},
114 support: `type S9 struct { p *int; s []unsafe.Pointer }`,
115 body: `i := 0; p := &S9{p:&i, s:[]unsafe.Pointer{nil}}; C.f9(&p.s[0])`,
119 // Passing the address of a slice of an array that is
120 // an element in a struct, with a type conversion.
122 c: `void f10(void* p) {}`,
123 imports: []string{"unsafe"},
124 support: `type S10 struct { p *int; a [4]byte }`,
125 body: `i := 0; p := &S10{p:&i}; s := p.a[:]; C.f10(unsafe.Pointer(&s[0]))`,
129 // Passing the address of a slice of an array that is
130 // an element in a struct, with a type conversion.
132 c: `typedef void* PV11; void f11(PV11 p) {}`,
133 imports: []string{"unsafe"},
134 support: `type S11 struct { p *int; a [4]byte }`,
135 body: `i := 0; p := &S11{p:&i}; C.f11(C.PV11(unsafe.Pointer(&p.a[0])))`,
139 // Passing the address of a static variable with no
140 // pointers doesn't matter.
142 c: `void f12(char** parg) {}`,
143 support: `var hello12 = [...]C.char{'h', 'e', 'l', 'l', 'o'}`,
144 body: `parg := [1]*C.char{&hello12[0]}; C.f12(&parg[0])`,
148 // Passing the address of a static variable with
149 // pointers does matter.
151 c: `void f13(char*** parg) {}`,
152 support: `var hello13 = [...]*C.char{new(C.char)}`,
153 body: `parg := [1]**C.char{&hello13[0]}; C.f13(&parg[0])`,
157 // Storing a Go pointer into C memory should fail.
159 c: `#include <stdlib.h>
160 char **f14a() { return malloc(sizeof(char*)); }
161 void f14b(char **p) {}`,
162 body: `p := C.f14a(); *p = new(C.char); C.f14b(p)`,
167 // Storing a pinned Go pointer into C memory should succeed.
168 name: "barrierpinnedok",
169 c: `#include <stdlib.h>
170 char **f14a2() { return malloc(sizeof(char*)); }
171 void f14b2(char **p) {}`,
172 imports: []string{"runtime"},
173 body: `var pinr runtime.Pinner; p := C.f14a2(); x := new(C.char); pinr.Pin(x); *p = x; C.f14b2(p); pinr.Unpin()`,
178 // Storing a Go pointer into C memory by assigning a
179 // large value should fail.
180 name: "barrierstruct",
181 c: `#include <stdlib.h>
182 struct s15 { char *a[10]; };
183 struct s15 *f15() { return malloc(sizeof(struct s15)); }
184 void f15b(struct s15 *p) {}`,
185 body: `p := C.f15(); p.a = [10]*C.char{new(C.char)}; C.f15b(p)`,
190 // Storing a Go pointer into C memory using a slice
192 name: "barrierslice",
193 c: `#include <stdlib.h>
194 struct s16 { char *a[10]; };
195 struct s16 *f16() { return malloc(sizeof(struct s16)); }
196 void f16b(struct s16 *p) {}`,
197 body: `p := C.f16(); copy(p.a[:], []*C.char{new(C.char)}); C.f16b(p)`,
202 // A very large value uses a GC program, which is a
203 // different code path.
204 name: "barriergcprogarray",
205 c: `#include <stdlib.h>
206 struct s17 { char *a[32769]; };
207 struct s17 *f17() { return malloc(sizeof(struct s17)); }
208 void f17b(struct s17 *p) {}`,
209 body: `p := C.f17(); p.a = [32769]*C.char{new(C.char)}; C.f17b(p)`,
214 // Similar case, with a source on the heap.
215 name: "barriergcprogarrayheap",
216 c: `#include <stdlib.h>
217 struct s18 { char *a[32769]; };
218 struct s18 *f18() { return malloc(sizeof(struct s18)); }
219 void f18b(struct s18 *p) {}
220 void f18c(void *p) {}`,
221 imports: []string{"unsafe"},
222 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))`,
227 // A GC program with a struct.
228 name: "barriergcprogstruct",
229 c: `#include <stdlib.h>
230 struct s19a { char *a[32769]; };
231 struct s19b { struct s19a f; };
232 struct s19b *f19() { return malloc(sizeof(struct s19b)); }
233 void f19b(struct s19b *p) {}`,
234 body: `p := C.f19(); p.f = C.struct_s19a{[32769]*C.char{new(C.char)}}; C.f19b(p)`,
239 // Similar case, with a source on the heap.
240 name: "barriergcprogstructheap",
241 c: `#include <stdlib.h>
242 struct s20a { char *a[32769]; };
243 struct s20b { struct s20a f; };
244 struct s20b *f20() { return malloc(sizeof(struct s20b)); }
245 void f20b(struct s20b *p) {}
246 void f20c(void *p) {}`,
247 imports: []string{"unsafe"},
248 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))`,
253 // Exported functions may not return Go pointers.
255 c: `extern unsigned char *GoFn21();`,
256 support: `//export GoFn21
257 func GoFn21() *byte { return new(byte) }`,
262 // Returning a C pointer is fine.
264 c: `#include <stdlib.h>
265 extern unsigned char *GoFn22();`,
266 support: `//export GoFn22
267 func GoFn22() *byte { return (*byte)(C.malloc(1)) }`,
271 // Passing a Go string is fine.
273 c: `#include <stddef.h>
274 typedef struct { const char *p; ptrdiff_t n; } gostring23;
275 gostring23 f23(gostring23 s) { return s; }`,
276 imports: []string{"unsafe"},
277 body: `s := "a"; r := C.f23(*(*C.gostring23)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`,
280 // Passing a slice of Go strings fails.
281 name: "passstringslice",
282 c: `void f24(void *p) {}`,
283 imports: []string{"strings", "unsafe"},
284 support: `type S24 struct { a [1]string }`,
285 body: `s := S24{a:[1]string{strings.Repeat("a", 2)}}; C.f24(unsafe.Pointer(&s.a[0]))`,
289 // Exported functions may not return strings.
291 c: `extern void f25();`,
292 imports: []string{"strings"},
293 support: `//export GoStr25
294 func GoStr25() string { return strings.Repeat("a", 2) }`,
296 c1: `#include <stddef.h>
297 typedef struct { const char *p; ptrdiff_t n; } gostring25;
298 extern gostring25 GoStr25();
299 void f25() { GoStr25(); }`,
303 // Don't check non-pointer data.
304 // Uses unsafe code to get a pointer we shouldn't check.
305 // Although we use unsafe, the uintptr represents an integer
306 // that happens to have the same representation as a pointer;
307 // that is, we are testing something that is not unsafe.
309 c: `#include <stdlib.h>
310 void f26(void* p) {}`,
311 imports: []string{"unsafe"},
312 support: `type S26 struct { p *int; a [8*8]byte; u uintptr }`,
313 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))`,
317 // Like ptrdata1, but with a type that uses a GC program.
319 c: `#include <stdlib.h>
320 void f27(void* p) {}`,
321 imports: []string{"unsafe"},
322 support: `type S27 struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
323 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))`,
327 // Check deferred pointers when they are used, not
328 // when the defer statement is run.
330 c: `typedef struct s28 { int *p; } s28; void f28(s28 *ps) {}`,
331 body: `p := &C.s28{}; defer C.f28(p); p.p = new(C.int)`,
335 // Check a pointer to a union if the union has any
338 c: `typedef union { char **p; unsigned long i; } u29; void f29(u29 *pu) {}`,
339 imports: []string{"unsafe"},
340 body: `var b C.char; p := &b; C.f29((*C.u29)(unsafe.Pointer(&p)))`,
344 // Don't check a pointer to a union if the union does
345 // not have any pointer fields.
346 // Like ptrdata1 above, the uintptr represents an
347 // integer that happens to have the same
348 // representation as a pointer.
350 c: `typedef union { unsigned long i; } u39; void f39(u39 *pu) {}`,
351 imports: []string{"unsafe"},
352 body: `var b C.char; p := &b; C.f39((*C.u39)(unsafe.Pointer(&p)))`,
356 // Test preemption while entering a cgo call. Issue #21306.
357 name: "preemptduringcall",
359 imports: []string{"runtime", "sync"},
360 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()`,
364 // Test poller deadline with cgocheck=2. Issue #23435.
366 c: `#define US31 10`,
367 imports: []string{"os", "time"},
368 body: `r, _, _ := os.Pipe(); r.SetDeadline(time.Now().Add(C.US31 * time.Microsecond))`,
372 // Test for double evaluation of channel receive.
374 c: `void f32(char** p) {}`,
375 imports: []string{"time"},
376 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]);`,
380 // Test that converting the address of a struct field
381 // to unsafe.Pointer still just checks that field.
384 c: `void f33(void* p) {}`,
385 imports: []string{"unsafe"},
386 support: `type S33 struct { p *int; a [8]byte; u uintptr }`,
387 body: `s := &S33{p: new(int)}; C.f33(unsafe.Pointer(&s.a))`,
391 // Test that converting multiple struct field
392 // addresses to unsafe.Pointer still just checks those
393 // fields. Issue #25941.
394 name: "structfield2",
395 c: `void f34(void* p, int r, void* s) {}`,
396 imports: []string{"unsafe"},
397 support: `type S34 struct { a [8]byte; p *int; b int64; }`,
398 body: `s := &S34{p: new(int)}; C.f34(unsafe.Pointer(&s.a), 32, unsafe.Pointer(&s.b))`,
402 // Test that second argument to cgoCheckPointer is
403 // evaluated when a deferred function is deferred, not
406 c: `void f35(char **pc) {}`,
407 support: `type S35a struct { s []*C.char }; type S35b struct { ps *S35a }`,
408 body: `p := &S35b{&S35a{[]*C.char{nil}}}; defer C.f35(&p.ps.s[0]); p.ps = nil`,
412 // Test that indexing into a function call still
413 // examines only the slice being indexed.
415 c: `void f36(void *p) {}`,
416 imports: []string{"bytes", "unsafe"},
417 body: `var b bytes.Buffer; b.WriteString("a"); C.f36(unsafe.Pointer(&b.Bytes()[0]))`,
421 // Test that bgsweep releasing a finalizer is OK.
423 c: `// Nothing to declare.`,
424 imports: []string{"os"},
425 support: `func open37() { os.Open(os.Args[0]) }; var G37 [][]byte`,
426 body: `for i := 0; i < 10000; i++ { G37 = append(G37, make([]byte, 4096)); if i % 100 == 0 { G37 = nil; open37() } }`,
430 // Test that converting generated struct to interface is OK.
432 c: `// Nothing to declare.`,
433 imports: []string{"reflect"},
434 support: `type MyInt38 int; func (i MyInt38) Get() int { return int(i) }; type Getter38 interface { Get() int }`,
435 body: `t := reflect.StructOf([]reflect.StructField{{Name: "MyInt38", Type: reflect.TypeOf(MyInt38(0)), Anonymous: true}}); v := reflect.New(t).Elem(); v.Interface().(Getter38).Get()`,
439 // Test that a converted address of a struct field results
440 // in a check for just that field and not the whole struct.
441 name: "structfieldcast",
442 c: `struct S40i { int i; int* p; }; void f40(struct S40i* p) {}`,
443 support: `type S40 struct { p *int; a C.struct_S40i }`,
444 body: `s := &S40{p: new(int)}; C.f40((*C.struct_S40i)(&s.a))`,
449 func TestPointerChecks(t *testing.T) {
450 testenv.MustHaveGoBuild(t)
451 testenv.MustHaveCGO(t)
452 if runtime.GOOS == "windows" {
453 // TODO: Skip just the cases that fail?
454 t.Skipf("some tests fail to build on %s", runtime.GOOS)
463 d, err := os.MkdirTemp("", filepath.Base(t.Name()))
471 exe := buildPtrTests(t, gopath, false)
472 exe2 := buildPtrTests(t, gopath, true)
474 // We (TestPointerChecks) return before the parallel subtest functions do,
475 // so we can't just defer os.RemoveAll(dir). Instead we have to wait for
476 // the parallel subtests to finish. This code looks racy but is not:
477 // the add +1 run in serial before testOne blocks. The -1 run in parallel
478 // after testOne finishes.
480 for _, pt := range ptrTests {
482 t.Run(pt.name, func(t *testing.T) {
483 atomic.AddInt32(&pending, +1)
485 if atomic.AddInt32(&pending, -1) == 0 {
489 testOne(t, pt, exe, exe2)
494 func buildPtrTests(t *testing.T, gopath string, cgocheck2 bool) (exe string) {
496 src := filepath.Join(gopath, "src", "ptrtest")
497 if err := os.MkdirAll(src, 0777); err != nil {
500 if err := os.WriteFile(filepath.Join(src, "go.mod"), []byte("module ptrtest"), 0666); err != nil {
504 // Prepare two cgo inputs: one for standard cgo and one for //export cgo.
505 // (The latter cannot have C definitions, only declarations.)
506 var cgo1, cgo2 bytes.Buffer
507 fmt.Fprintf(&cgo1, "package main\n\n/*\n")
508 fmt.Fprintf(&cgo2, "package main\n\n/*\n")
511 for _, pt := range ptrTests {
513 if strings.Contains(pt.support, "//export") {
516 fmt.Fprintf(cgo, "%s\n", pt.c)
517 fmt.Fprintf(&cgo1, "%s\n", pt.c1)
519 fmt.Fprintf(&cgo1, "*/\nimport \"C\"\n\n")
520 fmt.Fprintf(&cgo2, "*/\nimport \"C\"\n\n")
523 did1 := make(map[string]bool)
524 did2 := make(map[string]bool)
525 did1["os"] = true // for ptrTestMain
526 fmt.Fprintf(&cgo1, "import \"os\"\n")
528 for _, pt := range ptrTests {
531 if strings.Contains(pt.support, "//export") {
535 for _, imp := range pt.imports {
538 fmt.Fprintf(cgo, "import %q\n", imp)
543 // Func support and bodies.
544 for _, pt := range ptrTests {
546 if strings.Contains(pt.support, "//export") {
549 fmt.Fprintf(cgo, "%s\nfunc %s() {\n%s\n}\n", pt.support, pt.name, pt.body)
552 // Func list and main dispatch.
553 fmt.Fprintf(&cgo1, "var funcs = map[string]func() {\n")
554 for _, pt := range ptrTests {
555 fmt.Fprintf(&cgo1, "\t%q: %s,\n", pt.name, pt.name)
557 fmt.Fprintf(&cgo1, "}\n\n")
558 fmt.Fprintf(&cgo1, "%s\n", ptrTestMain)
560 if err := os.WriteFile(filepath.Join(src, "cgo1.go"), cgo1.Bytes(), 0666); err != nil {
563 if err := os.WriteFile(filepath.Join(src, "cgo2.go"), cgo2.Bytes(), 0666); err != nil {
567 exeName := "ptrtest.exe"
569 exeName = "ptrtest2.exe"
571 cmd := exec.Command("go", "build", "-o", exeName)
573 cmd.Env = append(os.Environ(), "GOPATH="+gopath)
576 for i, e := range cmd.Env {
577 if strings.HasPrefix(e, "GOEXPERIMENT=") {
578 cmd.Env[i] = e + ",cgocheck2"
583 cmd.Env = append(cmd.Env, "GOEXPERIMENT=cgocheck2")
586 out, err := cmd.CombinedOutput()
588 t.Fatalf("go build: %v\n%s", err, out)
591 return filepath.Join(src, exeName)
594 const ptrTestMain = `
596 for _, arg := range os.Args[1:] {
599 panic("missing func "+arg)
606 var csem = make(chan bool, 16)
608 func testOne(t *testing.T, pt ptrTest, exe, exe2 string) {
611 // Run the tests in parallel, but don't run too many
612 // executions in parallel, to avoid overloading the system.
613 runcmd := func(cgocheck string) ([]byte, error) {
615 defer func() { <-csem }()
621 cmd := exec.Command(x, pt.name)
622 cmd.Env = append(os.Environ(), "GODEBUG=cgocheck="+cgocheck)
623 return cmd.CombinedOutput()
627 buf, err := runcmd("1")
631 t.Fatalf("test marked expensive, but failed when not expensive: %v", err)
633 t.Errorf("failed unexpectedly with GODEBUG=cgocheck=1: %v", err)
644 buf, err := runcmd(cgocheck)
648 t.Fatalf("did not fail as expected")
649 } else if !bytes.Contains(buf, []byte("Go pointer")) {
651 t.Fatalf("did not print expected error (failed with %v)", err)
656 t.Fatalf("failed unexpectedly: %v", err)
660 // Make sure it passes with the expensive checks.
661 buf, err := runcmd("2")
664 t.Fatalf("failed unexpectedly with expensive checks: %v", err)
670 buf, err := runcmd("0")
673 t.Fatalf("failed unexpectedly with GODEBUG=cgocheck=0: %v", err)