ptr_test.go 19 KB

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