diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-06-27 04:21:40 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-06-27 04:21:40 +0000 |
commit | 936615752a29ab245708d40782427c25e60a2114 (patch) | |
tree | f43366b59cae9e51da40272eefd1ea71bb3ea055 /libgo/misc/cgo/errors | |
parent | 9913ef5866a64176bac5749080487b0c7d637d4b (diff) | |
download | gcc-936615752a29ab245708d40782427c25e60a2114.zip gcc-936615752a29ab245708d40782427c25e60a2114.tar.gz gcc-936615752a29ab245708d40782427c25e60a2114.tar.bz2 |
libgo: add misc/cgo files
Copy all the misc/cgo files from the gc toolchain into libgo/misc.
These will be used for testing purposes by later changes to the
gotools directory.
Reviewed-on: https://go-review.googlesource.com/46721
From-SVN: r249674
Diffstat (limited to 'libgo/misc/cgo/errors')
-rw-r--r-- | libgo/misc/cgo/errors/err1.go | 18 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/err2.go | 13 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/err3.go | 18 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue11097a.go | 15 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue11097b.go | 15 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue13129.go | 14 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue13423.go | 12 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue13635.go | 24 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue13830.go | 26 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue14669.go | 23 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue16116.go | 12 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue16591.go | 17 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue7757.go | 14 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/issue8442.go | 17 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/malloc.go | 34 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/ptr.go | 576 | ||||
-rw-r--r-- | libgo/misc/cgo/errors/test.bash | 73 |
17 files changed, 921 insertions, 0 deletions
diff --git a/libgo/misc/cgo/errors/err1.go b/libgo/misc/cgo/errors/err1.go new file mode 100644 index 0000000..61bbcd2 --- /dev/null +++ b/libgo/misc/cgo/errors/err1.go @@ -0,0 +1,18 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +#cgo LDFLAGS: -c + +void test() { + xxx; // ERROR HERE +} +*/ +import "C" + +func main() { + C.test() +} diff --git a/libgo/misc/cgo/errors/err2.go b/libgo/misc/cgo/errors/err2.go new file mode 100644 index 0000000..3ab410b --- /dev/null +++ b/libgo/misc/cgo/errors/err2.go @@ -0,0 +1,13 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "C" + +func main() { + s := "" + _ = s + C.malloc(s) // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/err3.go b/libgo/misc/cgo/errors/err3.go new file mode 100644 index 0000000..609e1a0 --- /dev/null +++ b/libgo/misc/cgo/errors/err3.go @@ -0,0 +1,18 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +typedef struct foo foo_t; +typedef struct bar bar_t; + +foo_t *foop; +*/ +import "C" + +func main() { + x := (*C.bar_t)(nil) + C.foop = x // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/issue11097a.go b/libgo/misc/cgo/errors/issue11097a.go new file mode 100644 index 0000000..028d10c --- /dev/null +++ b/libgo/misc/cgo/errors/issue11097a.go @@ -0,0 +1,15 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +//enum test { foo, bar }; +*/ +import "C" + +func main() { + var a = C.enum_test(1) // ERROR HERE + _ = a +} diff --git a/libgo/misc/cgo/errors/issue11097b.go b/libgo/misc/cgo/errors/issue11097b.go new file mode 100644 index 0000000..b00f24f --- /dev/null +++ b/libgo/misc/cgo/errors/issue11097b.go @@ -0,0 +1,15 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +//enum test { foo, bar }; +*/ +import "C" + +func main() { + p := new(C.enum_test) // ERROR HERE + _ = p +} diff --git a/libgo/misc/cgo/errors/issue13129.go b/libgo/misc/cgo/errors/issue13129.go new file mode 100644 index 0000000..f7ad7a7 --- /dev/null +++ b/libgo/misc/cgo/errors/issue13129.go @@ -0,0 +1,14 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// issue 13129: used to output error about C.unsignedshort with CC=clang + +package main + +import "C" + +func main() { + var x C.ushort + x = int(0) // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/issue13423.go b/libgo/misc/cgo/errors/issue13423.go new file mode 100644 index 0000000..fc19157 --- /dev/null +++ b/libgo/misc/cgo/errors/issue13423.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// #include <stdio.h> +import "C" + +func main() { + _ = C.fopen() // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/issue13635.go b/libgo/misc/cgo/errors/issue13635.go new file mode 100644 index 0000000..0ce2b1e --- /dev/null +++ b/libgo/misc/cgo/errors/issue13635.go @@ -0,0 +1,24 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// issue 13635: used to output error about C.unsignedchar. +// This test tests all such types. + +package pkg + +import "C" + +func main() { + var ( + _ C.uchar = "uc" // ERROR HERE + _ C.schar = "sc" // ERROR HERE + _ C.ushort = "us" // ERROR HERE + _ C.uint = "ui" // ERROR HERE + _ C.ulong = "ul" // ERROR HERE + _ C.longlong = "ll" // ERROR HERE + _ C.ulonglong = "ull" // ERROR HERE + _ C.complexfloat = "cf" // ERROR HERE + _ C.complexdouble = "cd" // ERROR HERE + ) +} diff --git a/libgo/misc/cgo/errors/issue13830.go b/libgo/misc/cgo/errors/issue13830.go new file mode 100644 index 0000000..ac20c82 --- /dev/null +++ b/libgo/misc/cgo/errors/issue13830.go @@ -0,0 +1,26 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// cgo converts C void* to Go unsafe.Pointer, so despite appearances C +// void** is Go *unsafe.Pointer. This test verifies that we detect the +// problem at build time. + +package main + +// typedef void v; +// void F(v** p) {} +import "C" + +import "unsafe" + +type v [0]byte + +func f(p **v) { + C.F((**C.v)(unsafe.Pointer(p))) // ERROR HERE +} + +func main() { + var p *v + f(&p) +} diff --git a/libgo/misc/cgo/errors/issue14669.go b/libgo/misc/cgo/errors/issue14669.go new file mode 100644 index 0000000..04d2bcb --- /dev/null +++ b/libgo/misc/cgo/errors/issue14669.go @@ -0,0 +1,23 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 14669: test that fails when build with CGO_CFLAGS selecting +// optimization. + +package p + +/* +const int E = 1; + +typedef struct s { + int c; +} s; +*/ +import "C" + +func F() { + _ = C.s{ + c: C.E, + } +} diff --git a/libgo/misc/cgo/errors/issue16116.go b/libgo/misc/cgo/errors/issue16116.go new file mode 100644 index 0000000..1e01cab --- /dev/null +++ b/libgo/misc/cgo/errors/issue16116.go @@ -0,0 +1,12 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// void f(void *p, int x) {} +import "C" + +func main() { + _ = C.f(1) // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/issue16591.go b/libgo/misc/cgo/errors/issue16591.go new file mode 100644 index 0000000..10eb840 --- /dev/null +++ b/libgo/misc/cgo/errors/issue16591.go @@ -0,0 +1,17 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 16591: Test that we detect an invalid call that was being +// hidden by a type conversion inserted by cgo checking. + +package p + +// void f(int** p) { } +import "C" + +type x *C.int + +func F(p *x) { + C.f(p) // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/issue7757.go b/libgo/misc/cgo/errors/issue7757.go new file mode 100644 index 0000000..0426e9f --- /dev/null +++ b/libgo/misc/cgo/errors/issue7757.go @@ -0,0 +1,14 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +/* +void foo() {} +*/ +import "C" + +func main() { + C.foo = C.foo // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/issue8442.go b/libgo/misc/cgo/errors/issue8442.go new file mode 100644 index 0000000..60477ad --- /dev/null +++ b/libgo/misc/cgo/errors/issue8442.go @@ -0,0 +1,17 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// Issue 8442. Cgo output unhelpful error messages for +// invalid C preambles. + +/* +void issue8442foo(UNDEF*); // ERROR HERE +*/ +import "C" + +func main() { + C.issue8442foo(nil) +} diff --git a/libgo/misc/cgo/errors/malloc.go b/libgo/misc/cgo/errors/malloc.go new file mode 100644 index 0000000..65da0208 --- /dev/null +++ b/libgo/misc/cgo/errors/malloc.go @@ -0,0 +1,34 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that C.malloc does not return nil. + +package main + +// #include <stdlib.h> +import "C" + +import ( + "fmt" + "runtime" +) + +func main() { + var size C.size_t + size-- + + // The Dragonfly libc succeeds when asked to allocate + // 0xffffffffffffffff bytes, so pass a different value that + // causes it to fail. + if runtime.GOOS == "dragonfly" { + size = C.size_t(0x7fffffff << (32 * (^uintptr(0) >> 63))) + } + + p := C.malloc(size) + if p == nil { + fmt.Println("malloc: C.malloc returned nil") + // Just exit normally--the test script expects this + // program to crash, so exiting normally indicates failure. + } +} diff --git a/libgo/misc/cgo/errors/ptr.go b/libgo/misc/cgo/errors/ptr.go new file mode 100644 index 0000000..4dafbdf --- /dev/null +++ b/libgo/misc/cgo/errors/ptr.go @@ -0,0 +1,576 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Tests that cgo detects invalid pointer passing at runtime. + +package main + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "sync" +) + +// ptrTest is the tests without the boilerplate. +type ptrTest struct { + name string // for reporting + c string // the cgo comment + imports []string // a list of imports + support string // supporting functions + body string // the body of the main function + extra []extra // extra files + fail bool // whether the test should fail + expensive bool // whether the test requires the expensive check +} + +type extra struct { + name string + contents string +} + +var ptrTests = []ptrTest{ + { + // Passing a pointer to a struct that contains a Go pointer. + name: "ptr1", + c: `typedef struct s { int *p; } s; void f(s *ps) {}`, + body: `C.f(&C.s{new(C.int)})`, + fail: true, + }, + { + // Passing a pointer to a struct that contains a Go pointer. + name: "ptr2", + c: `typedef struct s { int *p; } s; void f(s *ps) {}`, + body: `p := &C.s{new(C.int)}; C.f(p)`, + fail: true, + }, + { + // Passing a pointer to an int field of a Go struct + // that (irrelevantly) contains a Go pointer. + name: "ok1", + c: `struct s { int i; int *p; }; void f(int *p) {}`, + body: `p := &C.struct_s{i: 0, p: new(C.int)}; C.f(&p.i)`, + fail: false, + }, + { + // Passing a pointer to a pointer field of a Go struct. + name: "ptr-field", + c: `struct s { int i; int *p; }; void f(int **p) {}`, + body: `p := &C.struct_s{i: 0, p: new(C.int)}; C.f(&p.p)`, + fail: true, + }, + { + // Passing a pointer to a pointer field of a Go + // struct, where the field does not contain a Go + // pointer, but another field (irrelevantly) does. + name: "ptr-field-ok", + c: `struct s { int *p1; int *p2; }; void f(int **p) {}`, + body: `p := &C.struct_s{p1: nil, p2: new(C.int)}; C.f(&p.p1)`, + fail: false, + }, + { + // Passing the address of a slice with no Go pointers. + name: "slice-ok-1", + c: `void f(void **p) {}`, + imports: []string{"unsafe"}, + body: `s := []unsafe.Pointer{nil}; C.f(&s[0])`, + fail: false, + }, + { + // Passing the address of a slice with a Go pointer. + name: "slice-ptr-1", + c: `void f(void **p) {}`, + imports: []string{"unsafe"}, + body: `i := 0; s := []unsafe.Pointer{unsafe.Pointer(&i)}; C.f(&s[0])`, + fail: true, + }, + { + // Passing the address of a slice with a Go pointer, + // where we are passing the address of an element that + // is not a Go pointer. + name: "slice-ptr-2", + c: `void f(void **p) {}`, + imports: []string{"unsafe"}, + body: `i := 0; s := []unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f(&s[0])`, + fail: true, + }, + { + // Passing the address of a slice that is an element + // in a struct only looks at the slice. + name: "slice-ok-2", + c: `void f(void **p) {}`, + imports: []string{"unsafe"}, + support: `type S struct { p *int; s []unsafe.Pointer }`, + body: `i := 0; p := &S{p:&i, s:[]unsafe.Pointer{nil}}; C.f(&p.s[0])`, + fail: false, + }, + { + // Passing the address of a slice of an array that is + // an element in a struct, with a type conversion. + name: "slice-ok-3", + c: `void f(void* p) {}`, + imports: []string{"unsafe"}, + support: `type S struct { p *int; a [4]byte }`, + body: `i := 0; p := &S{p:&i}; s := p.a[:]; C.f(unsafe.Pointer(&s[0]))`, + fail: false, + }, + { + // Passing the address of a slice of an array that is + // an element in a struct, with a type conversion. + name: "slice-ok-4", + c: `typedef void* PV; void f(PV p) {}`, + imports: []string{"unsafe"}, + support: `type S struct { p *int; a [4]byte }`, + body: `i := 0; p := &S{p:&i}; C.f(C.PV(unsafe.Pointer(&p.a[0])))`, + fail: false, + }, + { + // Passing the address of a static variable with no + // pointers doesn't matter. + name: "varok", + c: `void f(char** parg) {}`, + support: `var hello = [...]C.char{'h', 'e', 'l', 'l', 'o'}`, + body: `parg := [1]*C.char{&hello[0]}; C.f(&parg[0])`, + fail: false, + }, + { + // Passing the address of a static variable with + // pointers does matter. + name: "var", + c: `void f(char*** parg) {}`, + support: `var hello = [...]*C.char{new(C.char)}`, + body: `parg := [1]**C.char{&hello[0]}; C.f(&parg[0])`, + fail: true, + }, + { + // Storing a Go pointer into C memory should fail. + name: "barrier", + c: `#include <stdlib.h> + char **f1() { return malloc(sizeof(char*)); } + void f2(char **p) {}`, + body: `p := C.f1(); *p = new(C.char); C.f2(p)`, + fail: true, + expensive: true, + }, + { + // Storing a Go pointer into C memory by assigning a + // large value should fail. + name: "barrier-struct", + c: `#include <stdlib.h> + struct s { char *a[10]; }; + struct s *f1() { return malloc(sizeof(struct s)); } + void f2(struct s *p) {}`, + body: `p := C.f1(); p.a = [10]*C.char{new(C.char)}; C.f2(p)`, + fail: true, + expensive: true, + }, + { + // Storing a Go pointer into C memory using a slice + // copy should fail. + name: "barrier-slice", + c: `#include <stdlib.h> + struct s { char *a[10]; }; + struct s *f1() { return malloc(sizeof(struct s)); } + void f2(struct s *p) {}`, + body: `p := C.f1(); copy(p.a[:], []*C.char{new(C.char)}); C.f2(p)`, + fail: true, + expensive: true, + }, + { + // A very large value uses a GC program, which is a + // different code path. + name: "barrier-gcprog-array", + c: `#include <stdlib.h> + struct s { char *a[32769]; }; + struct s *f1() { return malloc(sizeof(struct s)); } + void f2(struct s *p) {}`, + body: `p := C.f1(); p.a = [32769]*C.char{new(C.char)}; C.f2(p)`, + fail: true, + expensive: true, + }, + { + // Similar case, with a source on the heap. + name: "barrier-gcprog-array-heap", + c: `#include <stdlib.h> + struct s { char *a[32769]; }; + struct s *f1() { return malloc(sizeof(struct s)); } + void f2(struct s *p) {} + void f3(void *p) {}`, + imports: []string{"unsafe"}, + body: `p := C.f1(); n := &[32769]*C.char{new(C.char)}; p.a = *n; C.f2(p); n[0] = nil; C.f3(unsafe.Pointer(n))`, + fail: true, + expensive: true, + }, + { + // A GC program with a struct. + name: "barrier-gcprog-struct", + c: `#include <stdlib.h> + struct s { char *a[32769]; }; + struct s2 { struct s f; }; + struct s2 *f1() { return malloc(sizeof(struct s2)); } + void f2(struct s2 *p) {}`, + body: `p := C.f1(); p.f = C.struct_s{[32769]*C.char{new(C.char)}}; C.f2(p)`, + fail: true, + expensive: true, + }, + { + // Similar case, with a source on the heap. + name: "barrier-gcprog-struct-heap", + c: `#include <stdlib.h> + struct s { char *a[32769]; }; + struct s2 { struct s f; }; + struct s2 *f1() { return malloc(sizeof(struct s2)); } + void f2(struct s2 *p) {} + void f3(void *p) {}`, + imports: []string{"unsafe"}, + body: `p := C.f1(); n := &C.struct_s{[32769]*C.char{new(C.char)}}; p.f = *n; C.f2(p); n.a[0] = nil; C.f3(unsafe.Pointer(n))`, + fail: true, + expensive: true, + }, + { + // Exported functions may not return Go pointers. + name: "export1", + c: `extern unsigned char *GoFn();`, + support: `//export GoFn + func GoFn() *byte { return new(byte) }`, + body: `C.GoFn()`, + fail: true, + }, + { + // Returning a C pointer is fine. + name: "exportok", + c: `#include <stdlib.h> + extern unsigned char *GoFn();`, + support: `//export GoFn + func GoFn() *byte { return (*byte)(C.malloc(1)) }`, + body: `C.GoFn()`, + }, + { + // Passing a Go string is fine. + name: "pass-string", + c: `#include <stddef.h> + typedef struct { const char *p; ptrdiff_t n; } gostring; + gostring f(gostring s) { return s; }`, + imports: []string{"unsafe"}, + body: `s := "a"; r := C.f(*(*C.gostring)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`, + }, + { + // Passing a slice of Go strings fails. + name: "pass-string-slice", + c: `void f(void *p) {}`, + imports: []string{"strings", "unsafe"}, + support: `type S struct { a [1]string }`, + body: `s := S{a:[1]string{strings.Repeat("a", 2)}}; C.f(unsafe.Pointer(&s.a[0]))`, + fail: true, + }, + { + // Exported functions may not return strings. + name: "ret-string", + c: `extern void f();`, + imports: []string{"strings"}, + support: `//export GoStr + func GoStr() string { return strings.Repeat("a", 2) }`, + body: `C.f()`, + extra: []extra{ + { + "call.c", + `#include <stddef.h> + typedef struct { const char *p; ptrdiff_t n; } gostring; + extern gostring GoStr(); + void f() { GoStr(); }`, + }, + }, + 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, + }, + { + // Check deferred pointers when they are used, not + // when the defer statement is run. + name: "defer", + c: `typedef struct s { int *p; } s; void f(s *ps) {}`, + body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`, + fail: true, + }, + { + // Check a pointer to a union if the union has any + // pointer fields. + name: "union1", + c: `typedef union { char **p; unsigned long i; } u; void f(u *pu) {}`, + imports: []string{"unsafe"}, + body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`, + fail: true, + }, + { + // Don't check a pointer to a union if the union does + // not have any pointer fields. + // Like ptrdata1 above, the uintptr represents an + // integer that happens to have the same + // representation as a pointer. + name: "union2", + c: `typedef union { unsigned long i; } u; void f(u *pu) {}`, + imports: []string{"unsafe"}, + body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`, + fail: false, + }, +} + +func main() { + os.Exit(doTests()) +} + +func doTests() int { + gopath, err := ioutil.TempDir("", "cgoerrors") + if err != nil { + fmt.Fprintln(os.Stderr, err) + return 2 + } + defer os.RemoveAll(gopath) + + if err := os.MkdirAll(filepath.Join(gopath, "src"), 0777); err != nil { + fmt.Fprintln(os.Stderr, err) + return 2 + } + + workers := runtime.NumCPU() + 1 + + var wg sync.WaitGroup + c := make(chan int) + errs := make(chan int) + for i := 0; i < workers; i++ { + wg.Add(1) + go func() { + worker(gopath, c, errs) + wg.Done() + }() + } + + for i := range ptrTests { + c <- i + } + close(c) + + go func() { + wg.Wait() + close(errs) + }() + + tot := 0 + for e := range errs { + tot += e + } + return tot +} + +func worker(gopath string, c, errs chan int) { + e := 0 + for i := range c { + if !doOne(gopath, i) { + e++ + } + } + if e > 0 { + errs <- e + } +} + +func doOne(gopath string, i int) bool { + t := &ptrTests[i] + + dir := filepath.Join(gopath, "src", fmt.Sprintf("dir%d", i)) + if err := os.Mkdir(dir, 0777); err != nil { + fmt.Fprintln(os.Stderr, err) + return false + } + + name := filepath.Join(dir, fmt.Sprintf("t%d.go", i)) + f, err := os.Create(name) + if err != nil { + fmt.Fprintln(os.Stderr, err) + return false + } + + b := bufio.NewWriter(f) + fmt.Fprintln(b, `package main`) + fmt.Fprintln(b) + fmt.Fprintln(b, `/*`) + fmt.Fprintln(b, t.c) + fmt.Fprintln(b, `*/`) + fmt.Fprintln(b, `import "C"`) + fmt.Fprintln(b) + for _, imp := range t.imports { + fmt.Fprintln(b, `import "`+imp+`"`) + } + if len(t.imports) > 0 { + fmt.Fprintln(b) + } + if len(t.support) > 0 { + fmt.Fprintln(b, t.support) + fmt.Fprintln(b) + } + fmt.Fprintln(b, `func main() {`) + fmt.Fprintln(b, t.body) + fmt.Fprintln(b, `}`) + + if err := b.Flush(); err != nil { + fmt.Fprintf(os.Stderr, "flushing %s: %v\n", name, err) + return false + } + if err := f.Close(); err != nil { + fmt.Fprintf(os.Stderr, "closing %s: %v\n", name, err) + return false + } + + for _, e := range t.extra { + if err := ioutil.WriteFile(filepath.Join(dir, e.name), []byte(e.contents), 0644); err != nil { + fmt.Fprintf(os.Stderr, "writing %s: %v\n", e.name, err) + return false + } + } + + ok := true + + cmd := exec.Command("go", "build") + cmd.Dir = dir + cmd.Env = addEnv("GOPATH", gopath) + buf, err := cmd.CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "test %s failed to build: %v\n%s", t.name, err, buf) + return false + } + + exe := filepath.Join(dir, filepath.Base(dir)) + cmd = exec.Command(exe) + cmd.Dir = dir + + if t.expensive { + cmd.Env = cgocheckEnv("1") + buf, err := cmd.CombinedOutput() + if err != nil { + var errbuf bytes.Buffer + if t.fail { + fmt.Fprintf(&errbuf, "test %s marked expensive but failed when not expensive: %v\n", t.name, err) + } else { + fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=1: %v\n", t.name, err) + } + reportTestOutput(&errbuf, t.name, buf) + os.Stderr.Write(errbuf.Bytes()) + ok = false + } + + cmd = exec.Command(exe) + cmd.Dir = dir + } + + if t.expensive { + cmd.Env = cgocheckEnv("2") + } + + buf, err = cmd.CombinedOutput() + + if t.fail { + if err == nil { + var errbuf bytes.Buffer + fmt.Fprintf(&errbuf, "test %s did not fail as expected\n", t.name) + reportTestOutput(&errbuf, t.name, buf) + os.Stderr.Write(errbuf.Bytes()) + ok = false + } else if !bytes.Contains(buf, []byte("Go pointer")) { + var errbuf bytes.Buffer + fmt.Fprintf(&errbuf, "test %s output does not contain expected error (failed with %v)\n", t.name, err) + reportTestOutput(&errbuf, t.name, buf) + os.Stderr.Write(errbuf.Bytes()) + ok = false + } + } else { + if err != nil { + var errbuf bytes.Buffer + fmt.Fprintf(&errbuf, "test %s failed unexpectedly: %v\n", t.name, err) + reportTestOutput(&errbuf, t.name, buf) + os.Stderr.Write(errbuf.Bytes()) + ok = false + } + + if !t.expensive && ok { + // Make sure it passes with the expensive checks. + cmd := exec.Command(exe) + cmd.Dir = dir + cmd.Env = cgocheckEnv("2") + buf, err := cmd.CombinedOutput() + if err != nil { + var errbuf bytes.Buffer + fmt.Fprintf(&errbuf, "test %s failed unexpectedly with expensive checks: %v\n", t.name, err) + reportTestOutput(&errbuf, t.name, buf) + os.Stderr.Write(errbuf.Bytes()) + ok = false + } + } + } + + if t.fail && ok { + cmd = exec.Command(exe) + cmd.Dir = dir + cmd.Env = cgocheckEnv("0") + buf, err := cmd.CombinedOutput() + if err != nil { + var errbuf bytes.Buffer + fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=0: %v\n", t.name, err) + reportTestOutput(&errbuf, t.name, buf) + os.Stderr.Write(errbuf.Bytes()) + ok = false + } + } + + return ok +} + +func reportTestOutput(w io.Writer, name string, buf []byte) { + fmt.Fprintf(w, "=== test %s output ===\n", name) + fmt.Fprintf(w, "%s", buf) + fmt.Fprintf(w, "=== end of test %s output ===\n", name) +} + +func cgocheckEnv(val string) []string { + return addEnv("GODEBUG", "cgocheck="+val) +} + +func addEnv(key, val string) []string { + env := []string{key + "=" + val} + look := key + "=" + for _, e := range os.Environ() { + if !strings.HasPrefix(e, look) { + env = append(env, e) + } + } + return env +} diff --git a/libgo/misc/cgo/errors/test.bash b/libgo/misc/cgo/errors/test.bash new file mode 100644 index 0000000..05261e9 --- /dev/null +++ b/libgo/misc/cgo/errors/test.bash @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +# Copyright 2013 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +check() { + file=$1 + line=$(grep -n 'ERROR HERE' $file | sed 's/:.*//') + if [ "$line" = "" ]; then + echo 1>&2 misc/cgo/errors/test.bash: BUG: cannot find ERROR HERE in $file + exit 1 + fi + expect $file $file:$line: +} + +expect() { + file=$1 + shift + if go build $file >errs 2>&1; then + echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded + exit 1 + fi + if ! test -s errs; then + echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file but saw none + exit 1 + fi + for error; do + if ! fgrep $error errs >/dev/null 2>&1; then + echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file to contain \"$error\" but saw: + cat 1>&2 errs + exit 1 + fi + done +} + +check err1.go +check err2.go +check err3.go +check issue7757.go +check issue8442.go +check issue11097a.go +check issue11097b.go +expect issue13129.go C.ushort +check issue13423.go +expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble +check issue13830.go +check issue16116.go +check issue16591.go + +if ! go build issue14669.go; then + exit 1 +fi +if ! CGO_CFLAGS="-O" go build issue14669.go; then + exit 1 +fi + +if ! go run ptr.go; then + exit 1 +fi + +# The malloc.go test should crash. +rm -f malloc.out +if go run malloc.go >malloc.out 2>&1; then + echo '`go run malloc.go` succeeded unexpectedly' + cat malloc.out + rm -f malloc.out + exit 1 +fi +rm -f malloc.out + +rm -rf errs _obj +exit 0 |