github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/misc/cgo/errors/ptr_test.go (about)

     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.
     4  
     5  // Tests that cgo detects invalid pointer passing at runtime.
     6  
     7  package errorstest
     8  
     9  import (
    10  	"bytes"
    11  	"flag"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"strings"
    18  	"sync/atomic"
    19  	"testing"
    20  )
    21  
    22  var tmp = flag.String("tmp", "", "use `dir` for temporary files and do not clean up")
    23  
    24  // ptrTest is the tests without the boilerplate.
    25  type ptrTest struct {
    26  	name      string   // for reporting
    27  	c         string   // the cgo comment
    28  	c1        string   // cgo comment forced into non-export cgo file
    29  	imports   []string // a list of imports
    30  	support   string   // supporting functions
    31  	body      string   // the body of the main function
    32  	extra     []extra  // extra files
    33  	fail      bool     // whether the test should fail
    34  	expensive bool     // whether the test requires the expensive check
    35  }
    36  
    37  type extra struct {
    38  	name     string
    39  	contents string
    40  }
    41  
    42  var ptrTests = []ptrTest{
    43  	{
    44  		// Passing a pointer to a struct that contains a Go pointer.
    45  		name: "ptr1",
    46  		c:    `typedef struct s1 { int *p; } s1; void f1(s1 *ps) {}`,
    47  		body: `C.f1(&C.s1{new(C.int)})`,
    48  		fail: true,
    49  	},
    50  	{
    51  		// Passing a pointer to a struct that contains a Go pointer.
    52  		name: "ptr2",
    53  		c:    `typedef struct s2 { int *p; } s2; void f2(s2 *ps) {}`,
    54  		body: `p := &C.s2{new(C.int)}; C.f2(p)`,
    55  		fail: true,
    56  	},
    57  	{
    58  		// Passing a pointer to an int field of a Go struct
    59  		// that (irrelevantly) contains a Go pointer.
    60  		name: "ok1",
    61  		c:    `struct s3 { int i; int *p; }; void f3(int *p) {}`,
    62  		body: `p := &C.struct_s3{i: 0, p: new(C.int)}; C.f3(&p.i)`,
    63  		fail: false,
    64  	},
    65  	{
    66  		// Passing a pointer to a pointer field of a Go struct.
    67  		name: "ptrfield",
    68  		c:    `struct s4 { int i; int *p; }; void f4(int **p) {}`,
    69  		body: `p := &C.struct_s4{i: 0, p: new(C.int)}; C.f4(&p.p)`,
    70  		fail: true,
    71  	},
    72  	{
    73  		// Passing a pointer to a pointer field of a Go
    74  		// struct, where the field does not contain a Go
    75  		// pointer, but another field (irrelevantly) does.
    76  		name: "ptrfieldok",
    77  		c:    `struct s5 { int *p1; int *p2; }; void f5(int **p) {}`,
    78  		body: `p := &C.struct_s5{p1: nil, p2: new(C.int)}; C.f5(&p.p1)`,
    79  		fail: false,
    80  	},
    81  	{
    82  		// Passing the address of a slice with no Go pointers.
    83  		name:    "sliceok1",
    84  		c:       `void f6(void **p) {}`,
    85  		imports: []string{"unsafe"},
    86  		body:    `s := []unsafe.Pointer{nil}; C.f6(&s[0])`,
    87  		fail:    false,
    88  	},
    89  	{
    90  		// Passing the address of a slice with a Go pointer.
    91  		name:    "sliceptr1",
    92  		c:       `void f7(void **p) {}`,
    93  		imports: []string{"unsafe"},
    94  		body:    `i := 0; s := []unsafe.Pointer{unsafe.Pointer(&i)}; C.f7(&s[0])`,
    95  		fail:    true,
    96  	},
    97  	{
    98  		// Passing the address of a slice with a Go pointer,
    99  		// where we are passing the address of an element that
   100  		// is not a Go pointer.
   101  		name:    "sliceptr2",
   102  		c:       `void f8(void **p) {}`,
   103  		imports: []string{"unsafe"},
   104  		body:    `i := 0; s := []unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f8(&s[0])`,
   105  		fail:    true,
   106  	},
   107  	{
   108  		// Passing the address of a slice that is an element
   109  		// in a struct only looks at the slice.
   110  		name:    "sliceok2",
   111  		c:       `void f9(void **p) {}`,
   112  		imports: []string{"unsafe"},
   113  		support: `type S9 struct { p *int; s []unsafe.Pointer }`,
   114  		body:    `i := 0; p := &S9{p:&i, s:[]unsafe.Pointer{nil}}; C.f9(&p.s[0])`,
   115  		fail:    false,
   116  	},
   117  	{
   118  		// Passing the address of a slice of an array that is
   119  		// an element in a struct, with a type conversion.
   120  		name:    "sliceok3",
   121  		c:       `void f10(void* p) {}`,
   122  		imports: []string{"unsafe"},
   123  		support: `type S10 struct { p *int; a [4]byte }`,
   124  		body:    `i := 0; p := &S10{p:&i}; s := p.a[:]; C.f10(unsafe.Pointer(&s[0]))`,
   125  		fail:    false,
   126  	},
   127  	{
   128  		// Passing the address of a slice of an array that is
   129  		// an element in a struct, with a type conversion.
   130  		name:    "sliceok4",
   131  		c:       `typedef void* PV11; void f11(PV11 p) {}`,
   132  		imports: []string{"unsafe"},
   133  		support: `type S11 struct { p *int; a [4]byte }`,
   134  		body:    `i := 0; p := &S11{p:&i}; C.f11(C.PV11(unsafe.Pointer(&p.a[0])))`,
   135  		fail:    false,
   136  	},
   137  	{
   138  		// Passing the address of a static variable with no
   139  		// pointers doesn't matter.
   140  		name:    "varok",
   141  		c:       `void f12(char** parg) {}`,
   142  		support: `var hello12 = [...]C.char{'h', 'e', 'l', 'l', 'o'}`,
   143  		body:    `parg := [1]*C.char{&hello12[0]}; C.f12(&parg[0])`,
   144  		fail:    false,
   145  	},
   146  	{
   147  		// Passing the address of a static variable with
   148  		// pointers does matter.
   149  		name:    "var1",
   150  		c:       `void f13(char*** parg) {}`,
   151  		support: `var hello13 = [...]*C.char{new(C.char)}`,
   152  		body:    `parg := [1]**C.char{&hello13[0]}; C.f13(&parg[0])`,
   153  		fail:    true,
   154  	},
   155  	{
   156  		// Storing a Go pointer into C memory should fail.
   157  		name: "barrier",
   158  		c: `#include <stdlib.h>
   159  		    char **f14a() { return malloc(sizeof(char*)); }
   160  		    void f14b(char **p) {}`,
   161  		body:      `p := C.f14a(); *p = new(C.char); C.f14b(p)`,
   162  		fail:      true,
   163  		expensive: true,
   164  	},
   165  	{
   166  		// Storing a Go pointer into C memory by assigning a
   167  		// large value should fail.
   168  		name: "barrierstruct",
   169  		c: `#include <stdlib.h>
   170  		    struct s15 { char *a[10]; };
   171  		    struct s15 *f15() { return malloc(sizeof(struct s15)); }
   172  		    void f15b(struct s15 *p) {}`,
   173  		body:      `p := C.f15(); p.a = [10]*C.char{new(C.char)}; C.f15b(p)`,
   174  		fail:      true,
   175  		expensive: true,
   176  	},
   177  	{
   178  		// Storing a Go pointer into C memory using a slice
   179  		// copy should fail.
   180  		name: "barrierslice",
   181  		c: `#include <stdlib.h>
   182  		    struct s16 { char *a[10]; };
   183  		    struct s16 *f16() { return malloc(sizeof(struct s16)); }
   184  		    void f16b(struct s16 *p) {}`,
   185  		body:      `p := C.f16(); copy(p.a[:], []*C.char{new(C.char)}); C.f16b(p)`,
   186  		fail:      true,
   187  		expensive: true,
   188  	},
   189  	{
   190  		// A very large value uses a GC program, which is a
   191  		// different code path.
   192  		name: "barriergcprogarray",
   193  		c: `#include <stdlib.h>
   194  		    struct s17 { char *a[32769]; };
   195  		    struct s17 *f17() { return malloc(sizeof(struct s17)); }
   196  		    void f17b(struct s17 *p) {}`,
   197  		body:      `p := C.f17(); p.a = [32769]*C.char{new(C.char)}; C.f17b(p)`,
   198  		fail:      true,
   199  		expensive: true,
   200  	},
   201  	{
   202  		// Similar case, with a source on the heap.
   203  		name: "barriergcprogarrayheap",
   204  		c: `#include <stdlib.h>
   205  		    struct s18 { char *a[32769]; };
   206  		    struct s18 *f18() { return malloc(sizeof(struct s18)); }
   207  		    void f18b(struct s18 *p) {}
   208  		    void f18c(void *p) {}`,
   209  		imports:   []string{"unsafe"},
   210  		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))`,
   211  		fail:      true,
   212  		expensive: true,
   213  	},
   214  	{
   215  		// A GC program with a struct.
   216  		name: "barriergcprogstruct",
   217  		c: `#include <stdlib.h>
   218  		    struct s19a { char *a[32769]; };
   219  		    struct s19b { struct s19a f; };
   220  		    struct s19b *f19() { return malloc(sizeof(struct s19b)); }
   221  		    void f19b(struct s19b *p) {}`,
   222  		body:      `p := C.f19(); p.f = C.struct_s19a{[32769]*C.char{new(C.char)}}; C.f19b(p)`,
   223  		fail:      true,
   224  		expensive: true,
   225  	},
   226  	{
   227  		// Similar case, with a source on the heap.
   228  		name: "barriergcprogstructheap",
   229  		c: `#include <stdlib.h>
   230  		    struct s20a { char *a[32769]; };
   231  		    struct s20b { struct s20a f; };
   232  		    struct s20b *f20() { return malloc(sizeof(struct s20b)); }
   233  		    void f20b(struct s20b *p) {}
   234  		    void f20c(void *p) {}`,
   235  		imports:   []string{"unsafe"},
   236  		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))`,
   237  		fail:      true,
   238  		expensive: true,
   239  	},
   240  	{
   241  		// Exported functions may not return Go pointers.
   242  		name: "export1",
   243  		c:    `extern unsigned char *GoFn21();`,
   244  		support: `//export GoFn21
   245  		          func GoFn21() *byte { return new(byte) }`,
   246  		body: `C.GoFn21()`,
   247  		fail: true,
   248  	},
   249  	{
   250  		// Returning a C pointer is fine.
   251  		name: "exportok",
   252  		c: `#include <stdlib.h>
   253  		    extern unsigned char *GoFn22();`,
   254  		support: `//export GoFn22
   255  		          func GoFn22() *byte { return (*byte)(C.malloc(1)) }`,
   256  		body: `C.GoFn22()`,
   257  	},
   258  	{
   259  		// Passing a Go string is fine.
   260  		name: "passstring",
   261  		c: `#include <stddef.h>
   262  		    typedef struct { const char *p; ptrdiff_t n; } gostring23;
   263  		    gostring23 f23(gostring23 s) { return s; }`,
   264  		imports: []string{"unsafe"},
   265  		body:    `s := "a"; r := C.f23(*(*C.gostring23)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`,
   266  	},
   267  	{
   268  		// Passing a slice of Go strings fails.
   269  		name:    "passstringslice",
   270  		c:       `void f24(void *p) {}`,
   271  		imports: []string{"strings", "unsafe"},
   272  		support: `type S24 struct { a [1]string }`,
   273  		body:    `s := S24{a:[1]string{strings.Repeat("a", 2)}}; C.f24(unsafe.Pointer(&s.a[0]))`,
   274  		fail:    true,
   275  	},
   276  	{
   277  		// Exported functions may not return strings.
   278  		name:    "retstring",
   279  		c:       `extern void f25();`,
   280  		imports: []string{"strings"},
   281  		support: `//export GoStr25
   282  		          func GoStr25() string { return strings.Repeat("a", 2) }`,
   283  		body: `C.f25()`,
   284  		c1: `#include <stddef.h>
   285  		     typedef struct { const char *p; ptrdiff_t n; } gostring25;
   286  		     extern gostring25 GoStr25();
   287  		     void f25() { GoStr25(); }`,
   288  		fail: true,
   289  	},
   290  	{
   291  		// Don't check non-pointer data.
   292  		// Uses unsafe code to get a pointer we shouldn't check.
   293  		// Although we use unsafe, the uintptr represents an integer
   294  		// that happens to have the same representation as a pointer;
   295  		// that is, we are testing something that is not unsafe.
   296  		name: "ptrdata1",
   297  		c: `#include <stdlib.h>
   298  		    void f26(void* p) {}`,
   299  		imports: []string{"unsafe"},
   300  		support: `type S26 struct { p *int; a [8*8]byte; u uintptr }`,
   301  		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))`,
   302  		fail:    false,
   303  	},
   304  	{
   305  		// Like ptrdata1, but with a type that uses a GC program.
   306  		name: "ptrdata2",
   307  		c: `#include <stdlib.h>
   308  		    void f27(void* p) {}`,
   309  		imports: []string{"unsafe"},
   310  		support: `type S27 struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
   311  		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))`,
   312  		fail:    false,
   313  	},
   314  	{
   315  		// Check deferred pointers when they are used, not
   316  		// when the defer statement is run.
   317  		name: "defer1",
   318  		c:    `typedef struct s28 { int *p; } s28; void f28(s28 *ps) {}`,
   319  		body: `p := &C.s28{}; defer C.f28(p); p.p = new(C.int)`,
   320  		fail: true,
   321  	},
   322  	{
   323  		// Check a pointer to a union if the union has any
   324  		// pointer fields.
   325  		name:    "union1",
   326  		c:       `typedef union { char **p; unsigned long i; } u29; void f29(u29 *pu) {}`,
   327  		imports: []string{"unsafe"},
   328  		body:    `var b C.char; p := &b; C.f29((*C.u29)(unsafe.Pointer(&p)))`,
   329  		fail:    true,
   330  	},
   331  	{
   332  		// Don't check a pointer to a union if the union does
   333  		// not have any pointer fields.
   334  		// Like ptrdata1 above, the uintptr represents an
   335  		// integer that happens to have the same
   336  		// representation as a pointer.
   337  		name:    "union2",
   338  		c:       `typedef union { unsigned long i; } u39; void f39(u39 *pu) {}`,
   339  		imports: []string{"unsafe"},
   340  		body:    `var b C.char; p := &b; C.f39((*C.u39)(unsafe.Pointer(&p)))`,
   341  		fail:    false,
   342  	},
   343  	{
   344  		// Test preemption while entering a cgo call. Issue #21306.
   345  		name:    "preemptduringcall",
   346  		c:       `void f30() {}`,
   347  		imports: []string{"runtime", "sync"},
   348  		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()`,
   349  		fail:    false,
   350  	},
   351  	{
   352  		// Test poller deadline with cgocheck=2.  Issue #23435.
   353  		name:    "deadline",
   354  		c:       `#define US31 10`,
   355  		imports: []string{"os", "time"},
   356  		body:    `r, _, _ := os.Pipe(); r.SetDeadline(time.Now().Add(C.US31 * time.Microsecond))`,
   357  		fail:    false,
   358  	},
   359  	{
   360  		// Test for double evaluation of channel receive.
   361  		name:    "chanrecv",
   362  		c:       `void f32(char** p) {}`,
   363  		imports: []string{"time"},
   364  		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]);`,
   365  		fail:    false,
   366  	},
   367  	{
   368  		// Test that converting the address of a struct field
   369  		// to unsafe.Pointer still just checks that field.
   370  		// Issue #25941.
   371  		name:    "structfield",
   372  		c:       `void f33(void* p) {}`,
   373  		imports: []string{"unsafe"},
   374  		support: `type S33 struct { p *int; a [8]byte; u uintptr }`,
   375  		body:    `s := &S33{p: new(int)}; C.f33(unsafe.Pointer(&s.a))`,
   376  		fail:    false,
   377  	},
   378  	{
   379  		// Test that converting multiple struct field
   380  		// addresses to unsafe.Pointer still just checks those
   381  		// fields. Issue #25941.
   382  		name:    "structfield2",
   383  		c:       `void f34(void* p, int r, void* s) {}`,
   384  		imports: []string{"unsafe"},
   385  		support: `type S34 struct { a [8]byte; p *int; b int64; }`,
   386  		body:    `s := &S34{p: new(int)}; C.f34(unsafe.Pointer(&s.a), 32, unsafe.Pointer(&s.b))`,
   387  		fail:    false,
   388  	},
   389  	{
   390  		// Test that second argument to cgoCheckPointer is
   391  		// evaluated when a deferred function is deferred, not
   392  		// when it is run.
   393  		name:    "defer2",
   394  		c:       `void f35(char **pc) {}`,
   395  		support: `type S35a struct { s []*C.char }; type S35b struct { ps *S35a }`,
   396  		body:    `p := &S35b{&S35a{[]*C.char{nil}}}; defer C.f35(&p.ps.s[0]); p.ps = nil`,
   397  		fail:    false,
   398  	},
   399  	{
   400  		// Test that indexing into a function call still
   401  		// examines only the slice being indexed.
   402  		name:    "buffer",
   403  		c:       `void f36(void *p) {}`,
   404  		imports: []string{"bytes", "unsafe"},
   405  		body:    `var b bytes.Buffer; b.WriteString("a"); C.f36(unsafe.Pointer(&b.Bytes()[0]))`,
   406  		fail:    false,
   407  	},
   408  	{
   409  		// Test that bgsweep releasing a finalizer is OK.
   410  		name:    "finalizer",
   411  		c:       `// Nothing to declare.`,
   412  		imports: []string{"os"},
   413  		support: `func open37() { os.Open(os.Args[0]) }; var G37 [][]byte`,
   414  		body:    `for i := 0; i < 10000; i++ { G37 = append(G37, make([]byte, 4096)); if i % 100 == 0 { G37 = nil; open37() } }`,
   415  		fail:    false,
   416  	},
   417  	{
   418  		// Test that converting generated struct to interface is OK.
   419  		name:    "structof",
   420  		c:       `// Nothing to declare.`,
   421  		imports: []string{"reflect"},
   422  		support: `type MyInt38 int; func (i MyInt38) Get() int { return int(i) }; type Getter38 interface { Get() int }`,
   423  		body:    `t := reflect.StructOf([]reflect.StructField{{Name: "MyInt38", Type: reflect.TypeOf(MyInt38(0)), Anonymous: true}}); v := reflect.New(t).Elem(); v.Interface().(Getter38).Get()`,
   424  		fail:    false,
   425  	},
   426  	{
   427  		// Test that a converted address of a struct field results
   428  		// in a check for just that field and not the whole struct.
   429  		name:    "structfieldcast",
   430  		c:       `struct S40i { int i; int* p; }; void f40(struct S40i* p) {}`,
   431  		support: `type S40 struct { p *int; a C.struct_S40i }`,
   432  		body:    `s := &S40{p: new(int)}; C.f40((*C.struct_S40i)(&s.a))`,
   433  		fail:    false,
   434  	},
   435  }
   436  
   437  func TestPointerChecks(t *testing.T) {
   438  	dir, exe := buildPtrTests(t)
   439  
   440  	// We (TestPointerChecks) return before the parallel subtest functions do,
   441  	// so we can't just defer os.RemoveAll(dir). Instead we have to wait for
   442  	// the parallel subtests to finish. This code looks racy but is not:
   443  	// the add +1 run in serial before testOne blocks. The -1 run in parallel
   444  	// after testOne finishes.
   445  	var pending int32
   446  	for _, pt := range ptrTests {
   447  		pt := pt
   448  		t.Run(pt.name, func(t *testing.T) {
   449  			atomic.AddInt32(&pending, +1)
   450  			defer func() {
   451  				if atomic.AddInt32(&pending, -1) == 0 {
   452  					os.RemoveAll(dir)
   453  				}
   454  			}()
   455  			testOne(t, pt, exe)
   456  		})
   457  	}
   458  }
   459  
   460  func buildPtrTests(t *testing.T) (dir, exe string) {
   461  	var gopath string
   462  	if *tmp != "" {
   463  		gopath = *tmp
   464  		dir = ""
   465  	} else {
   466  		d, err := ioutil.TempDir("", filepath.Base(t.Name()))
   467  		if err != nil {
   468  			t.Fatal(err)
   469  		}
   470  		dir = d
   471  		gopath = d
   472  	}
   473  
   474  	src := filepath.Join(gopath, "src", "ptrtest")
   475  	if err := os.MkdirAll(src, 0777); err != nil {
   476  		t.Fatal(err)
   477  	}
   478  	if err := ioutil.WriteFile(filepath.Join(src, "go.mod"), []byte("module ptrtest"), 0666); err != nil {
   479  		t.Fatal(err)
   480  	}
   481  
   482  	// Prepare two cgo inputs: one for standard cgo and one for //export cgo.
   483  	// (The latter cannot have C definitions, only declarations.)
   484  	var cgo1, cgo2 bytes.Buffer
   485  	fmt.Fprintf(&cgo1, "package main\n\n/*\n")
   486  	fmt.Fprintf(&cgo2, "package main\n\n/*\n")
   487  
   488  	// C code
   489  	for _, pt := range ptrTests {
   490  		cgo := &cgo1
   491  		if strings.Contains(pt.support, "//export") {
   492  			cgo = &cgo2
   493  		}
   494  		fmt.Fprintf(cgo, "%s\n", pt.c)
   495  		fmt.Fprintf(&cgo1, "%s\n", pt.c1)
   496  	}
   497  	fmt.Fprintf(&cgo1, "*/\nimport \"C\"\n\n")
   498  	fmt.Fprintf(&cgo2, "*/\nimport \"C\"\n\n")
   499  
   500  	// Imports
   501  	did1 := make(map[string]bool)
   502  	did2 := make(map[string]bool)
   503  	did1["os"] = true // for ptrTestMain
   504  	fmt.Fprintf(&cgo1, "import \"os\"\n")
   505  
   506  	for _, pt := range ptrTests {
   507  		did := did1
   508  		cgo := &cgo1
   509  		if strings.Contains(pt.support, "//export") {
   510  			did = did2
   511  			cgo = &cgo2
   512  		}
   513  		for _, imp := range pt.imports {
   514  			if !did[imp] {
   515  				did[imp] = true
   516  				fmt.Fprintf(cgo, "import %q\n", imp)
   517  			}
   518  		}
   519  	}
   520  
   521  	// Func support and bodies.
   522  	for _, pt := range ptrTests {
   523  		cgo := &cgo1
   524  		if strings.Contains(pt.support, "//export") {
   525  			cgo = &cgo2
   526  		}
   527  		fmt.Fprintf(cgo, "%s\nfunc %s() {\n%s\n}\n", pt.support, pt.name, pt.body)
   528  	}
   529  
   530  	// Func list and main dispatch.
   531  	fmt.Fprintf(&cgo1, "var funcs = map[string]func() {\n")
   532  	for _, pt := range ptrTests {
   533  		fmt.Fprintf(&cgo1, "\t%q: %s,\n", pt.name, pt.name)
   534  	}
   535  	fmt.Fprintf(&cgo1, "}\n\n")
   536  	fmt.Fprintf(&cgo1, "%s\n", ptrTestMain)
   537  
   538  	if err := ioutil.WriteFile(filepath.Join(src, "cgo1.go"), cgo1.Bytes(), 0666); err != nil {
   539  		t.Fatal(err)
   540  	}
   541  	if err := ioutil.WriteFile(filepath.Join(src, "cgo2.go"), cgo2.Bytes(), 0666); err != nil {
   542  		t.Fatal(err)
   543  	}
   544  
   545  	cmd := exec.Command("go", "build", "-o", "ptrtest.exe")
   546  	cmd.Dir = src
   547  	cmd.Env = append(os.Environ(), "GOPATH="+gopath)
   548  	out, err := cmd.CombinedOutput()
   549  	if err != nil {
   550  		t.Fatalf("go build: %v\n%s", err, out)
   551  	}
   552  
   553  	return dir, filepath.Join(src, "ptrtest.exe")
   554  }
   555  
   556  const ptrTestMain = `
   557  func main() {
   558  	for _, arg := range os.Args[1:] {
   559  		f := funcs[arg]
   560  		if f == nil {
   561  			panic("missing func "+arg)
   562  		}
   563  		f()
   564  	}
   565  }
   566  `
   567  
   568  var csem = make(chan bool, 16)
   569  
   570  func testOne(t *testing.T, pt ptrTest, exe string) {
   571  	t.Parallel()
   572  
   573  	// Run the tests in parallel, but don't run too many
   574  	// executions in parallel, to avoid overloading the system.
   575  	runcmd := func(cgocheck string) ([]byte, error) {
   576  		csem <- true
   577  		defer func() { <-csem }()
   578  		cmd := exec.Command(exe, pt.name)
   579  		cmd.Env = append(os.Environ(), "GODEBUG=cgocheck="+cgocheck)
   580  		return cmd.CombinedOutput()
   581  	}
   582  
   583  	if pt.expensive {
   584  		buf, err := runcmd("1")
   585  		if err != nil {
   586  			t.Logf("%s", buf)
   587  			if pt.fail {
   588  				t.Fatalf("test marked expensive, but failed when not expensive: %v", err)
   589  			} else {
   590  				t.Errorf("failed unexpectedly with GODEBUG=cgocheck=1: %v", err)
   591  			}
   592  		}
   593  
   594  	}
   595  
   596  	cgocheck := ""
   597  	if pt.expensive {
   598  		cgocheck = "2"
   599  	}
   600  
   601  	buf, err := runcmd(cgocheck)
   602  	if pt.fail {
   603  		if err == nil {
   604  			t.Logf("%s", buf)
   605  			t.Fatalf("did not fail as expected")
   606  		} else if !bytes.Contains(buf, []byte("Go pointer")) {
   607  			t.Logf("%s", buf)
   608  			t.Fatalf("did not print expected error (failed with %v)", err)
   609  		}
   610  	} else {
   611  		if err != nil {
   612  			t.Logf("%s", buf)
   613  			t.Fatalf("failed unexpectedly: %v", err)
   614  		}
   615  
   616  		if !pt.expensive {
   617  			// Make sure it passes with the expensive checks.
   618  			buf, err := runcmd("2")
   619  			if err != nil {
   620  				t.Logf("%s", buf)
   621  				t.Fatalf("failed unexpectedly with expensive checks: %v", err)
   622  			}
   623  		}
   624  	}
   625  
   626  	if pt.fail {
   627  		buf, err := runcmd("0")
   628  		if err != nil {
   629  			t.Logf("%s", buf)
   630  			t.Fatalf("failed unexpectedly with GODEBUG=cgocheck=0: %v", err)
   631  		}
   632  	}
   633  }