summaryrefslogtreecommitdiff
path: root/libgo/misc/cgo/errors
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/misc/cgo/errors')
-rw-r--r--libgo/misc/cgo/errors/err1.go18
-rw-r--r--libgo/misc/cgo/errors/err2.go13
-rw-r--r--libgo/misc/cgo/errors/err3.go18
-rw-r--r--libgo/misc/cgo/errors/issue11097a.go15
-rw-r--r--libgo/misc/cgo/errors/issue11097b.go15
-rw-r--r--libgo/misc/cgo/errors/issue13129.go14
-rw-r--r--libgo/misc/cgo/errors/issue13423.go12
-rw-r--r--libgo/misc/cgo/errors/issue13635.go24
-rw-r--r--libgo/misc/cgo/errors/issue13830.go26
-rw-r--r--libgo/misc/cgo/errors/issue14669.go23
-rw-r--r--libgo/misc/cgo/errors/issue16116.go12
-rw-r--r--libgo/misc/cgo/errors/issue16591.go17
-rw-r--r--libgo/misc/cgo/errors/issue7757.go14
-rw-r--r--libgo/misc/cgo/errors/issue8442.go17
-rw-r--r--libgo/misc/cgo/errors/malloc.go34
-rw-r--r--libgo/misc/cgo/errors/ptr.go576
-rw-r--r--libgo/misc/cgo/errors/test.bash73
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 00000000000..61bbcd29577
--- /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 00000000000..3ab410bbaac
--- /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 00000000000..609e1a0b748
--- /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 00000000000..028d10ce5cb
--- /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 00000000000..b00f24fc103
--- /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 00000000000..f7ad7a7e149
--- /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 00000000000..fc191572376
--- /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 00000000000..0ce2b1e83a1
--- /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 00000000000..ac20c82b81b
--- /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 00000000000..04d2bcb631d
--- /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 00000000000..1e01cab844e
--- /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 00000000000..10eb8403cf8
--- /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 00000000000..0426e9fb7ef
--- /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 00000000000..60477ad345e
--- /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 00000000000..65da0208b97
--- /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 00000000000..4dafbdf3c01
--- /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 00000000000..05261e9d767
--- /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