From: Ian Lance Taylor Date: Tue, 27 Jun 2017 04:21:40 +0000 (+0000) Subject: libgo: add misc/cgo files X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=936615752a29ab245708d40782427c25e60a2114;p=gcc.git 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 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 38f08feddf7..583d6032e93 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -bfb18fb16194826bf2bf2d7af873719ddb5e8e42 +040dc31406d580e33f82e578a840600fea5004ef The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/merge.sh b/libgo/merge.sh index bdf0043f12b..bc24504e2a0 100755 --- a/libgo/merge.sh +++ b/libgo/merge.sh @@ -182,6 +182,13 @@ done done done +(cd ${NEWDIR}/misc/cgo && find . -type f -print) | while read f; do + oldfile=${OLDDIR}/misc/cgo/$f + newfile=${NEWDIR}/misc/cgo/$f + libgofile=misc/cgo/$f + merge $f ${oldfile} ${newfile} ${libgofile} +done + (cd ${OLDDIR}/src && find . -name '*.go' -print) | while read f; do oldfile=${OLDDIR}/src/$f newfile=${NEWDIR}/src/$f @@ -197,5 +204,20 @@ done git rm ${libgofile} done +(cd ${OLDDIR}/misc/cgo && find . -type f -print) | while read f; do + oldfile=${OLDDIR}/misc/cgo/$f + newfile=${NEWDIR}/misc/cgo/$f + libgofile=misc/cgo/$f + if test -f ${newfile}; then + continue + fi + if ! test -f ${libgofile}; then + continue + fi + echo "merge.sh: ${libgofile}: REMOVED" + rm -f ${libgofile} + git rm ${libgofile} +done + (echo ${new_rev}; sed -ne '2,$p' MERGE) > MERGE.tmp mv MERGE.tmp MERGE 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 +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 +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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 diff --git a/libgo/misc/cgo/fortran/answer.f90 b/libgo/misc/cgo/fortran/answer.f90 new file mode 100644 index 00000000000..b3717ee27a6 --- /dev/null +++ b/libgo/misc/cgo/fortran/answer.f90 @@ -0,0 +1,9 @@ +! 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. + +function the_answer() result(j) bind(C) + use iso_c_binding, only: c_int + integer(c_int) :: j ! output + j = 42 +end function the_answer diff --git a/libgo/misc/cgo/fortran/fortran.go b/libgo/misc/cgo/fortran/fortran.go new file mode 100644 index 00000000000..0079b535d94 --- /dev/null +++ b/libgo/misc/cgo/fortran/fortran.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 fortran + +// int the_answer(); +import "C" + +func TheAnswer() int { + return int(C.the_answer()) +} diff --git a/libgo/misc/cgo/fortran/fortran_test.go b/libgo/misc/cgo/fortran/fortran_test.go new file mode 100644 index 00000000000..d0cb9f22463 --- /dev/null +++ b/libgo/misc/cgo/fortran/fortran_test.go @@ -0,0 +1,13 @@ +// 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 fortran + +import "testing" + +func TestFortran(t *testing.T) { + if a := TheAnswer(); a != 42 { + t.Errorf("Unexpected result for The Answer. Got: %d Want: 42", a) + } +} diff --git a/libgo/misc/cgo/fortran/helloworld/helloworld.f90 b/libgo/misc/cgo/fortran/helloworld/helloworld.f90 new file mode 100644 index 00000000000..cbc34c16ef7 --- /dev/null +++ b/libgo/misc/cgo/fortran/helloworld/helloworld.f90 @@ -0,0 +1,3 @@ + program HelloWorldF90 + write(*,*) "Hello World!" + end program HelloWorldF90 diff --git a/libgo/misc/cgo/fortran/test.bash b/libgo/misc/cgo/fortran/test.bash new file mode 100644 index 00000000000..3d1bc9de8e9 --- /dev/null +++ b/libgo/misc/cgo/fortran/test.bash @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# 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. + +# This directory is intended to test the use of Fortran with cgo. + +set -e + +FC=$1 + +goos=$(go env GOOS) + +libext="so" +if [ "$goos" == "darwin" ]; then + libext="dylib" +fi + +case "$FC" in +*gfortran*) + libpath=$(dirname $($FC -print-file-name=libgfortran.$libext)) + export CGO_LDFLAGS="$CGO_LDFLAGS -Wl,-rpath,$libpath -L $libpath" + ;; +esac + +if ! $FC helloworld/helloworld.f90 -o main.exe >& /dev/null; then + echo "skipping Fortran test: could not build helloworld.f90 with $FC" + exit 0 +fi +rm -f main.exe + +status=0 + +if ! go test; then + echo "FAIL: go test" + status=1 +fi + +exit $status diff --git a/libgo/misc/cgo/gmp/fib.go b/libgo/misc/cgo/gmp/fib.go new file mode 100644 index 00000000000..f1091b1c54f --- /dev/null +++ b/libgo/misc/cgo/gmp/fib.go @@ -0,0 +1,45 @@ +// Copyright 2009 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. + +// +build ignore + +// Compute Fibonacci numbers with two goroutines +// that pass integers back and forth. No actual +// concurrency, just threads and synchronization +// and foreign code on multiple pthreads. + +package main + +import ( + big "." + "runtime" +) + +func fibber(c chan *big.Int, out chan string, n int64) { + // Keep the fibbers in dedicated operating system + // threads, so that this program tests coordination + // between pthreads and not just goroutines. + runtime.LockOSThread() + + i := big.NewInt(n) + if n == 0 { + c <- i + } + for { + j := <-c + out <- j.String() + i.Add(i, j) + c <- i + } +} + +func main() { + c := make(chan *big.Int) + out := make(chan string) + go fibber(c, out, 0) + go fibber(c, out, 1) + for i := 0; i < 200; i++ { + println(<-out) + } +} diff --git a/libgo/misc/cgo/gmp/gmp.go b/libgo/misc/cgo/gmp/gmp.go new file mode 100644 index 00000000000..971a10aaac6 --- /dev/null +++ b/libgo/misc/cgo/gmp/gmp.go @@ -0,0 +1,380 @@ +// Copyright 2009 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. + +/* +An example of wrapping a C library in Go. This is the GNU +multiprecision library gmp's integer type mpz_t wrapped to look like +the Go package big's integer type Int. + +This is a syntactically valid Go program—it can be parsed with the Go +parser and processed by godoc—but it is not compiled directly by gc. +Instead, a separate tool, cgo, processes it to produce three output +files. The first two, 6g.go and 6c.c, are a Go source file for 6g and +a C source file for 6c; both compile as part of the named package +(gmp, in this example). The third, gcc.c, is a C source file for gcc; +it compiles into a shared object (.so) that is dynamically linked into +any 6.out that imports the first two files. + +The stanza + + // #include + import "C" + +is a signal to cgo. The doc comment on the import of "C" provides +additional context for the C file. Here it is just a single #include +but it could contain arbitrary C definitions to be imported and used. + +Cgo recognizes any use of a qualified identifier C.xxx and uses gcc to +find the definition of xxx. If xxx is a type, cgo replaces C.xxx with +a Go translation. C arithmetic types translate to precisely-sized Go +arithmetic types. A C struct translates to a Go struct, field by +field; unrepresentable fields are replaced with opaque byte arrays. A +C union translates into a struct containing the first union member and +perhaps additional padding. C arrays become Go arrays. C pointers +become Go pointers. C function pointers become Go's uintptr. +C void pointers become Go's unsafe.Pointer. + +For example, mpz_t is defined in as: + + typedef unsigned long int mp_limb_t; + + typedef struct + { + int _mp_alloc; + int _mp_size; + mp_limb_t *_mp_d; + } __mpz_struct; + + typedef __mpz_struct mpz_t[1]; + +Cgo generates: + + type _C_int int32 + type _C_mp_limb_t uint64 + type _C___mpz_struct struct { + _mp_alloc _C_int; + _mp_size _C_int; + _mp_d *_C_mp_limb_t; + } + type _C_mpz_t [1]_C___mpz_struct + +and then replaces each occurrence of a type C.xxx with _C_xxx. + +If xxx is data, cgo arranges for C.xxx to refer to the C variable, +with the type translated as described above. To do this, cgo must +introduce a Go variable that points at the C variable (the linker can +be told to initialize this pointer). For example, if the gmp library +provided + + mpz_t zero; + +then cgo would rewrite a reference to C.zero by introducing + + var _C_zero *C.mpz_t + +and then replacing all instances of C.zero with (*_C_zero). + +Cgo's most interesting translation is for functions. If xxx is a C +function, then cgo rewrites C.xxx into a new function _C_xxx that +calls the C xxx in a standard pthread. The new function translates +its arguments, calls xxx, and translates the return value. + +Translation of parameters and the return value follows the type +translation above except that arrays passed as parameters translate +explicitly in Go to pointers to arrays, as they do (implicitly) in C. + +Garbage collection is the big problem. It is fine for the Go world to +have pointers into the C world and to free those pointers when they +are no longer needed. To help, the Go code can define Go objects +holding the C pointers and use runtime.SetFinalizer on those Go objects. + +It is much more difficult for the C world to have pointers into the Go +world, because the Go garbage collector is unaware of the memory +allocated by C. The most important consideration is not to +constrain future implementations, so the rule is that Go code can +hand a Go pointer to C code but must separately arrange for +Go to hang on to a reference to the pointer until C is done with it. +*/ +package gmp + +/* +#cgo LDFLAGS: -lgmp +#include +#include + +// gmp 5.0.0+ changed the type of the 3rd argument to mp_bitcnt_t, +// so, to support older versions, we wrap these two functions. +void _mpz_mul_2exp(mpz_ptr a, mpz_ptr b, unsigned long n) { + mpz_mul_2exp(a, b, n); +} +void _mpz_div_2exp(mpz_ptr a, mpz_ptr b, unsigned long n) { + mpz_div_2exp(a, b, n); +} +*/ +import "C" + +import ( + "os" + "unsafe" +) + +/* + * one of a kind + */ + +// An Int represents a signed multi-precision integer. +// The zero value for an Int represents the value 0. +type Int struct { + i C.mpz_t + init bool +} + +// NewInt returns a new Int initialized to x. +func NewInt(x int64) *Int { return new(Int).SetInt64(x) } + +// Int promises that the zero value is a 0, but in gmp +// the zero value is a crash. To bridge the gap, the +// init bool says whether this is a valid gmp value. +// doinit initializes z.i if it needs it. This is not inherent +// to FFI, just a mismatch between Go's convention of +// making zero values useful and gmp's decision not to. +func (z *Int) doinit() { + if z.init { + return + } + z.init = true + C.mpz_init(&z.i[0]) +} + +// Bytes returns z's representation as a big-endian byte array. +func (z *Int) Bytes() []byte { + b := make([]byte, (z.Len()+7)/8) + n := C.size_t(len(b)) + C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0]) + return b[0:n] +} + +// Len returns the length of z in bits. 0 is considered to have length 1. +func (z *Int) Len() int { + z.doinit() + return int(C.mpz_sizeinbase(&z.i[0], 2)) +} + +// Set sets z = x and returns z. +func (z *Int) Set(x *Int) *Int { + z.doinit() + C.mpz_set(&z.i[0], &x.i[0]) + return z +} + +// SetBytes interprets b as the bytes of a big-endian integer +// and sets z to that value. +func (z *Int) SetBytes(b []byte) *Int { + z.doinit() + if len(b) == 0 { + z.SetInt64(0) + } else { + C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0])) + } + return z +} + +// SetInt64 sets z = x and returns z. +func (z *Int) SetInt64(x int64) *Int { + z.doinit() + // TODO(rsc): more work on 32-bit platforms + C.mpz_set_si(&z.i[0], C.long(x)) + return z +} + +// SetString interprets s as a number in the given base +// and sets z to that value. The base must be in the range [2,36]. +// SetString returns an error if s cannot be parsed or the base is invalid. +func (z *Int) SetString(s string, base int) error { + z.doinit() + if base < 2 || base > 36 { + return os.ErrInvalid + } + p := C.CString(s) + defer C.free(unsafe.Pointer(p)) + if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 { + return os.ErrInvalid + } + return nil +} + +// String returns the decimal representation of z. +func (z *Int) String() string { + if z == nil { + return "nil" + } + z.doinit() + p := C.mpz_get_str(nil, 10, &z.i[0]) + s := C.GoString(p) + C.free(unsafe.Pointer(p)) + return s +} + +func (z *Int) destroy() { + if z.init { + C.mpz_clear(&z.i[0]) + } + z.init = false +} + +/* + * arithmetic + */ + +// Add sets z = x + y and returns z. +func (z *Int) Add(x, y *Int) *Int { + x.doinit() + y.doinit() + z.doinit() + C.mpz_add(&z.i[0], &x.i[0], &y.i[0]) + return z +} + +// Sub sets z = x - y and returns z. +func (z *Int) Sub(x, y *Int) *Int { + x.doinit() + y.doinit() + z.doinit() + C.mpz_sub(&z.i[0], &x.i[0], &y.i[0]) + return z +} + +// Mul sets z = x * y and returns z. +func (z *Int) Mul(x, y *Int) *Int { + x.doinit() + y.doinit() + z.doinit() + C.mpz_mul(&z.i[0], &x.i[0], &y.i[0]) + return z +} + +// Div sets z = x / y, rounding toward zero, and returns z. +func (z *Int) Div(x, y *Int) *Int { + x.doinit() + y.doinit() + z.doinit() + C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0]) + return z +} + +// Mod sets z = x % y and returns z. +// Like the result of the Go % operator, z has the same sign as x. +func (z *Int) Mod(x, y *Int) *Int { + x.doinit() + y.doinit() + z.doinit() + C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0]) + return z +} + +// Lsh sets z = x << s and returns z. +func (z *Int) Lsh(x *Int, s uint) *Int { + x.doinit() + z.doinit() + C._mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s)) + return z +} + +// Rsh sets z = x >> s and returns z. +func (z *Int) Rsh(x *Int, s uint) *Int { + x.doinit() + z.doinit() + C._mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s)) + return z +} + +// Exp sets z = x^y % m and returns z. +// If m == nil, Exp sets z = x^y. +func (z *Int) Exp(x, y, m *Int) *Int { + m.doinit() + x.doinit() + y.doinit() + z.doinit() + if m == nil { + C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0])) + } else { + C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0]) + } + return z +} + +func (z *Int) Int64() int64 { + if !z.init { + return 0 + } + return int64(C.mpz_get_si(&z.i[0])) +} + +// Neg sets z = -x and returns z. +func (z *Int) Neg(x *Int) *Int { + x.doinit() + z.doinit() + C.mpz_neg(&z.i[0], &x.i[0]) + return z +} + +// Abs sets z to the absolute value of x and returns z. +func (z *Int) Abs(x *Int) *Int { + x.doinit() + z.doinit() + C.mpz_abs(&z.i[0], &x.i[0]) + return z +} + +/* + * functions without a clear receiver + */ + +// CmpInt compares x and y. The result is +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +// +func CmpInt(x, y *Int) int { + x.doinit() + y.doinit() + switch cmp := C.mpz_cmp(&x.i[0], &y.i[0]); { + case cmp < 0: + return -1 + case cmp == 0: + return 0 + } + return +1 +} + +// DivModInt sets q = x / y and r = x % y. +func DivModInt(q, r, x, y *Int) { + q.doinit() + r.doinit() + x.doinit() + y.doinit() + C.mpz_tdiv_qr(&q.i[0], &r.i[0], &x.i[0], &y.i[0]) +} + +// GcdInt sets d to the greatest common divisor of a and b, +// which must be positive numbers. +// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y. +// If either a or b is not positive, GcdInt sets d = x = y = 0. +func GcdInt(d, x, y, a, b *Int) { + d.doinit() + x.doinit() + y.doinit() + a.doinit() + b.doinit() + C.mpz_gcdext(&d.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0]) +} + +// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime. +// If it returns true, z is prime with probability 1 - 1/4^n. +// If it returns false, z is not prime. +func (z *Int) ProbablyPrime(n int) bool { + z.doinit() + return int(C.mpz_probab_prime_p(&z.i[0], C.int(n))) > 0 +} diff --git a/libgo/misc/cgo/gmp/pi.go b/libgo/misc/cgo/gmp/pi.go new file mode 100644 index 00000000000..d5851e8e6bd --- /dev/null +++ b/libgo/misc/cgo/gmp/pi.go @@ -0,0 +1,73 @@ +// Copyright 2009 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. + +// +build ignore + +package main + +import ( + big "." + "fmt" + "runtime" +) + +var ( + tmp1 = big.NewInt(0) + tmp2 = big.NewInt(0) + numer = big.NewInt(1) + accum = big.NewInt(0) + denom = big.NewInt(1) + ten = big.NewInt(10) +) + +func extractDigit() int64 { + if big.CmpInt(numer, accum) > 0 { + return -1 + } + tmp1.Lsh(numer, 1).Add(tmp1, numer).Add(tmp1, accum) + big.DivModInt(tmp1, tmp2, tmp1, denom) + tmp2.Add(tmp2, numer) + if big.CmpInt(tmp2, denom) >= 0 { + return -1 + } + return tmp1.Int64() +} + +func nextTerm(k int64) { + y2 := k*2 + 1 + accum.Add(accum, tmp1.Lsh(numer, 1)) + accum.Mul(accum, tmp1.SetInt64(y2)) + numer.Mul(numer, tmp1.SetInt64(k)) + denom.Mul(denom, tmp1.SetInt64(y2)) +} + +func eliminateDigit(d int64) { + accum.Sub(accum, tmp1.Mul(denom, tmp1.SetInt64(d))) + accum.Mul(accum, ten) + numer.Mul(numer, ten) +} + +func main() { + i := 0 + k := int64(0) + for { + d := int64(-1) + for d < 0 { + k++ + nextTerm(k) + d = extractDigit() + } + eliminateDigit(d) + fmt.Printf("%c", d+'0') + + if i++; i%50 == 0 { + fmt.Printf("\n") + if i >= 1000 { + break + } + } + } + + fmt.Printf("\n%d calls; bit sizes: %d %d %d\n", runtime.NumCgoCall(), numer.Len(), accum.Len(), denom.Len()) +} diff --git a/libgo/misc/cgo/life/c-life.c b/libgo/misc/cgo/life/c-life.c new file mode 100644 index 00000000000..f853163e2f0 --- /dev/null +++ b/libgo/misc/cgo/life/c-life.c @@ -0,0 +1,56 @@ +// Copyright 2010 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. + +#include +#include "life.h" +#include "_cgo_export.h" + +const int MYCONST = 0; + +// Do the actual manipulation of the life board in C. This could be +// done easily in Go, we are just using C for demonstration +// purposes. +void +Step(int x, int y, int *a, int *n) +{ + struct GoStart_return r; + + // Use Go to start 4 goroutines each of which handles 1/4 of the + // board. + r = GoStart(0, x, y, 0, x / 2, 0, y / 2, a, n); + assert(r.r0 == 0 && r.r1 == 100); // test multiple returns + r = GoStart(1, x, y, x / 2, x, 0, y / 2, a, n); + assert(r.r0 == 1 && r.r1 == 101); // test multiple returns + GoStart(2, x, y, 0, x / 2, y / 2, y, a, n); + GoStart(3, x, y, x / 2, x, y / 2, y, a, n); + GoWait(0); + GoWait(1); + GoWait(2); + GoWait(3); +} + +// The actual computation. This is called in parallel. +void +DoStep(int xdim, int ydim, int xstart, int xend, int ystart, int yend, int *a, int *n) +{ + int x, y, c, i, j; + + for(x = xstart; x < xend; x++) { + for(y = ystart; y < yend; y++) { + c = 0; + for(i = -1; i <= 1; i++) { + for(j = -1; j <= 1; j++) { + if(x+i >= 0 && x+i < xdim && + y+j >= 0 && y+j < ydim && + (i != 0 || j != 0)) + c += a[(x+i)*xdim + (y+j)] != 0; + } + } + if(c == 3 || (c == 2 && a[x*xdim + y] != 0)) + n[x*xdim + y] = 1; + else + n[x*xdim + y] = 0; + } + } +} diff --git a/libgo/misc/cgo/life/life.go b/libgo/misc/cgo/life/life.go new file mode 100644 index 00000000000..170a620c878 --- /dev/null +++ b/libgo/misc/cgo/life/life.go @@ -0,0 +1,41 @@ +// skip + +// Copyright 2010 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 life + +// #include "life.h" +import "C" + +import "unsafe" + +func Run(gen, x, y int, a []int32) { + n := make([]int32, x*y) + for i := 0; i < gen; i++ { + C.Step(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&a[0])), (*C.int)(unsafe.Pointer(&n[0]))) + copy(a, n) + } +} + +// Keep the channels visible from Go. +var chans [4]chan bool + +//export GoStart +// Double return value is just for testing. +func GoStart(i, xdim, ydim, xstart, xend, ystart, yend C.int, a *C.int, n *C.int) (int, int) { + c := make(chan bool, int(C.MYCONST)) + go func() { + C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n) + c <- true + }() + chans[i] = c + return int(i), int(i + 100) +} + +//export GoWait +func GoWait(i C.int) { + <-chans[i] + chans[i] = nil +} diff --git a/libgo/misc/cgo/life/life.h b/libgo/misc/cgo/life/life.h new file mode 100644 index 00000000000..11d2b972267 --- /dev/null +++ b/libgo/misc/cgo/life/life.h @@ -0,0 +1,7 @@ +// Copyright 2010 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. + +extern void Step(int, int, int *, int *); +extern void DoStep(int, int, int, int, int, int, int *, int *); +extern const int MYCONST; diff --git a/libgo/misc/cgo/life/main.go b/libgo/misc/cgo/life/main.go new file mode 100644 index 00000000000..aa2f6d116b3 --- /dev/null +++ b/libgo/misc/cgo/life/main.go @@ -0,0 +1,48 @@ +// cmpout + +// Copyright 2010 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. + +// +build test_run + +// Run the game of life in C using Go for parallelization. + +package main + +import ( + "." + "flag" + "fmt" +) + +const MAXDIM = 100 + +var dim = flag.Int("dim", 16, "board dimensions") +var gen = flag.Int("gen", 10, "generations") + +func main() { + flag.Parse() + + var a [MAXDIM * MAXDIM]int32 + for i := 2; i < *dim; i += 8 { + for j := 2; j < *dim-3; j += 8 { + for y := 0; y < 3; y++ { + a[i**dim+j+y] = 1 + } + } + } + + life.Run(*gen, *dim, *dim, a[:]) + + for i := 0; i < *dim; i++ { + for j := 0; j < *dim; j++ { + if a[i**dim+j] == 0 { + fmt.Print(" ") + } else { + fmt.Print("X") + } + } + fmt.Print("\n") + } +} diff --git a/libgo/misc/cgo/life/main.out b/libgo/misc/cgo/life/main.out new file mode 100644 index 00000000000..26fc9c6e3ff --- /dev/null +++ b/libgo/misc/cgo/life/main.out @@ -0,0 +1,16 @@ + + + XXX XXX + + + + + + + + XXX XXX + + + + + diff --git a/libgo/misc/cgo/nocgo/nocgo.go b/libgo/misc/cgo/nocgo/nocgo.go new file mode 100644 index 00000000000..00ae5e9c862 --- /dev/null +++ b/libgo/misc/cgo/nocgo/nocgo.go @@ -0,0 +1,22 @@ +// 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. + +// Test that -static works when not using cgo. This test is in +// misc/cgo to take advantage of the testing framework support for +// when -static is expected to work. + +package nocgo + +func NoCgo() int { + c := make(chan int) + + // The test is run with external linking, which means that + // goroutines will be created via the runtime/cgo package. + // Make sure that works. + go func() { + c <- 42 + }() + + return <-c +} diff --git a/libgo/misc/cgo/nocgo/nocgo_test.go b/libgo/misc/cgo/nocgo/nocgo_test.go new file mode 100644 index 00000000000..45d247cf954 --- /dev/null +++ b/libgo/misc/cgo/nocgo/nocgo_test.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 nocgo + +import "testing" + +func TestNop(t *testing.T) { + i := NoCgo() + if i != 42 { + t.Errorf("got %d, want %d", i, 42) + } +} diff --git a/libgo/misc/cgo/stdio/chain.go b/libgo/misc/cgo/stdio/chain.go new file mode 100644 index 00000000000..03cddb76888 --- /dev/null +++ b/libgo/misc/cgo/stdio/chain.go @@ -0,0 +1,48 @@ +// cmpout + +// Copyright 2009 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. + +// +build test_run + +// Pass numbers along a chain of threads. + +package main + +import ( + "runtime" + "strconv" + + "../stdio" +) + +const N = 10 +const R = 5 + +func link(left chan<- int, right <-chan int) { + // Keep the links in dedicated operating system + // threads, so that this program tests coordination + // between pthreads and not just goroutines. + runtime.LockOSThread() + for { + v := <-right + stdio.Stdout.WriteString(strconv.Itoa(v) + "\n") + left <- 1 + v + } +} + +func main() { + leftmost := make(chan int) + var left chan int + right := leftmost + for i := 0; i < N; i++ { + left, right = right, make(chan int) + go link(left, right) + } + for i := 0; i < R; i++ { + right <- 0 + x := <-leftmost + stdio.Stdout.WriteString(strconv.Itoa(x) + "\n") + } +} diff --git a/libgo/misc/cgo/stdio/chain.out b/libgo/misc/cgo/stdio/chain.out new file mode 100644 index 00000000000..963cf9b6679 --- /dev/null +++ b/libgo/misc/cgo/stdio/chain.out @@ -0,0 +1,55 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 diff --git a/libgo/misc/cgo/stdio/fib.go b/libgo/misc/cgo/stdio/fib.go new file mode 100644 index 00000000000..61a1b83728c --- /dev/null +++ b/libgo/misc/cgo/stdio/fib.go @@ -0,0 +1,52 @@ +// cmpout + +// Copyright 2009 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. + +// +build test_run + +// Compute Fibonacci numbers with two goroutines +// that pass integers back and forth. No actual +// concurrency, just threads and synchronization +// and foreign code on multiple pthreads. + +package main + +import ( + "runtime" + "strconv" + + "../stdio" +) + +func fibber(c, out chan int64, i int64) { + // Keep the fibbers in dedicated operating system + // threads, so that this program tests coordination + // between pthreads and not just goroutines. + runtime.LockOSThread() + + if i == 0 { + c <- i + } + for { + j := <-c + stdio.Stdout.WriteString(strconv.FormatInt(j, 10) + "\n") + out <- j + <-out + i += j + c <- i + } +} + +func main() { + c := make(chan int64) + out := make(chan int64) + go fibber(c, out, 0) + go fibber(c, out, 1) + <-out + for i := 0; i < 90; i++ { + out <- 1 + <-out + } +} diff --git a/libgo/misc/cgo/stdio/fib.out b/libgo/misc/cgo/stdio/fib.out new file mode 100644 index 00000000000..17ff503356d --- /dev/null +++ b/libgo/misc/cgo/stdio/fib.out @@ -0,0 +1,91 @@ +0 +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 +144 +233 +377 +610 +987 +1597 +2584 +4181 +6765 +10946 +17711 +28657 +46368 +75025 +121393 +196418 +317811 +514229 +832040 +1346269 +2178309 +3524578 +5702887 +9227465 +14930352 +24157817 +39088169 +63245986 +102334155 +165580141 +267914296 +433494437 +701408733 +1134903170 +1836311903 +2971215073 +4807526976 +7778742049 +12586269025 +20365011074 +32951280099 +53316291173 +86267571272 +139583862445 +225851433717 +365435296162 +591286729879 +956722026041 +1548008755920 +2504730781961 +4052739537881 +6557470319842 +10610209857723 +17167680177565 +27777890035288 +44945570212853 +72723460248141 +117669030460994 +190392490709135 +308061521170129 +498454011879264 +806515533049393 +1304969544928657 +2111485077978050 +3416454622906707 +5527939700884757 +8944394323791464 +14472334024676221 +23416728348467685 +37889062373143906 +61305790721611591 +99194853094755497 +160500643816367088 +259695496911122585 +420196140727489673 +679891637638612258 +1100087778366101931 +1779979416004714189 +2880067194370816120 diff --git a/libgo/misc/cgo/stdio/file.go b/libgo/misc/cgo/stdio/file.go new file mode 100644 index 00000000000..a024f2c361c --- /dev/null +++ b/libgo/misc/cgo/stdio/file.go @@ -0,0 +1,44 @@ +// skip + +// Copyright 2009 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. + +/* +A trivial example of wrapping a C library in Go. +For a more complex example and explanation, +see ../gmp/gmp.go. +*/ + +package stdio + +/* +#include +#include +#include +#include + +char* greeting = "hello, world"; +*/ +import "C" +import "unsafe" + +type File C.FILE + +// Test reference to library symbol. +// Stdout and stderr are too special to be a reliable test. +//var = C.environ + +func (f *File) WriteString(s string) { + p := C.CString(s) + C.fputs(p, (*C.FILE)(f)) + C.free(unsafe.Pointer(p)) + f.Flush() +} + +func (f *File) Flush() { + C.fflush((*C.FILE)(f)) +} + +var Greeting = C.GoString(C.greeting) +var Gbytes = C.GoBytes(unsafe.Pointer(C.greeting), C.int(len(Greeting))) diff --git a/libgo/misc/cgo/stdio/hello.go b/libgo/misc/cgo/stdio/hello.go new file mode 100644 index 00000000000..47179ba4827 --- /dev/null +++ b/libgo/misc/cgo/stdio/hello.go @@ -0,0 +1,15 @@ +// cmpout + +// Copyright 2009 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. + +// +build test_run + +package main + +import "../stdio" + +func main() { + stdio.Stdout.WriteString(stdio.Greeting + "\n") +} diff --git a/libgo/misc/cgo/stdio/hello.out b/libgo/misc/cgo/stdio/hello.out new file mode 100644 index 00000000000..4b5fa63702d --- /dev/null +++ b/libgo/misc/cgo/stdio/hello.out @@ -0,0 +1 @@ +hello, world diff --git a/libgo/misc/cgo/stdio/run.out b/libgo/misc/cgo/stdio/run.out new file mode 100644 index 00000000000..c0e496547ed --- /dev/null +++ b/libgo/misc/cgo/stdio/run.out @@ -0,0 +1,150 @@ +* hello +hello, world +* fib +0 +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 +144 +233 +377 +610 +987 +1597 +2584 +4181 +6765 +10946 +17711 +28657 +46368 +75025 +121393 +196418 +317811 +514229 +832040 +1346269 +2178309 +3524578 +5702887 +9227465 +14930352 +24157817 +39088169 +63245986 +102334155 +165580141 +267914296 +433494437 +701408733 +1134903170 +1836311903 +2971215073 +4807526976 +7778742049 +12586269025 +20365011074 +32951280099 +53316291173 +86267571272 +139583862445 +225851433717 +365435296162 +591286729879 +956722026041 +1548008755920 +2504730781961 +4052739537881 +6557470319842 +10610209857723 +17167680177565 +27777890035288 +44945570212853 +72723460248141 +117669030460994 +190392490709135 +308061521170129 +498454011879264 +806515533049393 +1304969544928657 +2111485077978050 +3416454622906707 +5527939700884757 +8944394323791464 +14472334024676221 +23416728348467685 +37889062373143906 +61305790721611591 +99194853094755497 +160500643816367088 +259695496911122585 +420196140727489673 +679891637638612258 +1100087778366101931 +1779979416004714189 +2880067194370816120 +* chain +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 diff --git a/libgo/misc/cgo/stdio/stdio.go b/libgo/misc/cgo/stdio/stdio.go new file mode 100644 index 00000000000..d216e44fe7c --- /dev/null +++ b/libgo/misc/cgo/stdio/stdio.go @@ -0,0 +1,22 @@ +// skip + +// Copyright 2009 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 stdio + +/* +#include + +// on mingw, stderr and stdout are defined as &_iob[FILENO] +// on netbsd, they are defined as &__sF[FILENO] +// and cgo doesn't recognize them, so write a function to get them, +// instead of depending on internals of libc implementation. +FILE *getStdout(void) { return stdout; } +FILE *getStderr(void) { return stderr; } +*/ +import "C" + +var Stdout = (*File)(C.getStdout()) +var Stderr = (*File)(C.getStderr()) diff --git a/libgo/misc/cgo/test/align.go b/libgo/misc/cgo/test/align.go new file mode 100644 index 00000000000..a23b44fc38c --- /dev/null +++ b/libgo/misc/cgo/test/align.go @@ -0,0 +1,76 @@ +// Copyright 2010 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 cgotest + +/* +#include + +typedef unsigned char Uint8; +typedef unsigned short Uint16; + +typedef enum { + MOD1 = 0x0000, + MODX = 0x8000 +} SDLMod; + +typedef enum { + A = 1, + B = 322, + SDLK_LAST +} SDLKey; + +typedef struct SDL_keysym { + Uint8 scancode; + SDLKey sym; + SDLMod mod; + Uint16 unicode; +} SDL_keysym; + +typedef struct SDL_KeyboardEvent { + Uint8 typ; + Uint8 which; + Uint8 state; + SDL_keysym keysym; +} SDL_KeyboardEvent; + +void makeEvent(SDL_KeyboardEvent *event) { + unsigned char *p; + int i; + + p = (unsigned char*)event; + for (i=0; ityp == typ && e->which == which && e->state == state && e->keysym.scancode == scan && e->keysym.sym == sym && e->keysym.mod == mod && e->keysym.unicode == uni; +} + +void cTest(SDL_KeyboardEvent *event) { + printf("C: %#x %#x %#x %#x %#x %#x %#x\n", event->typ, event->which, event->state, + event->keysym.scancode, event->keysym.sym, event->keysym.mod, event->keysym.unicode); + fflush(stdout); +} + +*/ +import "C" + +import ( + "testing" +) + +func testAlign(t *testing.T) { + var evt C.SDL_KeyboardEvent + C.makeEvent(&evt) + if C.same(&evt, evt.typ, evt.which, evt.state, evt.keysym.scancode, evt.keysym.sym, evt.keysym.mod, evt.keysym.unicode) == 0 { + t.Error("*** bad alignment") + C.cTest(&evt) + t.Errorf("Go: %#x %#x %#x %#x %#x %#x %#x\n", + evt.typ, evt.which, evt.state, evt.keysym.scancode, + evt.keysym.sym, evt.keysym.mod, evt.keysym.unicode) + t.Error(evt) + } +} diff --git a/libgo/misc/cgo/test/api.go b/libgo/misc/cgo/test/api.go new file mode 100644 index 00000000000..d2b09cbeffe --- /dev/null +++ b/libgo/misc/cgo/test/api.go @@ -0,0 +1,30 @@ +// 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. + +// API Compatibility Checks for cgo + +package cgotest + +// #include +// +// // Test for issue 17723. +// typedef char *cstring_pointer; +// static void cstring_pointer_fun(cstring_pointer dummy) { } +// +// const char *api_hello = "hello!"; +import "C" +import "unsafe" + +func testAPI() { + var cs *C.char + cs = C.CString("hello") + defer C.free(unsafe.Pointer(cs)) + var s string + s = C.GoString((*C.char)(C.api_hello)) + s = C.GoStringN((*C.char)(C.api_hello), C.int(6)) + var b []byte + b = C.GoBytes(unsafe.Pointer(C.api_hello), C.int(6)) + _, _ = s, b + C.cstring_pointer_fun(nil) +} diff --git a/libgo/misc/cgo/test/backdoor.go b/libgo/misc/cgo/test/backdoor.go new file mode 100644 index 00000000000..6fb33d66cb2 --- /dev/null +++ b/libgo/misc/cgo/test/backdoor.go @@ -0,0 +1,11 @@ +// 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 cgotest + +import _ "unsafe" + +//go:linkname lockedOSThread runtime.lockedOSThread +//extern runtime_lockedOSThread +func lockedOSThread() bool diff --git a/libgo/misc/cgo/test/basic.go b/libgo/misc/cgo/test/basic.go new file mode 100644 index 00000000000..3ceb4ce8470 --- /dev/null +++ b/libgo/misc/cgo/test/basic.go @@ -0,0 +1,167 @@ +// Copyright 2010 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. + +// Basic test cases for cgo. + +package cgotest + +/* +#include +#include +#include +#include + +#define SHIFT(x, y) ((x)<<(y)) +#define KILO SHIFT(1, 10) +#define UINT32VAL 0xc008427bU + +enum E { + Enum1 = 1, + Enum2 = 2, +}; + +typedef unsigned char cgo_uuid_t[20]; + +void uuid_generate(cgo_uuid_t x) { + x[0] = 0; +} + +struct S { + int x; +}; + +extern enum E myConstFunc(struct S* const ctx, int const id, struct S **const filter); + +enum E myConstFunc(struct S *const ctx, int const id, struct S **const filter) { return 0; } + +// issue 1222 +typedef union { + long align; +} xxpthread_mutex_t; + +struct ibv_async_event { + union { + int x; + } element; +}; + +struct ibv_context { + xxpthread_mutex_t mutex; +}; + +int add(int x, int y) { + return x+y; +}; +*/ +import "C" +import ( + "runtime" + "syscall" + "testing" + "unsafe" +) + +const EINVAL = C.EINVAL /* test #define */ + +var KILO = C.KILO + +func uuidgen() { + var uuid C.cgo_uuid_t + C.uuid_generate(&uuid[0]) +} + +func Strtol(s string, base int) (int, error) { + p := C.CString(s) + n, err := C.strtol(p, nil, C.int(base)) + C.free(unsafe.Pointer(p)) + return int(n), err +} + +func Atol(s string) int { + p := C.CString(s) + n := C.atol(p) + C.free(unsafe.Pointer(p)) + return int(n) +} + +func testConst(t *testing.T) { + C.myConstFunc(nil, 0, nil) +} + +func testEnum(t *testing.T) { + if C.Enum1 != 1 || C.Enum2 != 2 { + t.Error("bad enum", C.Enum1, C.Enum2) + } +} + +func testAtol(t *testing.T) { + l := Atol("123") + if l != 123 { + t.Error("Atol 123: ", l) + } +} + +func testErrno(t *testing.T) { + p := C.CString("no-such-file") + m := C.CString("r") + f, err := C.fopen(p, m) + C.free(unsafe.Pointer(p)) + C.free(unsafe.Pointer(m)) + if err == nil { + C.fclose(f) + t.Fatalf("C.fopen: should fail") + } + if err != syscall.ENOENT { + t.Fatalf("C.fopen: unexpected error: %v", err) + } +} + +func testMultipleAssign(t *testing.T) { + p := C.CString("234") + n, m := C.strtol(p, nil, 345), C.strtol(p, nil, 10) + if runtime.GOOS == "openbsd" { + // Bug in OpenBSD strtol(3) - base > 36 succeeds. + if (n != 0 && n != 239089) || m != 234 { + t.Fatal("Strtol x2: ", n, m) + } + } else if n != 0 || m != 234 { + t.Fatal("Strtol x2: ", n, m) + } + C.free(unsafe.Pointer(p)) +} + +var ( + cuint = (C.uint)(0) + culong C.ulong + cchar C.char +) + +type Context struct { + ctx *C.struct_ibv_context +} + +func benchCgoCall(b *testing.B) { + const x = C.int(2) + const y = C.int(3) + for i := 0; i < b.N; i++ { + C.add(x, y) + } +} + +// Issue 2470. +func testUnsignedInt(t *testing.T) { + a := (int64)(C.UINT32VAL) + b := (int64)(0xc008427b) + if a != b { + t.Errorf("Incorrect unsigned int - got %x, want %x", a, b) + } +} + +// Static (build-time) test that syntax traversal visits all operands of s[i:j:k]. +func sliceOperands(array [2000]int) { + _ = array[C.KILO:C.KILO:C.KILO] // no type error +} + +// set in cgo_thread_lock.go init +var testThreadLockFunc = func(*testing.T) {} diff --git a/libgo/misc/cgo/test/buildid_linux.go b/libgo/misc/cgo/test/buildid_linux.go new file mode 100644 index 00000000000..47dd87128ff --- /dev/null +++ b/libgo/misc/cgo/test/buildid_linux.go @@ -0,0 +1,77 @@ +// 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 cgotest + +// Test that we have no more than one build ID. In the past we used +// to generate a separate build ID for each package using cgo, and the +// linker concatenated them all. We don't want that--we only want +// one. + +import ( + "bytes" + "debug/elf" + "os" + "testing" +) + +func testBuildID(t *testing.T) { + f, err := elf.Open("/proc/self/exe") + if err != nil { + if os.IsNotExist(err) { + t.Skip("no /proc/self/exe") + } + t.Fatal("opening /proc/self/exe: ", err) + } + defer f.Close() + + c := 0 + for i, s := range f.Sections { + if s.Type != elf.SHT_NOTE { + continue + } + + d, err := s.Data() + if err != nil { + t.Logf("reading data of note section %d: %v", i, err) + continue + } + + for len(d) > 0 { + + // ELF standards differ as to the sizes in + // note sections. Both the GNU linker and + // gold always generate 32-bit sizes, so that + // is what we assume here. + + if len(d) < 12 { + t.Logf("note section %d too short (%d < 12)", i, len(d)) + continue + } + + namesz := f.ByteOrder.Uint32(d) + descsz := f.ByteOrder.Uint32(d[4:]) + typ := f.ByteOrder.Uint32(d[8:]) + + an := (namesz + 3) &^ 3 + ad := (descsz + 3) &^ 3 + + if int(12+an+ad) > len(d) { + t.Logf("note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))", i, len(d), namesz, descsz) + continue + } + + // 3 == NT_GNU_BUILD_ID + if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) { + c++ + } + + d = d[12+an+ad:] + } + } + + if c > 1 { + t.Errorf("found %d build ID notes", c) + } +} diff --git a/libgo/misc/cgo/test/callback.go b/libgo/misc/cgo/test/callback.go new file mode 100644 index 00000000000..b88bf134bc1 --- /dev/null +++ b/libgo/misc/cgo/test/callback.go @@ -0,0 +1,1782 @@ +// Copyright 2011 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 cgotest + +/* +void callback(void *f); +void callGoFoo(void); +void callGoStackCheck(void); +void callPanic(void); +int callGoReturnVal(void); +int returnAfterGrow(void); +int returnAfterGrowFromGo(void); +void callGoWithString(void); +*/ +import "C" + +import ( + "path" + "runtime" + "strings" + "sync" + "testing" + "unsafe" +) + +// Pass a func value from nestedCall to goCallback using an integer token. +var callbackMutex sync.Mutex +var callbackToken int +var callbackFuncs = make(map[int]func()) + +// nestedCall calls into C, back into Go, and finally to f. +func nestedCall(f func()) { + // callback(x) calls goCallback(x) + callbackMutex.Lock() + callbackToken++ + i := callbackToken + callbackFuncs[i] = f + callbackMutex.Unlock() + + // Pass the address of i because the C function was written to + // take a pointer. We could pass an int if we felt like + // rewriting the C code. + C.callback(unsafe.Pointer(&i)) + + callbackMutex.Lock() + delete(callbackFuncs, i) + callbackMutex.Unlock() +} + +//export goCallback +func goCallback(p unsafe.Pointer) { + i := *(*int)(p) + + callbackMutex.Lock() + f := callbackFuncs[i] + callbackMutex.Unlock() + + if f == nil { + panic("missing callback function") + } + f() +} + +func testCallback(t *testing.T) { + var x = false + nestedCall(func() { x = true }) + if !x { + t.Fatal("nestedCall did not call func") + } +} + +func testCallbackGC(t *testing.T) { + nestedCall(runtime.GC) +} + +func testCallbackPanic(t *testing.T) { + // Make sure panic during callback unwinds properly. + if lockedOSThread() { + t.Fatal("locked OS thread on entry to TestCallbackPanic") + } + defer func() { + s := recover() + if s == nil { + t.Fatal("did not panic") + } + if s.(string) != "callback panic" { + t.Fatal("wrong panic:", s) + } + if lockedOSThread() { + t.Fatal("locked OS thread on exit from TestCallbackPanic") + } + }() + nestedCall(func() { panic("callback panic") }) + panic("nestedCall returned") +} + +func testCallbackPanicLoop(t *testing.T) { + // Make sure we don't blow out m->g0 stack. + for i := 0; i < 100000; i++ { + testCallbackPanic(t) + } +} + +func testCallbackPanicLocked(t *testing.T) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if !lockedOSThread() { + t.Fatal("runtime.LockOSThread didn't") + } + defer func() { + s := recover() + if s == nil { + t.Fatal("did not panic") + } + if s.(string) != "callback panic" { + t.Fatal("wrong panic:", s) + } + if !lockedOSThread() { + t.Fatal("lost lock on OS thread after panic") + } + }() + nestedCall(func() { panic("callback panic") }) + panic("nestedCall returned") +} + +// Callback with zero arguments used to make the stack misaligned, +// which broke the garbage collector and other things. +func testZeroArgCallback(t *testing.T) { + defer func() { + s := recover() + if s != nil { + t.Fatal("panic during callback:", s) + } + }() + C.callGoFoo() +} + +//export goFoo +func goFoo() { + x := 1 + for i := 0; i < 10000; i++ { + // variadic call mallocs + writes to + variadic(x, x, x) + if x != 1 { + panic("bad x") + } + } +} + +func variadic(x ...interface{}) {} + +func testBlocking(t *testing.T) { + c := make(chan int) + go func() { + for i := 0; i < 10; i++ { + c <- <-c + } + }() + nestedCall(func() { + for i := 0; i < 10; i++ { + c <- i + if j := <-c; j != i { + t.Errorf("out of sync %d != %d", j, i) + } + } + }) +} + +// Test that the stack can be unwound through a call out and call back +// into Go. +func testCallbackCallers(t *testing.T) { + if runtime.Compiler != "gc" { + // The exact function names are not going to be the same. + t.Skip("skipping for non-gc toolchain") + } + pc := make([]uintptr, 100) + n := 0 + name := []string{ + "runtime.call16", + "runtime.cgocallbackg1", + "runtime.cgocallbackg", + "runtime.cgocallback_gofunc", + "runtime.asmcgocall", + "runtime.cgocall", + "test._Cfunc_callback", + "test.nestedCall.func1", + "test.nestedCall", + "test.testCallbackCallers", + "test.TestCallbackCallers", + "testing.tRunner", + "runtime.goexit", + } + if unsafe.Sizeof((*byte)(nil)) == 8 { + name[0] = "runtime.call32" + } + nestedCall(func() { + n = runtime.Callers(4, pc) + }) + if n != len(name) { + t.Errorf("expected %d frames, got %d", len(name), n) + } + for i := 0; i < n; i++ { + f := runtime.FuncForPC(pc[i]) + if f == nil { + t.Fatalf("expected non-nil Func for pc %d", pc[i]) + } + fname := f.Name() + // Remove the prepended pathname from automatically + // generated cgo function names. + if strings.HasPrefix(fname, "_") { + fname = path.Base(f.Name()[1:]) + } + namei := "" + if i < len(name) { + namei = name[i] + } + if fname != namei { + t.Errorf("stk[%d] = %q, want %q", i, fname, namei) + } + } +} + +func testPanicFromC(t *testing.T) { + defer func() { + r := recover() + if r == nil { + t.Fatal("did not panic") + } + if r.(string) != "panic from C" { + t.Fatal("wrong panic:", r) + } + }() + C.callPanic() +} + +// Test that C code can return a value if it calls a Go function that +// causes a stack copy. +func testReturnAfterGrow(t *testing.T) { + // Use a new goroutine so that we get a small stack. + c := make(chan int) + go func() { + c <- int(C.returnAfterGrow()) + }() + if got, want := <-c, 123456; got != want { + t.Errorf("got %d want %d", got, want) + } +} + +// Test that we can return a value from Go->C->Go if the Go code +// causes a stack copy. +func testReturnAfterGrowFromGo(t *testing.T) { + // Use a new goroutine so that we get a small stack. + c := make(chan int) + go func() { + c <- int(C.returnAfterGrowFromGo()) + }() + if got, want := <-c, 129*128/2; got != want { + t.Errorf("got %d want %d", got, want) + } +} + +//export goReturnVal +func goReturnVal() (r C.int) { + // Force a stack copy. + var f func(int) int + f = func(i int) int { + var buf [256]byte + use(buf[:]) + if i == 0 { + return 0 + } + return i + f(i-1) + } + r = C.int(f(128)) + return +} + +// Test that C can pass in a Go string from a string constant. +func testCallGoWithString(t *testing.T) { + C.callGoWithString() + want := "string passed from C to Go" + if stringFromGo != want { + t.Errorf("string passed through C is %s, want %s", stringFromGo, want) + } +} + +var stringFromGo string + +//export goWithString +func goWithString(s string) { + stringFromGo = s +} + +func testCallbackStack(t *testing.T) { + // Make cgo call and callback with different amount of stack stack available. + // We do not do any explicit checks, just ensure that it does not crash. + for _, f := range splitTests { + f() + } +} + +//export goStackCheck +func goStackCheck() { + // use some stack memory to trigger split stack check + var buf [256]byte + use(buf[:]) +} + +var Used byte + +func use(buf []byte) { + for _, c := range buf { + Used += c + } +} + +var splitTests = []func(){ + // Edit .+1,/^}/-1|seq 4 4 5000 | sed 's/.*/ stack&,/' | fmt + stack4, stack8, stack12, stack16, stack20, stack24, stack28, + stack32, stack36, stack40, stack44, stack48, stack52, stack56, + stack60, stack64, stack68, stack72, stack76, stack80, stack84, + stack88, stack92, stack96, stack100, stack104, stack108, stack112, + stack116, stack120, stack124, stack128, stack132, stack136, + stack140, stack144, stack148, stack152, stack156, stack160, + stack164, stack168, stack172, stack176, stack180, stack184, + stack188, stack192, stack196, stack200, stack204, stack208, + stack212, stack216, stack220, stack224, stack228, stack232, + stack236, stack240, stack244, stack248, stack252, stack256, + stack260, stack264, stack268, stack272, stack276, stack280, + stack284, stack288, stack292, stack296, stack300, stack304, + stack308, stack312, stack316, stack320, stack324, stack328, + stack332, stack336, stack340, stack344, stack348, stack352, + stack356, stack360, stack364, stack368, stack372, stack376, + stack380, stack384, stack388, stack392, stack396, stack400, + stack404, stack408, stack412, stack416, stack420, stack424, + stack428, stack432, stack436, stack440, stack444, stack448, + stack452, stack456, stack460, stack464, stack468, stack472, + stack476, stack480, stack484, stack488, stack492, stack496, + stack500, stack504, stack508, stack512, stack516, stack520, + stack524, stack528, stack532, stack536, stack540, stack544, + stack548, stack552, stack556, stack560, stack564, stack568, + stack572, stack576, stack580, stack584, stack588, stack592, + stack596, stack600, stack604, stack608, stack612, stack616, + stack620, stack624, stack628, stack632, stack636, stack640, + stack644, stack648, stack652, stack656, stack660, stack664, + stack668, stack672, stack676, stack680, stack684, stack688, + stack692, stack696, stack700, stack704, stack708, stack712, + stack716, stack720, stack724, stack728, stack732, stack736, + stack740, stack744, stack748, stack752, stack756, stack760, + stack764, stack768, stack772, stack776, stack780, stack784, + stack788, stack792, stack796, stack800, stack804, stack808, + stack812, stack816, stack820, stack824, stack828, stack832, + stack836, stack840, stack844, stack848, stack852, stack856, + stack860, stack864, stack868, stack872, stack876, stack880, + stack884, stack888, stack892, stack896, stack900, stack904, + stack908, stack912, stack916, stack920, stack924, stack928, + stack932, stack936, stack940, stack944, stack948, stack952, + stack956, stack960, stack964, stack968, stack972, stack976, + stack980, stack984, stack988, stack992, stack996, stack1000, + stack1004, stack1008, stack1012, stack1016, stack1020, stack1024, + stack1028, stack1032, stack1036, stack1040, stack1044, stack1048, + stack1052, stack1056, stack1060, stack1064, stack1068, stack1072, + stack1076, stack1080, stack1084, stack1088, stack1092, stack1096, + stack1100, stack1104, stack1108, stack1112, stack1116, stack1120, + stack1124, stack1128, stack1132, stack1136, stack1140, stack1144, + stack1148, stack1152, stack1156, stack1160, stack1164, stack1168, + stack1172, stack1176, stack1180, stack1184, stack1188, stack1192, + stack1196, stack1200, stack1204, stack1208, stack1212, stack1216, + stack1220, stack1224, stack1228, stack1232, stack1236, stack1240, + stack1244, stack1248, stack1252, stack1256, stack1260, stack1264, + stack1268, stack1272, stack1276, stack1280, stack1284, stack1288, + stack1292, stack1296, stack1300, stack1304, stack1308, stack1312, + stack1316, stack1320, stack1324, stack1328, stack1332, stack1336, + stack1340, stack1344, stack1348, stack1352, stack1356, stack1360, + stack1364, stack1368, stack1372, stack1376, stack1380, stack1384, + stack1388, stack1392, stack1396, stack1400, stack1404, stack1408, + stack1412, stack1416, stack1420, stack1424, stack1428, stack1432, + stack1436, stack1440, stack1444, stack1448, stack1452, stack1456, + stack1460, stack1464, stack1468, stack1472, stack1476, stack1480, + stack1484, stack1488, stack1492, stack1496, stack1500, stack1504, + stack1508, stack1512, stack1516, stack1520, stack1524, stack1528, + stack1532, stack1536, stack1540, stack1544, stack1548, stack1552, + stack1556, stack1560, stack1564, stack1568, stack1572, stack1576, + stack1580, stack1584, stack1588, stack1592, stack1596, stack1600, + stack1604, stack1608, stack1612, stack1616, stack1620, stack1624, + stack1628, stack1632, stack1636, stack1640, stack1644, stack1648, + stack1652, stack1656, stack1660, stack1664, stack1668, stack1672, + stack1676, stack1680, stack1684, stack1688, stack1692, stack1696, + stack1700, stack1704, stack1708, stack1712, stack1716, stack1720, + stack1724, stack1728, stack1732, stack1736, stack1740, stack1744, + stack1748, stack1752, stack1756, stack1760, stack1764, stack1768, + stack1772, stack1776, stack1780, stack1784, stack1788, stack1792, + stack1796, stack1800, stack1804, stack1808, stack1812, stack1816, + stack1820, stack1824, stack1828, stack1832, stack1836, stack1840, + stack1844, stack1848, stack1852, stack1856, stack1860, stack1864, + stack1868, stack1872, stack1876, stack1880, stack1884, stack1888, + stack1892, stack1896, stack1900, stack1904, stack1908, stack1912, + stack1916, stack1920, stack1924, stack1928, stack1932, stack1936, + stack1940, stack1944, stack1948, stack1952, stack1956, stack1960, + stack1964, stack1968, stack1972, stack1976, stack1980, stack1984, + stack1988, stack1992, stack1996, stack2000, stack2004, stack2008, + stack2012, stack2016, stack2020, stack2024, stack2028, stack2032, + stack2036, stack2040, stack2044, stack2048, stack2052, stack2056, + stack2060, stack2064, stack2068, stack2072, stack2076, stack2080, + stack2084, stack2088, stack2092, stack2096, stack2100, stack2104, + stack2108, stack2112, stack2116, stack2120, stack2124, stack2128, + stack2132, stack2136, stack2140, stack2144, stack2148, stack2152, + stack2156, stack2160, stack2164, stack2168, stack2172, stack2176, + stack2180, stack2184, stack2188, stack2192, stack2196, stack2200, + stack2204, stack2208, stack2212, stack2216, stack2220, stack2224, + stack2228, stack2232, stack2236, stack2240, stack2244, stack2248, + stack2252, stack2256, stack2260, stack2264, stack2268, stack2272, + stack2276, stack2280, stack2284, stack2288, stack2292, stack2296, + stack2300, stack2304, stack2308, stack2312, stack2316, stack2320, + stack2324, stack2328, stack2332, stack2336, stack2340, stack2344, + stack2348, stack2352, stack2356, stack2360, stack2364, stack2368, + stack2372, stack2376, stack2380, stack2384, stack2388, stack2392, + stack2396, stack2400, stack2404, stack2408, stack2412, stack2416, + stack2420, stack2424, stack2428, stack2432, stack2436, stack2440, + stack2444, stack2448, stack2452, stack2456, stack2460, stack2464, + stack2468, stack2472, stack2476, stack2480, stack2484, stack2488, + stack2492, stack2496, stack2500, stack2504, stack2508, stack2512, + stack2516, stack2520, stack2524, stack2528, stack2532, stack2536, + stack2540, stack2544, stack2548, stack2552, stack2556, stack2560, + stack2564, stack2568, stack2572, stack2576, stack2580, stack2584, + stack2588, stack2592, stack2596, stack2600, stack2604, stack2608, + stack2612, stack2616, stack2620, stack2624, stack2628, stack2632, + stack2636, stack2640, stack2644, stack2648, stack2652, stack2656, + stack2660, stack2664, stack2668, stack2672, stack2676, stack2680, + stack2684, stack2688, stack2692, stack2696, stack2700, stack2704, + stack2708, stack2712, stack2716, stack2720, stack2724, stack2728, + stack2732, stack2736, stack2740, stack2744, stack2748, stack2752, + stack2756, stack2760, stack2764, stack2768, stack2772, stack2776, + stack2780, stack2784, stack2788, stack2792, stack2796, stack2800, + stack2804, stack2808, stack2812, stack2816, stack2820, stack2824, + stack2828, stack2832, stack2836, stack2840, stack2844, stack2848, + stack2852, stack2856, stack2860, stack2864, stack2868, stack2872, + stack2876, stack2880, stack2884, stack2888, stack2892, stack2896, + stack2900, stack2904, stack2908, stack2912, stack2916, stack2920, + stack2924, stack2928, stack2932, stack2936, stack2940, stack2944, + stack2948, stack2952, stack2956, stack2960, stack2964, stack2968, + stack2972, stack2976, stack2980, stack2984, stack2988, stack2992, + stack2996, stack3000, stack3004, stack3008, stack3012, stack3016, + stack3020, stack3024, stack3028, stack3032, stack3036, stack3040, + stack3044, stack3048, stack3052, stack3056, stack3060, stack3064, + stack3068, stack3072, stack3076, stack3080, stack3084, stack3088, + stack3092, stack3096, stack3100, stack3104, stack3108, stack3112, + stack3116, stack3120, stack3124, stack3128, stack3132, stack3136, + stack3140, stack3144, stack3148, stack3152, stack3156, stack3160, + stack3164, stack3168, stack3172, stack3176, stack3180, stack3184, + stack3188, stack3192, stack3196, stack3200, stack3204, stack3208, + stack3212, stack3216, stack3220, stack3224, stack3228, stack3232, + stack3236, stack3240, stack3244, stack3248, stack3252, stack3256, + stack3260, stack3264, stack3268, stack3272, stack3276, stack3280, + stack3284, stack3288, stack3292, stack3296, stack3300, stack3304, + stack3308, stack3312, stack3316, stack3320, stack3324, stack3328, + stack3332, stack3336, stack3340, stack3344, stack3348, stack3352, + stack3356, stack3360, stack3364, stack3368, stack3372, stack3376, + stack3380, stack3384, stack3388, stack3392, stack3396, stack3400, + stack3404, stack3408, stack3412, stack3416, stack3420, stack3424, + stack3428, stack3432, stack3436, stack3440, stack3444, stack3448, + stack3452, stack3456, stack3460, stack3464, stack3468, stack3472, + stack3476, stack3480, stack3484, stack3488, stack3492, stack3496, + stack3500, stack3504, stack3508, stack3512, stack3516, stack3520, + stack3524, stack3528, stack3532, stack3536, stack3540, stack3544, + stack3548, stack3552, stack3556, stack3560, stack3564, stack3568, + stack3572, stack3576, stack3580, stack3584, stack3588, stack3592, + stack3596, stack3600, stack3604, stack3608, stack3612, stack3616, + stack3620, stack3624, stack3628, stack3632, stack3636, stack3640, + stack3644, stack3648, stack3652, stack3656, stack3660, stack3664, + stack3668, stack3672, stack3676, stack3680, stack3684, stack3688, + stack3692, stack3696, stack3700, stack3704, stack3708, stack3712, + stack3716, stack3720, stack3724, stack3728, stack3732, stack3736, + stack3740, stack3744, stack3748, stack3752, stack3756, stack3760, + stack3764, stack3768, stack3772, stack3776, stack3780, stack3784, + stack3788, stack3792, stack3796, stack3800, stack3804, stack3808, + stack3812, stack3816, stack3820, stack3824, stack3828, stack3832, + stack3836, stack3840, stack3844, stack3848, stack3852, stack3856, + stack3860, stack3864, stack3868, stack3872, stack3876, stack3880, + stack3884, stack3888, stack3892, stack3896, stack3900, stack3904, + stack3908, stack3912, stack3916, stack3920, stack3924, stack3928, + stack3932, stack3936, stack3940, stack3944, stack3948, stack3952, + stack3956, stack3960, stack3964, stack3968, stack3972, stack3976, + stack3980, stack3984, stack3988, stack3992, stack3996, stack4000, + stack4004, stack4008, stack4012, stack4016, stack4020, stack4024, + stack4028, stack4032, stack4036, stack4040, stack4044, stack4048, + stack4052, stack4056, stack4060, stack4064, stack4068, stack4072, + stack4076, stack4080, stack4084, stack4088, stack4092, stack4096, + stack4100, stack4104, stack4108, stack4112, stack4116, stack4120, + stack4124, stack4128, stack4132, stack4136, stack4140, stack4144, + stack4148, stack4152, stack4156, stack4160, stack4164, stack4168, + stack4172, stack4176, stack4180, stack4184, stack4188, stack4192, + stack4196, stack4200, stack4204, stack4208, stack4212, stack4216, + stack4220, stack4224, stack4228, stack4232, stack4236, stack4240, + stack4244, stack4248, stack4252, stack4256, stack4260, stack4264, + stack4268, stack4272, stack4276, stack4280, stack4284, stack4288, + stack4292, stack4296, stack4300, stack4304, stack4308, stack4312, + stack4316, stack4320, stack4324, stack4328, stack4332, stack4336, + stack4340, stack4344, stack4348, stack4352, stack4356, stack4360, + stack4364, stack4368, stack4372, stack4376, stack4380, stack4384, + stack4388, stack4392, stack4396, stack4400, stack4404, stack4408, + stack4412, stack4416, stack4420, stack4424, stack4428, stack4432, + stack4436, stack4440, stack4444, stack4448, stack4452, stack4456, + stack4460, stack4464, stack4468, stack4472, stack4476, stack4480, + stack4484, stack4488, stack4492, stack4496, stack4500, stack4504, + stack4508, stack4512, stack4516, stack4520, stack4524, stack4528, + stack4532, stack4536, stack4540, stack4544, stack4548, stack4552, + stack4556, stack4560, stack4564, stack4568, stack4572, stack4576, + stack4580, stack4584, stack4588, stack4592, stack4596, stack4600, + stack4604, stack4608, stack4612, stack4616, stack4620, stack4624, + stack4628, stack4632, stack4636, stack4640, stack4644, stack4648, + stack4652, stack4656, stack4660, stack4664, stack4668, stack4672, + stack4676, stack4680, stack4684, stack4688, stack4692, stack4696, + stack4700, stack4704, stack4708, stack4712, stack4716, stack4720, + stack4724, stack4728, stack4732, stack4736, stack4740, stack4744, + stack4748, stack4752, stack4756, stack4760, stack4764, stack4768, + stack4772, stack4776, stack4780, stack4784, stack4788, stack4792, + stack4796, stack4800, stack4804, stack4808, stack4812, stack4816, + stack4820, stack4824, stack4828, stack4832, stack4836, stack4840, + stack4844, stack4848, stack4852, stack4856, stack4860, stack4864, + stack4868, stack4872, stack4876, stack4880, stack4884, stack4888, + stack4892, stack4896, stack4900, stack4904, stack4908, stack4912, + stack4916, stack4920, stack4924, stack4928, stack4932, stack4936, + stack4940, stack4944, stack4948, stack4952, stack4956, stack4960, + stack4964, stack4968, stack4972, stack4976, stack4980, stack4984, + stack4988, stack4992, stack4996, stack5000, +} + +// Edit .+1,$ | seq 4 4 5000 | sed 's/.*/func stack&() { var buf [&]byte; use(buf[:]); C.callGoStackCheck() }/' +func stack4() { var buf [4]byte; use(buf[:]); C.callGoStackCheck() } +func stack8() { var buf [8]byte; use(buf[:]); C.callGoStackCheck() } +func stack12() { var buf [12]byte; use(buf[:]); C.callGoStackCheck() } +func stack16() { var buf [16]byte; use(buf[:]); C.callGoStackCheck() } +func stack20() { var buf [20]byte; use(buf[:]); C.callGoStackCheck() } +func stack24() { var buf [24]byte; use(buf[:]); C.callGoStackCheck() } +func stack28() { var buf [28]byte; use(buf[:]); C.callGoStackCheck() } +func stack32() { var buf [32]byte; use(buf[:]); C.callGoStackCheck() } +func stack36() { var buf [36]byte; use(buf[:]); C.callGoStackCheck() } +func stack40() { var buf [40]byte; use(buf[:]); C.callGoStackCheck() } +func stack44() { var buf [44]byte; use(buf[:]); C.callGoStackCheck() } +func stack48() { var buf [48]byte; use(buf[:]); C.callGoStackCheck() } +func stack52() { var buf [52]byte; use(buf[:]); C.callGoStackCheck() } +func stack56() { var buf [56]byte; use(buf[:]); C.callGoStackCheck() } +func stack60() { var buf [60]byte; use(buf[:]); C.callGoStackCheck() } +func stack64() { var buf [64]byte; use(buf[:]); C.callGoStackCheck() } +func stack68() { var buf [68]byte; use(buf[:]); C.callGoStackCheck() } +func stack72() { var buf [72]byte; use(buf[:]); C.callGoStackCheck() } +func stack76() { var buf [76]byte; use(buf[:]); C.callGoStackCheck() } +func stack80() { var buf [80]byte; use(buf[:]); C.callGoStackCheck() } +func stack84() { var buf [84]byte; use(buf[:]); C.callGoStackCheck() } +func stack88() { var buf [88]byte; use(buf[:]); C.callGoStackCheck() } +func stack92() { var buf [92]byte; use(buf[:]); C.callGoStackCheck() } +func stack96() { var buf [96]byte; use(buf[:]); C.callGoStackCheck() } +func stack100() { var buf [100]byte; use(buf[:]); C.callGoStackCheck() } +func stack104() { var buf [104]byte; use(buf[:]); C.callGoStackCheck() } +func stack108() { var buf [108]byte; use(buf[:]); C.callGoStackCheck() } +func stack112() { var buf [112]byte; use(buf[:]); C.callGoStackCheck() } +func stack116() { var buf [116]byte; use(buf[:]); C.callGoStackCheck() } +func stack120() { var buf [120]byte; use(buf[:]); C.callGoStackCheck() } +func stack124() { var buf [124]byte; use(buf[:]); C.callGoStackCheck() } +func stack128() { var buf [128]byte; use(buf[:]); C.callGoStackCheck() } +func stack132() { var buf [132]byte; use(buf[:]); C.callGoStackCheck() } +func stack136() { var buf [136]byte; use(buf[:]); C.callGoStackCheck() } +func stack140() { var buf [140]byte; use(buf[:]); C.callGoStackCheck() } +func stack144() { var buf [144]byte; use(buf[:]); C.callGoStackCheck() } +func stack148() { var buf [148]byte; use(buf[:]); C.callGoStackCheck() } +func stack152() { var buf [152]byte; use(buf[:]); C.callGoStackCheck() } +func stack156() { var buf [156]byte; use(buf[:]); C.callGoStackCheck() } +func stack160() { var buf [160]byte; use(buf[:]); C.callGoStackCheck() } +func stack164() { var buf [164]byte; use(buf[:]); C.callGoStackCheck() } +func stack168() { var buf [168]byte; use(buf[:]); C.callGoStackCheck() } +func stack172() { var buf [172]byte; use(buf[:]); C.callGoStackCheck() } +func stack176() { var buf [176]byte; use(buf[:]); C.callGoStackCheck() } +func stack180() { var buf [180]byte; use(buf[:]); C.callGoStackCheck() } +func stack184() { var buf [184]byte; use(buf[:]); C.callGoStackCheck() } +func stack188() { var buf [188]byte; use(buf[:]); C.callGoStackCheck() } +func stack192() { var buf [192]byte; use(buf[:]); C.callGoStackCheck() } +func stack196() { var buf [196]byte; use(buf[:]); C.callGoStackCheck() } +func stack200() { var buf [200]byte; use(buf[:]); C.callGoStackCheck() } +func stack204() { var buf [204]byte; use(buf[:]); C.callGoStackCheck() } +func stack208() { var buf [208]byte; use(buf[:]); C.callGoStackCheck() } +func stack212() { var buf [212]byte; use(buf[:]); C.callGoStackCheck() } +func stack216() { var buf [216]byte; use(buf[:]); C.callGoStackCheck() } +func stack220() { var buf [220]byte; use(buf[:]); C.callGoStackCheck() } +func stack224() { var buf [224]byte; use(buf[:]); C.callGoStackCheck() } +func stack228() { var buf [228]byte; use(buf[:]); C.callGoStackCheck() } +func stack232() { var buf [232]byte; use(buf[:]); C.callGoStackCheck() } +func stack236() { var buf [236]byte; use(buf[:]); C.callGoStackCheck() } +func stack240() { var buf [240]byte; use(buf[:]); C.callGoStackCheck() } +func stack244() { var buf [244]byte; use(buf[:]); C.callGoStackCheck() } +func stack248() { var buf [248]byte; use(buf[:]); C.callGoStackCheck() } +func stack252() { var buf [252]byte; use(buf[:]); C.callGoStackCheck() } +func stack256() { var buf [256]byte; use(buf[:]); C.callGoStackCheck() } +func stack260() { var buf [260]byte; use(buf[:]); C.callGoStackCheck() } +func stack264() { var buf [264]byte; use(buf[:]); C.callGoStackCheck() } +func stack268() { var buf [268]byte; use(buf[:]); C.callGoStackCheck() } +func stack272() { var buf [272]byte; use(buf[:]); C.callGoStackCheck() } +func stack276() { var buf [276]byte; use(buf[:]); C.callGoStackCheck() } +func stack280() { var buf [280]byte; use(buf[:]); C.callGoStackCheck() } +func stack284() { var buf [284]byte; use(buf[:]); C.callGoStackCheck() } +func stack288() { var buf [288]byte; use(buf[:]); C.callGoStackCheck() } +func stack292() { var buf [292]byte; use(buf[:]); C.callGoStackCheck() } +func stack296() { var buf [296]byte; use(buf[:]); C.callGoStackCheck() } +func stack300() { var buf [300]byte; use(buf[:]); C.callGoStackCheck() } +func stack304() { var buf [304]byte; use(buf[:]); C.callGoStackCheck() } +func stack308() { var buf [308]byte; use(buf[:]); C.callGoStackCheck() } +func stack312() { var buf [312]byte; use(buf[:]); C.callGoStackCheck() } +func stack316() { var buf [316]byte; use(buf[:]); C.callGoStackCheck() } +func stack320() { var buf [320]byte; use(buf[:]); C.callGoStackCheck() } +func stack324() { var buf [324]byte; use(buf[:]); C.callGoStackCheck() } +func stack328() { var buf [328]byte; use(buf[:]); C.callGoStackCheck() } +func stack332() { var buf [332]byte; use(buf[:]); C.callGoStackCheck() } +func stack336() { var buf [336]byte; use(buf[:]); C.callGoStackCheck() } +func stack340() { var buf [340]byte; use(buf[:]); C.callGoStackCheck() } +func stack344() { var buf [344]byte; use(buf[:]); C.callGoStackCheck() } +func stack348() { var buf [348]byte; use(buf[:]); C.callGoStackCheck() } +func stack352() { var buf [352]byte; use(buf[:]); C.callGoStackCheck() } +func stack356() { var buf [356]byte; use(buf[:]); C.callGoStackCheck() } +func stack360() { var buf [360]byte; use(buf[:]); C.callGoStackCheck() } +func stack364() { var buf [364]byte; use(buf[:]); C.callGoStackCheck() } +func stack368() { var buf [368]byte; use(buf[:]); C.callGoStackCheck() } +func stack372() { var buf [372]byte; use(buf[:]); C.callGoStackCheck() } +func stack376() { var buf [376]byte; use(buf[:]); C.callGoStackCheck() } +func stack380() { var buf [380]byte; use(buf[:]); C.callGoStackCheck() } +func stack384() { var buf [384]byte; use(buf[:]); C.callGoStackCheck() } +func stack388() { var buf [388]byte; use(buf[:]); C.callGoStackCheck() } +func stack392() { var buf [392]byte; use(buf[:]); C.callGoStackCheck() } +func stack396() { var buf [396]byte; use(buf[:]); C.callGoStackCheck() } +func stack400() { var buf [400]byte; use(buf[:]); C.callGoStackCheck() } +func stack404() { var buf [404]byte; use(buf[:]); C.callGoStackCheck() } +func stack408() { var buf [408]byte; use(buf[:]); C.callGoStackCheck() } +func stack412() { var buf [412]byte; use(buf[:]); C.callGoStackCheck() } +func stack416() { var buf [416]byte; use(buf[:]); C.callGoStackCheck() } +func stack420() { var buf [420]byte; use(buf[:]); C.callGoStackCheck() } +func stack424() { var buf [424]byte; use(buf[:]); C.callGoStackCheck() } +func stack428() { var buf [428]byte; use(buf[:]); C.callGoStackCheck() } +func stack432() { var buf [432]byte; use(buf[:]); C.callGoStackCheck() } +func stack436() { var buf [436]byte; use(buf[:]); C.callGoStackCheck() } +func stack440() { var buf [440]byte; use(buf[:]); C.callGoStackCheck() } +func stack444() { var buf [444]byte; use(buf[:]); C.callGoStackCheck() } +func stack448() { var buf [448]byte; use(buf[:]); C.callGoStackCheck() } +func stack452() { var buf [452]byte; use(buf[:]); C.callGoStackCheck() } +func stack456() { var buf [456]byte; use(buf[:]); C.callGoStackCheck() } +func stack460() { var buf [460]byte; use(buf[:]); C.callGoStackCheck() } +func stack464() { var buf [464]byte; use(buf[:]); C.callGoStackCheck() } +func stack468() { var buf [468]byte; use(buf[:]); C.callGoStackCheck() } +func stack472() { var buf [472]byte; use(buf[:]); C.callGoStackCheck() } +func stack476() { var buf [476]byte; use(buf[:]); C.callGoStackCheck() } +func stack480() { var buf [480]byte; use(buf[:]); C.callGoStackCheck() } +func stack484() { var buf [484]byte; use(buf[:]); C.callGoStackCheck() } +func stack488() { var buf [488]byte; use(buf[:]); C.callGoStackCheck() } +func stack492() { var buf [492]byte; use(buf[:]); C.callGoStackCheck() } +func stack496() { var buf [496]byte; use(buf[:]); C.callGoStackCheck() } +func stack500() { var buf [500]byte; use(buf[:]); C.callGoStackCheck() } +func stack504() { var buf [504]byte; use(buf[:]); C.callGoStackCheck() } +func stack508() { var buf [508]byte; use(buf[:]); C.callGoStackCheck() } +func stack512() { var buf [512]byte; use(buf[:]); C.callGoStackCheck() } +func stack516() { var buf [516]byte; use(buf[:]); C.callGoStackCheck() } +func stack520() { var buf [520]byte; use(buf[:]); C.callGoStackCheck() } +func stack524() { var buf [524]byte; use(buf[:]); C.callGoStackCheck() } +func stack528() { var buf [528]byte; use(buf[:]); C.callGoStackCheck() } +func stack532() { var buf [532]byte; use(buf[:]); C.callGoStackCheck() } +func stack536() { var buf [536]byte; use(buf[:]); C.callGoStackCheck() } +func stack540() { var buf [540]byte; use(buf[:]); C.callGoStackCheck() } +func stack544() { var buf [544]byte; use(buf[:]); C.callGoStackCheck() } +func stack548() { var buf [548]byte; use(buf[:]); C.callGoStackCheck() } +func stack552() { var buf [552]byte; use(buf[:]); C.callGoStackCheck() } +func stack556() { var buf [556]byte; use(buf[:]); C.callGoStackCheck() } +func stack560() { var buf [560]byte; use(buf[:]); C.callGoStackCheck() } +func stack564() { var buf [564]byte; use(buf[:]); C.callGoStackCheck() } +func stack568() { var buf [568]byte; use(buf[:]); C.callGoStackCheck() } +func stack572() { var buf [572]byte; use(buf[:]); C.callGoStackCheck() } +func stack576() { var buf [576]byte; use(buf[:]); C.callGoStackCheck() } +func stack580() { var buf [580]byte; use(buf[:]); C.callGoStackCheck() } +func stack584() { var buf [584]byte; use(buf[:]); C.callGoStackCheck() } +func stack588() { var buf [588]byte; use(buf[:]); C.callGoStackCheck() } +func stack592() { var buf [592]byte; use(buf[:]); C.callGoStackCheck() } +func stack596() { var buf [596]byte; use(buf[:]); C.callGoStackCheck() } +func stack600() { var buf [600]byte; use(buf[:]); C.callGoStackCheck() } +func stack604() { var buf [604]byte; use(buf[:]); C.callGoStackCheck() } +func stack608() { var buf [608]byte; use(buf[:]); C.callGoStackCheck() } +func stack612() { var buf [612]byte; use(buf[:]); C.callGoStackCheck() } +func stack616() { var buf [616]byte; use(buf[:]); C.callGoStackCheck() } +func stack620() { var buf [620]byte; use(buf[:]); C.callGoStackCheck() } +func stack624() { var buf [624]byte; use(buf[:]); C.callGoStackCheck() } +func stack628() { var buf [628]byte; use(buf[:]); C.callGoStackCheck() } +func stack632() { var buf [632]byte; use(buf[:]); C.callGoStackCheck() } +func stack636() { var buf [636]byte; use(buf[:]); C.callGoStackCheck() } +func stack640() { var buf [640]byte; use(buf[:]); C.callGoStackCheck() } +func stack644() { var buf [644]byte; use(buf[:]); C.callGoStackCheck() } +func stack648() { var buf [648]byte; use(buf[:]); C.callGoStackCheck() } +func stack652() { var buf [652]byte; use(buf[:]); C.callGoStackCheck() } +func stack656() { var buf [656]byte; use(buf[:]); C.callGoStackCheck() } +func stack660() { var buf [660]byte; use(buf[:]); C.callGoStackCheck() } +func stack664() { var buf [664]byte; use(buf[:]); C.callGoStackCheck() } +func stack668() { var buf [668]byte; use(buf[:]); C.callGoStackCheck() } +func stack672() { var buf [672]byte; use(buf[:]); C.callGoStackCheck() } +func stack676() { var buf [676]byte; use(buf[:]); C.callGoStackCheck() } +func stack680() { var buf [680]byte; use(buf[:]); C.callGoStackCheck() } +func stack684() { var buf [684]byte; use(buf[:]); C.callGoStackCheck() } +func stack688() { var buf [688]byte; use(buf[:]); C.callGoStackCheck() } +func stack692() { var buf [692]byte; use(buf[:]); C.callGoStackCheck() } +func stack696() { var buf [696]byte; use(buf[:]); C.callGoStackCheck() } +func stack700() { var buf [700]byte; use(buf[:]); C.callGoStackCheck() } +func stack704() { var buf [704]byte; use(buf[:]); C.callGoStackCheck() } +func stack708() { var buf [708]byte; use(buf[:]); C.callGoStackCheck() } +func stack712() { var buf [712]byte; use(buf[:]); C.callGoStackCheck() } +func stack716() { var buf [716]byte; use(buf[:]); C.callGoStackCheck() } +func stack720() { var buf [720]byte; use(buf[:]); C.callGoStackCheck() } +func stack724() { var buf [724]byte; use(buf[:]); C.callGoStackCheck() } +func stack728() { var buf [728]byte; use(buf[:]); C.callGoStackCheck() } +func stack732() { var buf [732]byte; use(buf[:]); C.callGoStackCheck() } +func stack736() { var buf [736]byte; use(buf[:]); C.callGoStackCheck() } +func stack740() { var buf [740]byte; use(buf[:]); C.callGoStackCheck() } +func stack744() { var buf [744]byte; use(buf[:]); C.callGoStackCheck() } +func stack748() { var buf [748]byte; use(buf[:]); C.callGoStackCheck() } +func stack752() { var buf [752]byte; use(buf[:]); C.callGoStackCheck() } +func stack756() { var buf [756]byte; use(buf[:]); C.callGoStackCheck() } +func stack760() { var buf [760]byte; use(buf[:]); C.callGoStackCheck() } +func stack764() { var buf [764]byte; use(buf[:]); C.callGoStackCheck() } +func stack768() { var buf [768]byte; use(buf[:]); C.callGoStackCheck() } +func stack772() { var buf [772]byte; use(buf[:]); C.callGoStackCheck() } +func stack776() { var buf [776]byte; use(buf[:]); C.callGoStackCheck() } +func stack780() { var buf [780]byte; use(buf[:]); C.callGoStackCheck() } +func stack784() { var buf [784]byte; use(buf[:]); C.callGoStackCheck() } +func stack788() { var buf [788]byte; use(buf[:]); C.callGoStackCheck() } +func stack792() { var buf [792]byte; use(buf[:]); C.callGoStackCheck() } +func stack796() { var buf [796]byte; use(buf[:]); C.callGoStackCheck() } +func stack800() { var buf [800]byte; use(buf[:]); C.callGoStackCheck() } +func stack804() { var buf [804]byte; use(buf[:]); C.callGoStackCheck() } +func stack808() { var buf [808]byte; use(buf[:]); C.callGoStackCheck() } +func stack812() { var buf [812]byte; use(buf[:]); C.callGoStackCheck() } +func stack816() { var buf [816]byte; use(buf[:]); C.callGoStackCheck() } +func stack820() { var buf [820]byte; use(buf[:]); C.callGoStackCheck() } +func stack824() { var buf [824]byte; use(buf[:]); C.callGoStackCheck() } +func stack828() { var buf [828]byte; use(buf[:]); C.callGoStackCheck() } +func stack832() { var buf [832]byte; use(buf[:]); C.callGoStackCheck() } +func stack836() { var buf [836]byte; use(buf[:]); C.callGoStackCheck() } +func stack840() { var buf [840]byte; use(buf[:]); C.callGoStackCheck() } +func stack844() { var buf [844]byte; use(buf[:]); C.callGoStackCheck() } +func stack848() { var buf [848]byte; use(buf[:]); C.callGoStackCheck() } +func stack852() { var buf [852]byte; use(buf[:]); C.callGoStackCheck() } +func stack856() { var buf [856]byte; use(buf[:]); C.callGoStackCheck() } +func stack860() { var buf [860]byte; use(buf[:]); C.callGoStackCheck() } +func stack864() { var buf [864]byte; use(buf[:]); C.callGoStackCheck() } +func stack868() { var buf [868]byte; use(buf[:]); C.callGoStackCheck() } +func stack872() { var buf [872]byte; use(buf[:]); C.callGoStackCheck() } +func stack876() { var buf [876]byte; use(buf[:]); C.callGoStackCheck() } +func stack880() { var buf [880]byte; use(buf[:]); C.callGoStackCheck() } +func stack884() { var buf [884]byte; use(buf[:]); C.callGoStackCheck() } +func stack888() { var buf [888]byte; use(buf[:]); C.callGoStackCheck() } +func stack892() { var buf [892]byte; use(buf[:]); C.callGoStackCheck() } +func stack896() { var buf [896]byte; use(buf[:]); C.callGoStackCheck() } +func stack900() { var buf [900]byte; use(buf[:]); C.callGoStackCheck() } +func stack904() { var buf [904]byte; use(buf[:]); C.callGoStackCheck() } +func stack908() { var buf [908]byte; use(buf[:]); C.callGoStackCheck() } +func stack912() { var buf [912]byte; use(buf[:]); C.callGoStackCheck() } +func stack916() { var buf [916]byte; use(buf[:]); C.callGoStackCheck() } +func stack920() { var buf [920]byte; use(buf[:]); C.callGoStackCheck() } +func stack924() { var buf [924]byte; use(buf[:]); C.callGoStackCheck() } +func stack928() { var buf [928]byte; use(buf[:]); C.callGoStackCheck() } +func stack932() { var buf [932]byte; use(buf[:]); C.callGoStackCheck() } +func stack936() { var buf [936]byte; use(buf[:]); C.callGoStackCheck() } +func stack940() { var buf [940]byte; use(buf[:]); C.callGoStackCheck() } +func stack944() { var buf [944]byte; use(buf[:]); C.callGoStackCheck() } +func stack948() { var buf [948]byte; use(buf[:]); C.callGoStackCheck() } +func stack952() { var buf [952]byte; use(buf[:]); C.callGoStackCheck() } +func stack956() { var buf [956]byte; use(buf[:]); C.callGoStackCheck() } +func stack960() { var buf [960]byte; use(buf[:]); C.callGoStackCheck() } +func stack964() { var buf [964]byte; use(buf[:]); C.callGoStackCheck() } +func stack968() { var buf [968]byte; use(buf[:]); C.callGoStackCheck() } +func stack972() { var buf [972]byte; use(buf[:]); C.callGoStackCheck() } +func stack976() { var buf [976]byte; use(buf[:]); C.callGoStackCheck() } +func stack980() { var buf [980]byte; use(buf[:]); C.callGoStackCheck() } +func stack984() { var buf [984]byte; use(buf[:]); C.callGoStackCheck() } +func stack988() { var buf [988]byte; use(buf[:]); C.callGoStackCheck() } +func stack992() { var buf [992]byte; use(buf[:]); C.callGoStackCheck() } +func stack996() { var buf [996]byte; use(buf[:]); C.callGoStackCheck() } +func stack1000() { var buf [1000]byte; use(buf[:]); C.callGoStackCheck() } +func stack1004() { var buf [1004]byte; use(buf[:]); C.callGoStackCheck() } +func stack1008() { var buf [1008]byte; use(buf[:]); C.callGoStackCheck() } +func stack1012() { var buf [1012]byte; use(buf[:]); C.callGoStackCheck() } +func stack1016() { var buf [1016]byte; use(buf[:]); C.callGoStackCheck() } +func stack1020() { var buf [1020]byte; use(buf[:]); C.callGoStackCheck() } +func stack1024() { var buf [1024]byte; use(buf[:]); C.callGoStackCheck() } +func stack1028() { var buf [1028]byte; use(buf[:]); C.callGoStackCheck() } +func stack1032() { var buf [1032]byte; use(buf[:]); C.callGoStackCheck() } +func stack1036() { var buf [1036]byte; use(buf[:]); C.callGoStackCheck() } +func stack1040() { var buf [1040]byte; use(buf[:]); C.callGoStackCheck() } +func stack1044() { var buf [1044]byte; use(buf[:]); C.callGoStackCheck() } +func stack1048() { var buf [1048]byte; use(buf[:]); C.callGoStackCheck() } +func stack1052() { var buf [1052]byte; use(buf[:]); C.callGoStackCheck() } +func stack1056() { var buf [1056]byte; use(buf[:]); C.callGoStackCheck() } +func stack1060() { var buf [1060]byte; use(buf[:]); C.callGoStackCheck() } +func stack1064() { var buf [1064]byte; use(buf[:]); C.callGoStackCheck() } +func stack1068() { var buf [1068]byte; use(buf[:]); C.callGoStackCheck() } +func stack1072() { var buf [1072]byte; use(buf[:]); C.callGoStackCheck() } +func stack1076() { var buf [1076]byte; use(buf[:]); C.callGoStackCheck() } +func stack1080() { var buf [1080]byte; use(buf[:]); C.callGoStackCheck() } +func stack1084() { var buf [1084]byte; use(buf[:]); C.callGoStackCheck() } +func stack1088() { var buf [1088]byte; use(buf[:]); C.callGoStackCheck() } +func stack1092() { var buf [1092]byte; use(buf[:]); C.callGoStackCheck() } +func stack1096() { var buf [1096]byte; use(buf[:]); C.callGoStackCheck() } +func stack1100() { var buf [1100]byte; use(buf[:]); C.callGoStackCheck() } +func stack1104() { var buf [1104]byte; use(buf[:]); C.callGoStackCheck() } +func stack1108() { var buf [1108]byte; use(buf[:]); C.callGoStackCheck() } +func stack1112() { var buf [1112]byte; use(buf[:]); C.callGoStackCheck() } +func stack1116() { var buf [1116]byte; use(buf[:]); C.callGoStackCheck() } +func stack1120() { var buf [1120]byte; use(buf[:]); C.callGoStackCheck() } +func stack1124() { var buf [1124]byte; use(buf[:]); C.callGoStackCheck() } +func stack1128() { var buf [1128]byte; use(buf[:]); C.callGoStackCheck() } +func stack1132() { var buf [1132]byte; use(buf[:]); C.callGoStackCheck() } +func stack1136() { var buf [1136]byte; use(buf[:]); C.callGoStackCheck() } +func stack1140() { var buf [1140]byte; use(buf[:]); C.callGoStackCheck() } +func stack1144() { var buf [1144]byte; use(buf[:]); C.callGoStackCheck() } +func stack1148() { var buf [1148]byte; use(buf[:]); C.callGoStackCheck() } +func stack1152() { var buf [1152]byte; use(buf[:]); C.callGoStackCheck() } +func stack1156() { var buf [1156]byte; use(buf[:]); C.callGoStackCheck() } +func stack1160() { var buf [1160]byte; use(buf[:]); C.callGoStackCheck() } +func stack1164() { var buf [1164]byte; use(buf[:]); C.callGoStackCheck() } +func stack1168() { var buf [1168]byte; use(buf[:]); C.callGoStackCheck() } +func stack1172() { var buf [1172]byte; use(buf[:]); C.callGoStackCheck() } +func stack1176() { var buf [1176]byte; use(buf[:]); C.callGoStackCheck() } +func stack1180() { var buf [1180]byte; use(buf[:]); C.callGoStackCheck() } +func stack1184() { var buf [1184]byte; use(buf[:]); C.callGoStackCheck() } +func stack1188() { var buf [1188]byte; use(buf[:]); C.callGoStackCheck() } +func stack1192() { var buf [1192]byte; use(buf[:]); C.callGoStackCheck() } +func stack1196() { var buf [1196]byte; use(buf[:]); C.callGoStackCheck() } +func stack1200() { var buf [1200]byte; use(buf[:]); C.callGoStackCheck() } +func stack1204() { var buf [1204]byte; use(buf[:]); C.callGoStackCheck() } +func stack1208() { var buf [1208]byte; use(buf[:]); C.callGoStackCheck() } +func stack1212() { var buf [1212]byte; use(buf[:]); C.callGoStackCheck() } +func stack1216() { var buf [1216]byte; use(buf[:]); C.callGoStackCheck() } +func stack1220() { var buf [1220]byte; use(buf[:]); C.callGoStackCheck() } +func stack1224() { var buf [1224]byte; use(buf[:]); C.callGoStackCheck() } +func stack1228() { var buf [1228]byte; use(buf[:]); C.callGoStackCheck() } +func stack1232() { var buf [1232]byte; use(buf[:]); C.callGoStackCheck() } +func stack1236() { var buf [1236]byte; use(buf[:]); C.callGoStackCheck() } +func stack1240() { var buf [1240]byte; use(buf[:]); C.callGoStackCheck() } +func stack1244() { var buf [1244]byte; use(buf[:]); C.callGoStackCheck() } +func stack1248() { var buf [1248]byte; use(buf[:]); C.callGoStackCheck() } +func stack1252() { var buf [1252]byte; use(buf[:]); C.callGoStackCheck() } +func stack1256() { var buf [1256]byte; use(buf[:]); C.callGoStackCheck() } +func stack1260() { var buf [1260]byte; use(buf[:]); C.callGoStackCheck() } +func stack1264() { var buf [1264]byte; use(buf[:]); C.callGoStackCheck() } +func stack1268() { var buf [1268]byte; use(buf[:]); C.callGoStackCheck() } +func stack1272() { var buf [1272]byte; use(buf[:]); C.callGoStackCheck() } +func stack1276() { var buf [1276]byte; use(buf[:]); C.callGoStackCheck() } +func stack1280() { var buf [1280]byte; use(buf[:]); C.callGoStackCheck() } +func stack1284() { var buf [1284]byte; use(buf[:]); C.callGoStackCheck() } +func stack1288() { var buf [1288]byte; use(buf[:]); C.callGoStackCheck() } +func stack1292() { var buf [1292]byte; use(buf[:]); C.callGoStackCheck() } +func stack1296() { var buf [1296]byte; use(buf[:]); C.callGoStackCheck() } +func stack1300() { var buf [1300]byte; use(buf[:]); C.callGoStackCheck() } +func stack1304() { var buf [1304]byte; use(buf[:]); C.callGoStackCheck() } +func stack1308() { var buf [1308]byte; use(buf[:]); C.callGoStackCheck() } +func stack1312() { var buf [1312]byte; use(buf[:]); C.callGoStackCheck() } +func stack1316() { var buf [1316]byte; use(buf[:]); C.callGoStackCheck() } +func stack1320() { var buf [1320]byte; use(buf[:]); C.callGoStackCheck() } +func stack1324() { var buf [1324]byte; use(buf[:]); C.callGoStackCheck() } +func stack1328() { var buf [1328]byte; use(buf[:]); C.callGoStackCheck() } +func stack1332() { var buf [1332]byte; use(buf[:]); C.callGoStackCheck() } +func stack1336() { var buf [1336]byte; use(buf[:]); C.callGoStackCheck() } +func stack1340() { var buf [1340]byte; use(buf[:]); C.callGoStackCheck() } +func stack1344() { var buf [1344]byte; use(buf[:]); C.callGoStackCheck() } +func stack1348() { var buf [1348]byte; use(buf[:]); C.callGoStackCheck() } +func stack1352() { var buf [1352]byte; use(buf[:]); C.callGoStackCheck() } +func stack1356() { var buf [1356]byte; use(buf[:]); C.callGoStackCheck() } +func stack1360() { var buf [1360]byte; use(buf[:]); C.callGoStackCheck() } +func stack1364() { var buf [1364]byte; use(buf[:]); C.callGoStackCheck() } +func stack1368() { var buf [1368]byte; use(buf[:]); C.callGoStackCheck() } +func stack1372() { var buf [1372]byte; use(buf[:]); C.callGoStackCheck() } +func stack1376() { var buf [1376]byte; use(buf[:]); C.callGoStackCheck() } +func stack1380() { var buf [1380]byte; use(buf[:]); C.callGoStackCheck() } +func stack1384() { var buf [1384]byte; use(buf[:]); C.callGoStackCheck() } +func stack1388() { var buf [1388]byte; use(buf[:]); C.callGoStackCheck() } +func stack1392() { var buf [1392]byte; use(buf[:]); C.callGoStackCheck() } +func stack1396() { var buf [1396]byte; use(buf[:]); C.callGoStackCheck() } +func stack1400() { var buf [1400]byte; use(buf[:]); C.callGoStackCheck() } +func stack1404() { var buf [1404]byte; use(buf[:]); C.callGoStackCheck() } +func stack1408() { var buf [1408]byte; use(buf[:]); C.callGoStackCheck() } +func stack1412() { var buf [1412]byte; use(buf[:]); C.callGoStackCheck() } +func stack1416() { var buf [1416]byte; use(buf[:]); C.callGoStackCheck() } +func stack1420() { var buf [1420]byte; use(buf[:]); C.callGoStackCheck() } +func stack1424() { var buf [1424]byte; use(buf[:]); C.callGoStackCheck() } +func stack1428() { var buf [1428]byte; use(buf[:]); C.callGoStackCheck() } +func stack1432() { var buf [1432]byte; use(buf[:]); C.callGoStackCheck() } +func stack1436() { var buf [1436]byte; use(buf[:]); C.callGoStackCheck() } +func stack1440() { var buf [1440]byte; use(buf[:]); C.callGoStackCheck() } +func stack1444() { var buf [1444]byte; use(buf[:]); C.callGoStackCheck() } +func stack1448() { var buf [1448]byte; use(buf[:]); C.callGoStackCheck() } +func stack1452() { var buf [1452]byte; use(buf[:]); C.callGoStackCheck() } +func stack1456() { var buf [1456]byte; use(buf[:]); C.callGoStackCheck() } +func stack1460() { var buf [1460]byte; use(buf[:]); C.callGoStackCheck() } +func stack1464() { var buf [1464]byte; use(buf[:]); C.callGoStackCheck() } +func stack1468() { var buf [1468]byte; use(buf[:]); C.callGoStackCheck() } +func stack1472() { var buf [1472]byte; use(buf[:]); C.callGoStackCheck() } +func stack1476() { var buf [1476]byte; use(buf[:]); C.callGoStackCheck() } +func stack1480() { var buf [1480]byte; use(buf[:]); C.callGoStackCheck() } +func stack1484() { var buf [1484]byte; use(buf[:]); C.callGoStackCheck() } +func stack1488() { var buf [1488]byte; use(buf[:]); C.callGoStackCheck() } +func stack1492() { var buf [1492]byte; use(buf[:]); C.callGoStackCheck() } +func stack1496() { var buf [1496]byte; use(buf[:]); C.callGoStackCheck() } +func stack1500() { var buf [1500]byte; use(buf[:]); C.callGoStackCheck() } +func stack1504() { var buf [1504]byte; use(buf[:]); C.callGoStackCheck() } +func stack1508() { var buf [1508]byte; use(buf[:]); C.callGoStackCheck() } +func stack1512() { var buf [1512]byte; use(buf[:]); C.callGoStackCheck() } +func stack1516() { var buf [1516]byte; use(buf[:]); C.callGoStackCheck() } +func stack1520() { var buf [1520]byte; use(buf[:]); C.callGoStackCheck() } +func stack1524() { var buf [1524]byte; use(buf[:]); C.callGoStackCheck() } +func stack1528() { var buf [1528]byte; use(buf[:]); C.callGoStackCheck() } +func stack1532() { var buf [1532]byte; use(buf[:]); C.callGoStackCheck() } +func stack1536() { var buf [1536]byte; use(buf[:]); C.callGoStackCheck() } +func stack1540() { var buf [1540]byte; use(buf[:]); C.callGoStackCheck() } +func stack1544() { var buf [1544]byte; use(buf[:]); C.callGoStackCheck() } +func stack1548() { var buf [1548]byte; use(buf[:]); C.callGoStackCheck() } +func stack1552() { var buf [1552]byte; use(buf[:]); C.callGoStackCheck() } +func stack1556() { var buf [1556]byte; use(buf[:]); C.callGoStackCheck() } +func stack1560() { var buf [1560]byte; use(buf[:]); C.callGoStackCheck() } +func stack1564() { var buf [1564]byte; use(buf[:]); C.callGoStackCheck() } +func stack1568() { var buf [1568]byte; use(buf[:]); C.callGoStackCheck() } +func stack1572() { var buf [1572]byte; use(buf[:]); C.callGoStackCheck() } +func stack1576() { var buf [1576]byte; use(buf[:]); C.callGoStackCheck() } +func stack1580() { var buf [1580]byte; use(buf[:]); C.callGoStackCheck() } +func stack1584() { var buf [1584]byte; use(buf[:]); C.callGoStackCheck() } +func stack1588() { var buf [1588]byte; use(buf[:]); C.callGoStackCheck() } +func stack1592() { var buf [1592]byte; use(buf[:]); C.callGoStackCheck() } +func stack1596() { var buf [1596]byte; use(buf[:]); C.callGoStackCheck() } +func stack1600() { var buf [1600]byte; use(buf[:]); C.callGoStackCheck() } +func stack1604() { var buf [1604]byte; use(buf[:]); C.callGoStackCheck() } +func stack1608() { var buf [1608]byte; use(buf[:]); C.callGoStackCheck() } +func stack1612() { var buf [1612]byte; use(buf[:]); C.callGoStackCheck() } +func stack1616() { var buf [1616]byte; use(buf[:]); C.callGoStackCheck() } +func stack1620() { var buf [1620]byte; use(buf[:]); C.callGoStackCheck() } +func stack1624() { var buf [1624]byte; use(buf[:]); C.callGoStackCheck() } +func stack1628() { var buf [1628]byte; use(buf[:]); C.callGoStackCheck() } +func stack1632() { var buf [1632]byte; use(buf[:]); C.callGoStackCheck() } +func stack1636() { var buf [1636]byte; use(buf[:]); C.callGoStackCheck() } +func stack1640() { var buf [1640]byte; use(buf[:]); C.callGoStackCheck() } +func stack1644() { var buf [1644]byte; use(buf[:]); C.callGoStackCheck() } +func stack1648() { var buf [1648]byte; use(buf[:]); C.callGoStackCheck() } +func stack1652() { var buf [1652]byte; use(buf[:]); C.callGoStackCheck() } +func stack1656() { var buf [1656]byte; use(buf[:]); C.callGoStackCheck() } +func stack1660() { var buf [1660]byte; use(buf[:]); C.callGoStackCheck() } +func stack1664() { var buf [1664]byte; use(buf[:]); C.callGoStackCheck() } +func stack1668() { var buf [1668]byte; use(buf[:]); C.callGoStackCheck() } +func stack1672() { var buf [1672]byte; use(buf[:]); C.callGoStackCheck() } +func stack1676() { var buf [1676]byte; use(buf[:]); C.callGoStackCheck() } +func stack1680() { var buf [1680]byte; use(buf[:]); C.callGoStackCheck() } +func stack1684() { var buf [1684]byte; use(buf[:]); C.callGoStackCheck() } +func stack1688() { var buf [1688]byte; use(buf[:]); C.callGoStackCheck() } +func stack1692() { var buf [1692]byte; use(buf[:]); C.callGoStackCheck() } +func stack1696() { var buf [1696]byte; use(buf[:]); C.callGoStackCheck() } +func stack1700() { var buf [1700]byte; use(buf[:]); C.callGoStackCheck() } +func stack1704() { var buf [1704]byte; use(buf[:]); C.callGoStackCheck() } +func stack1708() { var buf [1708]byte; use(buf[:]); C.callGoStackCheck() } +func stack1712() { var buf [1712]byte; use(buf[:]); C.callGoStackCheck() } +func stack1716() { var buf [1716]byte; use(buf[:]); C.callGoStackCheck() } +func stack1720() { var buf [1720]byte; use(buf[:]); C.callGoStackCheck() } +func stack1724() { var buf [1724]byte; use(buf[:]); C.callGoStackCheck() } +func stack1728() { var buf [1728]byte; use(buf[:]); C.callGoStackCheck() } +func stack1732() { var buf [1732]byte; use(buf[:]); C.callGoStackCheck() } +func stack1736() { var buf [1736]byte; use(buf[:]); C.callGoStackCheck() } +func stack1740() { var buf [1740]byte; use(buf[:]); C.callGoStackCheck() } +func stack1744() { var buf [1744]byte; use(buf[:]); C.callGoStackCheck() } +func stack1748() { var buf [1748]byte; use(buf[:]); C.callGoStackCheck() } +func stack1752() { var buf [1752]byte; use(buf[:]); C.callGoStackCheck() } +func stack1756() { var buf [1756]byte; use(buf[:]); C.callGoStackCheck() } +func stack1760() { var buf [1760]byte; use(buf[:]); C.callGoStackCheck() } +func stack1764() { var buf [1764]byte; use(buf[:]); C.callGoStackCheck() } +func stack1768() { var buf [1768]byte; use(buf[:]); C.callGoStackCheck() } +func stack1772() { var buf [1772]byte; use(buf[:]); C.callGoStackCheck() } +func stack1776() { var buf [1776]byte; use(buf[:]); C.callGoStackCheck() } +func stack1780() { var buf [1780]byte; use(buf[:]); C.callGoStackCheck() } +func stack1784() { var buf [1784]byte; use(buf[:]); C.callGoStackCheck() } +func stack1788() { var buf [1788]byte; use(buf[:]); C.callGoStackCheck() } +func stack1792() { var buf [1792]byte; use(buf[:]); C.callGoStackCheck() } +func stack1796() { var buf [1796]byte; use(buf[:]); C.callGoStackCheck() } +func stack1800() { var buf [1800]byte; use(buf[:]); C.callGoStackCheck() } +func stack1804() { var buf [1804]byte; use(buf[:]); C.callGoStackCheck() } +func stack1808() { var buf [1808]byte; use(buf[:]); C.callGoStackCheck() } +func stack1812() { var buf [1812]byte; use(buf[:]); C.callGoStackCheck() } +func stack1816() { var buf [1816]byte; use(buf[:]); C.callGoStackCheck() } +func stack1820() { var buf [1820]byte; use(buf[:]); C.callGoStackCheck() } +func stack1824() { var buf [1824]byte; use(buf[:]); C.callGoStackCheck() } +func stack1828() { var buf [1828]byte; use(buf[:]); C.callGoStackCheck() } +func stack1832() { var buf [1832]byte; use(buf[:]); C.callGoStackCheck() } +func stack1836() { var buf [1836]byte; use(buf[:]); C.callGoStackCheck() } +func stack1840() { var buf [1840]byte; use(buf[:]); C.callGoStackCheck() } +func stack1844() { var buf [1844]byte; use(buf[:]); C.callGoStackCheck() } +func stack1848() { var buf [1848]byte; use(buf[:]); C.callGoStackCheck() } +func stack1852() { var buf [1852]byte; use(buf[:]); C.callGoStackCheck() } +func stack1856() { var buf [1856]byte; use(buf[:]); C.callGoStackCheck() } +func stack1860() { var buf [1860]byte; use(buf[:]); C.callGoStackCheck() } +func stack1864() { var buf [1864]byte; use(buf[:]); C.callGoStackCheck() } +func stack1868() { var buf [1868]byte; use(buf[:]); C.callGoStackCheck() } +func stack1872() { var buf [1872]byte; use(buf[:]); C.callGoStackCheck() } +func stack1876() { var buf [1876]byte; use(buf[:]); C.callGoStackCheck() } +func stack1880() { var buf [1880]byte; use(buf[:]); C.callGoStackCheck() } +func stack1884() { var buf [1884]byte; use(buf[:]); C.callGoStackCheck() } +func stack1888() { var buf [1888]byte; use(buf[:]); C.callGoStackCheck() } +func stack1892() { var buf [1892]byte; use(buf[:]); C.callGoStackCheck() } +func stack1896() { var buf [1896]byte; use(buf[:]); C.callGoStackCheck() } +func stack1900() { var buf [1900]byte; use(buf[:]); C.callGoStackCheck() } +func stack1904() { var buf [1904]byte; use(buf[:]); C.callGoStackCheck() } +func stack1908() { var buf [1908]byte; use(buf[:]); C.callGoStackCheck() } +func stack1912() { var buf [1912]byte; use(buf[:]); C.callGoStackCheck() } +func stack1916() { var buf [1916]byte; use(buf[:]); C.callGoStackCheck() } +func stack1920() { var buf [1920]byte; use(buf[:]); C.callGoStackCheck() } +func stack1924() { var buf [1924]byte; use(buf[:]); C.callGoStackCheck() } +func stack1928() { var buf [1928]byte; use(buf[:]); C.callGoStackCheck() } +func stack1932() { var buf [1932]byte; use(buf[:]); C.callGoStackCheck() } +func stack1936() { var buf [1936]byte; use(buf[:]); C.callGoStackCheck() } +func stack1940() { var buf [1940]byte; use(buf[:]); C.callGoStackCheck() } +func stack1944() { var buf [1944]byte; use(buf[:]); C.callGoStackCheck() } +func stack1948() { var buf [1948]byte; use(buf[:]); C.callGoStackCheck() } +func stack1952() { var buf [1952]byte; use(buf[:]); C.callGoStackCheck() } +func stack1956() { var buf [1956]byte; use(buf[:]); C.callGoStackCheck() } +func stack1960() { var buf [1960]byte; use(buf[:]); C.callGoStackCheck() } +func stack1964() { var buf [1964]byte; use(buf[:]); C.callGoStackCheck() } +func stack1968() { var buf [1968]byte; use(buf[:]); C.callGoStackCheck() } +func stack1972() { var buf [1972]byte; use(buf[:]); C.callGoStackCheck() } +func stack1976() { var buf [1976]byte; use(buf[:]); C.callGoStackCheck() } +func stack1980() { var buf [1980]byte; use(buf[:]); C.callGoStackCheck() } +func stack1984() { var buf [1984]byte; use(buf[:]); C.callGoStackCheck() } +func stack1988() { var buf [1988]byte; use(buf[:]); C.callGoStackCheck() } +func stack1992() { var buf [1992]byte; use(buf[:]); C.callGoStackCheck() } +func stack1996() { var buf [1996]byte; use(buf[:]); C.callGoStackCheck() } +func stack2000() { var buf [2000]byte; use(buf[:]); C.callGoStackCheck() } +func stack2004() { var buf [2004]byte; use(buf[:]); C.callGoStackCheck() } +func stack2008() { var buf [2008]byte; use(buf[:]); C.callGoStackCheck() } +func stack2012() { var buf [2012]byte; use(buf[:]); C.callGoStackCheck() } +func stack2016() { var buf [2016]byte; use(buf[:]); C.callGoStackCheck() } +func stack2020() { var buf [2020]byte; use(buf[:]); C.callGoStackCheck() } +func stack2024() { var buf [2024]byte; use(buf[:]); C.callGoStackCheck() } +func stack2028() { var buf [2028]byte; use(buf[:]); C.callGoStackCheck() } +func stack2032() { var buf [2032]byte; use(buf[:]); C.callGoStackCheck() } +func stack2036() { var buf [2036]byte; use(buf[:]); C.callGoStackCheck() } +func stack2040() { var buf [2040]byte; use(buf[:]); C.callGoStackCheck() } +func stack2044() { var buf [2044]byte; use(buf[:]); C.callGoStackCheck() } +func stack2048() { var buf [2048]byte; use(buf[:]); C.callGoStackCheck() } +func stack2052() { var buf [2052]byte; use(buf[:]); C.callGoStackCheck() } +func stack2056() { var buf [2056]byte; use(buf[:]); C.callGoStackCheck() } +func stack2060() { var buf [2060]byte; use(buf[:]); C.callGoStackCheck() } +func stack2064() { var buf [2064]byte; use(buf[:]); C.callGoStackCheck() } +func stack2068() { var buf [2068]byte; use(buf[:]); C.callGoStackCheck() } +func stack2072() { var buf [2072]byte; use(buf[:]); C.callGoStackCheck() } +func stack2076() { var buf [2076]byte; use(buf[:]); C.callGoStackCheck() } +func stack2080() { var buf [2080]byte; use(buf[:]); C.callGoStackCheck() } +func stack2084() { var buf [2084]byte; use(buf[:]); C.callGoStackCheck() } +func stack2088() { var buf [2088]byte; use(buf[:]); C.callGoStackCheck() } +func stack2092() { var buf [2092]byte; use(buf[:]); C.callGoStackCheck() } +func stack2096() { var buf [2096]byte; use(buf[:]); C.callGoStackCheck() } +func stack2100() { var buf [2100]byte; use(buf[:]); C.callGoStackCheck() } +func stack2104() { var buf [2104]byte; use(buf[:]); C.callGoStackCheck() } +func stack2108() { var buf [2108]byte; use(buf[:]); C.callGoStackCheck() } +func stack2112() { var buf [2112]byte; use(buf[:]); C.callGoStackCheck() } +func stack2116() { var buf [2116]byte; use(buf[:]); C.callGoStackCheck() } +func stack2120() { var buf [2120]byte; use(buf[:]); C.callGoStackCheck() } +func stack2124() { var buf [2124]byte; use(buf[:]); C.callGoStackCheck() } +func stack2128() { var buf [2128]byte; use(buf[:]); C.callGoStackCheck() } +func stack2132() { var buf [2132]byte; use(buf[:]); C.callGoStackCheck() } +func stack2136() { var buf [2136]byte; use(buf[:]); C.callGoStackCheck() } +func stack2140() { var buf [2140]byte; use(buf[:]); C.callGoStackCheck() } +func stack2144() { var buf [2144]byte; use(buf[:]); C.callGoStackCheck() } +func stack2148() { var buf [2148]byte; use(buf[:]); C.callGoStackCheck() } +func stack2152() { var buf [2152]byte; use(buf[:]); C.callGoStackCheck() } +func stack2156() { var buf [2156]byte; use(buf[:]); C.callGoStackCheck() } +func stack2160() { var buf [2160]byte; use(buf[:]); C.callGoStackCheck() } +func stack2164() { var buf [2164]byte; use(buf[:]); C.callGoStackCheck() } +func stack2168() { var buf [2168]byte; use(buf[:]); C.callGoStackCheck() } +func stack2172() { var buf [2172]byte; use(buf[:]); C.callGoStackCheck() } +func stack2176() { var buf [2176]byte; use(buf[:]); C.callGoStackCheck() } +func stack2180() { var buf [2180]byte; use(buf[:]); C.callGoStackCheck() } +func stack2184() { var buf [2184]byte; use(buf[:]); C.callGoStackCheck() } +func stack2188() { var buf [2188]byte; use(buf[:]); C.callGoStackCheck() } +func stack2192() { var buf [2192]byte; use(buf[:]); C.callGoStackCheck() } +func stack2196() { var buf [2196]byte; use(buf[:]); C.callGoStackCheck() } +func stack2200() { var buf [2200]byte; use(buf[:]); C.callGoStackCheck() } +func stack2204() { var buf [2204]byte; use(buf[:]); C.callGoStackCheck() } +func stack2208() { var buf [2208]byte; use(buf[:]); C.callGoStackCheck() } +func stack2212() { var buf [2212]byte; use(buf[:]); C.callGoStackCheck() } +func stack2216() { var buf [2216]byte; use(buf[:]); C.callGoStackCheck() } +func stack2220() { var buf [2220]byte; use(buf[:]); C.callGoStackCheck() } +func stack2224() { var buf [2224]byte; use(buf[:]); C.callGoStackCheck() } +func stack2228() { var buf [2228]byte; use(buf[:]); C.callGoStackCheck() } +func stack2232() { var buf [2232]byte; use(buf[:]); C.callGoStackCheck() } +func stack2236() { var buf [2236]byte; use(buf[:]); C.callGoStackCheck() } +func stack2240() { var buf [2240]byte; use(buf[:]); C.callGoStackCheck() } +func stack2244() { var buf [2244]byte; use(buf[:]); C.callGoStackCheck() } +func stack2248() { var buf [2248]byte; use(buf[:]); C.callGoStackCheck() } +func stack2252() { var buf [2252]byte; use(buf[:]); C.callGoStackCheck() } +func stack2256() { var buf [2256]byte; use(buf[:]); C.callGoStackCheck() } +func stack2260() { var buf [2260]byte; use(buf[:]); C.callGoStackCheck() } +func stack2264() { var buf [2264]byte; use(buf[:]); C.callGoStackCheck() } +func stack2268() { var buf [2268]byte; use(buf[:]); C.callGoStackCheck() } +func stack2272() { var buf [2272]byte; use(buf[:]); C.callGoStackCheck() } +func stack2276() { var buf [2276]byte; use(buf[:]); C.callGoStackCheck() } +func stack2280() { var buf [2280]byte; use(buf[:]); C.callGoStackCheck() } +func stack2284() { var buf [2284]byte; use(buf[:]); C.callGoStackCheck() } +func stack2288() { var buf [2288]byte; use(buf[:]); C.callGoStackCheck() } +func stack2292() { var buf [2292]byte; use(buf[:]); C.callGoStackCheck() } +func stack2296() { var buf [2296]byte; use(buf[:]); C.callGoStackCheck() } +func stack2300() { var buf [2300]byte; use(buf[:]); C.callGoStackCheck() } +func stack2304() { var buf [2304]byte; use(buf[:]); C.callGoStackCheck() } +func stack2308() { var buf [2308]byte; use(buf[:]); C.callGoStackCheck() } +func stack2312() { var buf [2312]byte; use(buf[:]); C.callGoStackCheck() } +func stack2316() { var buf [2316]byte; use(buf[:]); C.callGoStackCheck() } +func stack2320() { var buf [2320]byte; use(buf[:]); C.callGoStackCheck() } +func stack2324() { var buf [2324]byte; use(buf[:]); C.callGoStackCheck() } +func stack2328() { var buf [2328]byte; use(buf[:]); C.callGoStackCheck() } +func stack2332() { var buf [2332]byte; use(buf[:]); C.callGoStackCheck() } +func stack2336() { var buf [2336]byte; use(buf[:]); C.callGoStackCheck() } +func stack2340() { var buf [2340]byte; use(buf[:]); C.callGoStackCheck() } +func stack2344() { var buf [2344]byte; use(buf[:]); C.callGoStackCheck() } +func stack2348() { var buf [2348]byte; use(buf[:]); C.callGoStackCheck() } +func stack2352() { var buf [2352]byte; use(buf[:]); C.callGoStackCheck() } +func stack2356() { var buf [2356]byte; use(buf[:]); C.callGoStackCheck() } +func stack2360() { var buf [2360]byte; use(buf[:]); C.callGoStackCheck() } +func stack2364() { var buf [2364]byte; use(buf[:]); C.callGoStackCheck() } +func stack2368() { var buf [2368]byte; use(buf[:]); C.callGoStackCheck() } +func stack2372() { var buf [2372]byte; use(buf[:]); C.callGoStackCheck() } +func stack2376() { var buf [2376]byte; use(buf[:]); C.callGoStackCheck() } +func stack2380() { var buf [2380]byte; use(buf[:]); C.callGoStackCheck() } +func stack2384() { var buf [2384]byte; use(buf[:]); C.callGoStackCheck() } +func stack2388() { var buf [2388]byte; use(buf[:]); C.callGoStackCheck() } +func stack2392() { var buf [2392]byte; use(buf[:]); C.callGoStackCheck() } +func stack2396() { var buf [2396]byte; use(buf[:]); C.callGoStackCheck() } +func stack2400() { var buf [2400]byte; use(buf[:]); C.callGoStackCheck() } +func stack2404() { var buf [2404]byte; use(buf[:]); C.callGoStackCheck() } +func stack2408() { var buf [2408]byte; use(buf[:]); C.callGoStackCheck() } +func stack2412() { var buf [2412]byte; use(buf[:]); C.callGoStackCheck() } +func stack2416() { var buf [2416]byte; use(buf[:]); C.callGoStackCheck() } +func stack2420() { var buf [2420]byte; use(buf[:]); C.callGoStackCheck() } +func stack2424() { var buf [2424]byte; use(buf[:]); C.callGoStackCheck() } +func stack2428() { var buf [2428]byte; use(buf[:]); C.callGoStackCheck() } +func stack2432() { var buf [2432]byte; use(buf[:]); C.callGoStackCheck() } +func stack2436() { var buf [2436]byte; use(buf[:]); C.callGoStackCheck() } +func stack2440() { var buf [2440]byte; use(buf[:]); C.callGoStackCheck() } +func stack2444() { var buf [2444]byte; use(buf[:]); C.callGoStackCheck() } +func stack2448() { var buf [2448]byte; use(buf[:]); C.callGoStackCheck() } +func stack2452() { var buf [2452]byte; use(buf[:]); C.callGoStackCheck() } +func stack2456() { var buf [2456]byte; use(buf[:]); C.callGoStackCheck() } +func stack2460() { var buf [2460]byte; use(buf[:]); C.callGoStackCheck() } +func stack2464() { var buf [2464]byte; use(buf[:]); C.callGoStackCheck() } +func stack2468() { var buf [2468]byte; use(buf[:]); C.callGoStackCheck() } +func stack2472() { var buf [2472]byte; use(buf[:]); C.callGoStackCheck() } +func stack2476() { var buf [2476]byte; use(buf[:]); C.callGoStackCheck() } +func stack2480() { var buf [2480]byte; use(buf[:]); C.callGoStackCheck() } +func stack2484() { var buf [2484]byte; use(buf[:]); C.callGoStackCheck() } +func stack2488() { var buf [2488]byte; use(buf[:]); C.callGoStackCheck() } +func stack2492() { var buf [2492]byte; use(buf[:]); C.callGoStackCheck() } +func stack2496() { var buf [2496]byte; use(buf[:]); C.callGoStackCheck() } +func stack2500() { var buf [2500]byte; use(buf[:]); C.callGoStackCheck() } +func stack2504() { var buf [2504]byte; use(buf[:]); C.callGoStackCheck() } +func stack2508() { var buf [2508]byte; use(buf[:]); C.callGoStackCheck() } +func stack2512() { var buf [2512]byte; use(buf[:]); C.callGoStackCheck() } +func stack2516() { var buf [2516]byte; use(buf[:]); C.callGoStackCheck() } +func stack2520() { var buf [2520]byte; use(buf[:]); C.callGoStackCheck() } +func stack2524() { var buf [2524]byte; use(buf[:]); C.callGoStackCheck() } +func stack2528() { var buf [2528]byte; use(buf[:]); C.callGoStackCheck() } +func stack2532() { var buf [2532]byte; use(buf[:]); C.callGoStackCheck() } +func stack2536() { var buf [2536]byte; use(buf[:]); C.callGoStackCheck() } +func stack2540() { var buf [2540]byte; use(buf[:]); C.callGoStackCheck() } +func stack2544() { var buf [2544]byte; use(buf[:]); C.callGoStackCheck() } +func stack2548() { var buf [2548]byte; use(buf[:]); C.callGoStackCheck() } +func stack2552() { var buf [2552]byte; use(buf[:]); C.callGoStackCheck() } +func stack2556() { var buf [2556]byte; use(buf[:]); C.callGoStackCheck() } +func stack2560() { var buf [2560]byte; use(buf[:]); C.callGoStackCheck() } +func stack2564() { var buf [2564]byte; use(buf[:]); C.callGoStackCheck() } +func stack2568() { var buf [2568]byte; use(buf[:]); C.callGoStackCheck() } +func stack2572() { var buf [2572]byte; use(buf[:]); C.callGoStackCheck() } +func stack2576() { var buf [2576]byte; use(buf[:]); C.callGoStackCheck() } +func stack2580() { var buf [2580]byte; use(buf[:]); C.callGoStackCheck() } +func stack2584() { var buf [2584]byte; use(buf[:]); C.callGoStackCheck() } +func stack2588() { var buf [2588]byte; use(buf[:]); C.callGoStackCheck() } +func stack2592() { var buf [2592]byte; use(buf[:]); C.callGoStackCheck() } +func stack2596() { var buf [2596]byte; use(buf[:]); C.callGoStackCheck() } +func stack2600() { var buf [2600]byte; use(buf[:]); C.callGoStackCheck() } +func stack2604() { var buf [2604]byte; use(buf[:]); C.callGoStackCheck() } +func stack2608() { var buf [2608]byte; use(buf[:]); C.callGoStackCheck() } +func stack2612() { var buf [2612]byte; use(buf[:]); C.callGoStackCheck() } +func stack2616() { var buf [2616]byte; use(buf[:]); C.callGoStackCheck() } +func stack2620() { var buf [2620]byte; use(buf[:]); C.callGoStackCheck() } +func stack2624() { var buf [2624]byte; use(buf[:]); C.callGoStackCheck() } +func stack2628() { var buf [2628]byte; use(buf[:]); C.callGoStackCheck() } +func stack2632() { var buf [2632]byte; use(buf[:]); C.callGoStackCheck() } +func stack2636() { var buf [2636]byte; use(buf[:]); C.callGoStackCheck() } +func stack2640() { var buf [2640]byte; use(buf[:]); C.callGoStackCheck() } +func stack2644() { var buf [2644]byte; use(buf[:]); C.callGoStackCheck() } +func stack2648() { var buf [2648]byte; use(buf[:]); C.callGoStackCheck() } +func stack2652() { var buf [2652]byte; use(buf[:]); C.callGoStackCheck() } +func stack2656() { var buf [2656]byte; use(buf[:]); C.callGoStackCheck() } +func stack2660() { var buf [2660]byte; use(buf[:]); C.callGoStackCheck() } +func stack2664() { var buf [2664]byte; use(buf[:]); C.callGoStackCheck() } +func stack2668() { var buf [2668]byte; use(buf[:]); C.callGoStackCheck() } +func stack2672() { var buf [2672]byte; use(buf[:]); C.callGoStackCheck() } +func stack2676() { var buf [2676]byte; use(buf[:]); C.callGoStackCheck() } +func stack2680() { var buf [2680]byte; use(buf[:]); C.callGoStackCheck() } +func stack2684() { var buf [2684]byte; use(buf[:]); C.callGoStackCheck() } +func stack2688() { var buf [2688]byte; use(buf[:]); C.callGoStackCheck() } +func stack2692() { var buf [2692]byte; use(buf[:]); C.callGoStackCheck() } +func stack2696() { var buf [2696]byte; use(buf[:]); C.callGoStackCheck() } +func stack2700() { var buf [2700]byte; use(buf[:]); C.callGoStackCheck() } +func stack2704() { var buf [2704]byte; use(buf[:]); C.callGoStackCheck() } +func stack2708() { var buf [2708]byte; use(buf[:]); C.callGoStackCheck() } +func stack2712() { var buf [2712]byte; use(buf[:]); C.callGoStackCheck() } +func stack2716() { var buf [2716]byte; use(buf[:]); C.callGoStackCheck() } +func stack2720() { var buf [2720]byte; use(buf[:]); C.callGoStackCheck() } +func stack2724() { var buf [2724]byte; use(buf[:]); C.callGoStackCheck() } +func stack2728() { var buf [2728]byte; use(buf[:]); C.callGoStackCheck() } +func stack2732() { var buf [2732]byte; use(buf[:]); C.callGoStackCheck() } +func stack2736() { var buf [2736]byte; use(buf[:]); C.callGoStackCheck() } +func stack2740() { var buf [2740]byte; use(buf[:]); C.callGoStackCheck() } +func stack2744() { var buf [2744]byte; use(buf[:]); C.callGoStackCheck() } +func stack2748() { var buf [2748]byte; use(buf[:]); C.callGoStackCheck() } +func stack2752() { var buf [2752]byte; use(buf[:]); C.callGoStackCheck() } +func stack2756() { var buf [2756]byte; use(buf[:]); C.callGoStackCheck() } +func stack2760() { var buf [2760]byte; use(buf[:]); C.callGoStackCheck() } +func stack2764() { var buf [2764]byte; use(buf[:]); C.callGoStackCheck() } +func stack2768() { var buf [2768]byte; use(buf[:]); C.callGoStackCheck() } +func stack2772() { var buf [2772]byte; use(buf[:]); C.callGoStackCheck() } +func stack2776() { var buf [2776]byte; use(buf[:]); C.callGoStackCheck() } +func stack2780() { var buf [2780]byte; use(buf[:]); C.callGoStackCheck() } +func stack2784() { var buf [2784]byte; use(buf[:]); C.callGoStackCheck() } +func stack2788() { var buf [2788]byte; use(buf[:]); C.callGoStackCheck() } +func stack2792() { var buf [2792]byte; use(buf[:]); C.callGoStackCheck() } +func stack2796() { var buf [2796]byte; use(buf[:]); C.callGoStackCheck() } +func stack2800() { var buf [2800]byte; use(buf[:]); C.callGoStackCheck() } +func stack2804() { var buf [2804]byte; use(buf[:]); C.callGoStackCheck() } +func stack2808() { var buf [2808]byte; use(buf[:]); C.callGoStackCheck() } +func stack2812() { var buf [2812]byte; use(buf[:]); C.callGoStackCheck() } +func stack2816() { var buf [2816]byte; use(buf[:]); C.callGoStackCheck() } +func stack2820() { var buf [2820]byte; use(buf[:]); C.callGoStackCheck() } +func stack2824() { var buf [2824]byte; use(buf[:]); C.callGoStackCheck() } +func stack2828() { var buf [2828]byte; use(buf[:]); C.callGoStackCheck() } +func stack2832() { var buf [2832]byte; use(buf[:]); C.callGoStackCheck() } +func stack2836() { var buf [2836]byte; use(buf[:]); C.callGoStackCheck() } +func stack2840() { var buf [2840]byte; use(buf[:]); C.callGoStackCheck() } +func stack2844() { var buf [2844]byte; use(buf[:]); C.callGoStackCheck() } +func stack2848() { var buf [2848]byte; use(buf[:]); C.callGoStackCheck() } +func stack2852() { var buf [2852]byte; use(buf[:]); C.callGoStackCheck() } +func stack2856() { var buf [2856]byte; use(buf[:]); C.callGoStackCheck() } +func stack2860() { var buf [2860]byte; use(buf[:]); C.callGoStackCheck() } +func stack2864() { var buf [2864]byte; use(buf[:]); C.callGoStackCheck() } +func stack2868() { var buf [2868]byte; use(buf[:]); C.callGoStackCheck() } +func stack2872() { var buf [2872]byte; use(buf[:]); C.callGoStackCheck() } +func stack2876() { var buf [2876]byte; use(buf[:]); C.callGoStackCheck() } +func stack2880() { var buf [2880]byte; use(buf[:]); C.callGoStackCheck() } +func stack2884() { var buf [2884]byte; use(buf[:]); C.callGoStackCheck() } +func stack2888() { var buf [2888]byte; use(buf[:]); C.callGoStackCheck() } +func stack2892() { var buf [2892]byte; use(buf[:]); C.callGoStackCheck() } +func stack2896() { var buf [2896]byte; use(buf[:]); C.callGoStackCheck() } +func stack2900() { var buf [2900]byte; use(buf[:]); C.callGoStackCheck() } +func stack2904() { var buf [2904]byte; use(buf[:]); C.callGoStackCheck() } +func stack2908() { var buf [2908]byte; use(buf[:]); C.callGoStackCheck() } +func stack2912() { var buf [2912]byte; use(buf[:]); C.callGoStackCheck() } +func stack2916() { var buf [2916]byte; use(buf[:]); C.callGoStackCheck() } +func stack2920() { var buf [2920]byte; use(buf[:]); C.callGoStackCheck() } +func stack2924() { var buf [2924]byte; use(buf[:]); C.callGoStackCheck() } +func stack2928() { var buf [2928]byte; use(buf[:]); C.callGoStackCheck() } +func stack2932() { var buf [2932]byte; use(buf[:]); C.callGoStackCheck() } +func stack2936() { var buf [2936]byte; use(buf[:]); C.callGoStackCheck() } +func stack2940() { var buf [2940]byte; use(buf[:]); C.callGoStackCheck() } +func stack2944() { var buf [2944]byte; use(buf[:]); C.callGoStackCheck() } +func stack2948() { var buf [2948]byte; use(buf[:]); C.callGoStackCheck() } +func stack2952() { var buf [2952]byte; use(buf[:]); C.callGoStackCheck() } +func stack2956() { var buf [2956]byte; use(buf[:]); C.callGoStackCheck() } +func stack2960() { var buf [2960]byte; use(buf[:]); C.callGoStackCheck() } +func stack2964() { var buf [2964]byte; use(buf[:]); C.callGoStackCheck() } +func stack2968() { var buf [2968]byte; use(buf[:]); C.callGoStackCheck() } +func stack2972() { var buf [2972]byte; use(buf[:]); C.callGoStackCheck() } +func stack2976() { var buf [2976]byte; use(buf[:]); C.callGoStackCheck() } +func stack2980() { var buf [2980]byte; use(buf[:]); C.callGoStackCheck() } +func stack2984() { var buf [2984]byte; use(buf[:]); C.callGoStackCheck() } +func stack2988() { var buf [2988]byte; use(buf[:]); C.callGoStackCheck() } +func stack2992() { var buf [2992]byte; use(buf[:]); C.callGoStackCheck() } +func stack2996() { var buf [2996]byte; use(buf[:]); C.callGoStackCheck() } +func stack3000() { var buf [3000]byte; use(buf[:]); C.callGoStackCheck() } +func stack3004() { var buf [3004]byte; use(buf[:]); C.callGoStackCheck() } +func stack3008() { var buf [3008]byte; use(buf[:]); C.callGoStackCheck() } +func stack3012() { var buf [3012]byte; use(buf[:]); C.callGoStackCheck() } +func stack3016() { var buf [3016]byte; use(buf[:]); C.callGoStackCheck() } +func stack3020() { var buf [3020]byte; use(buf[:]); C.callGoStackCheck() } +func stack3024() { var buf [3024]byte; use(buf[:]); C.callGoStackCheck() } +func stack3028() { var buf [3028]byte; use(buf[:]); C.callGoStackCheck() } +func stack3032() { var buf [3032]byte; use(buf[:]); C.callGoStackCheck() } +func stack3036() { var buf [3036]byte; use(buf[:]); C.callGoStackCheck() } +func stack3040() { var buf [3040]byte; use(buf[:]); C.callGoStackCheck() } +func stack3044() { var buf [3044]byte; use(buf[:]); C.callGoStackCheck() } +func stack3048() { var buf [3048]byte; use(buf[:]); C.callGoStackCheck() } +func stack3052() { var buf [3052]byte; use(buf[:]); C.callGoStackCheck() } +func stack3056() { var buf [3056]byte; use(buf[:]); C.callGoStackCheck() } +func stack3060() { var buf [3060]byte; use(buf[:]); C.callGoStackCheck() } +func stack3064() { var buf [3064]byte; use(buf[:]); C.callGoStackCheck() } +func stack3068() { var buf [3068]byte; use(buf[:]); C.callGoStackCheck() } +func stack3072() { var buf [3072]byte; use(buf[:]); C.callGoStackCheck() } +func stack3076() { var buf [3076]byte; use(buf[:]); C.callGoStackCheck() } +func stack3080() { var buf [3080]byte; use(buf[:]); C.callGoStackCheck() } +func stack3084() { var buf [3084]byte; use(buf[:]); C.callGoStackCheck() } +func stack3088() { var buf [3088]byte; use(buf[:]); C.callGoStackCheck() } +func stack3092() { var buf [3092]byte; use(buf[:]); C.callGoStackCheck() } +func stack3096() { var buf [3096]byte; use(buf[:]); C.callGoStackCheck() } +func stack3100() { var buf [3100]byte; use(buf[:]); C.callGoStackCheck() } +func stack3104() { var buf [3104]byte; use(buf[:]); C.callGoStackCheck() } +func stack3108() { var buf [3108]byte; use(buf[:]); C.callGoStackCheck() } +func stack3112() { var buf [3112]byte; use(buf[:]); C.callGoStackCheck() } +func stack3116() { var buf [3116]byte; use(buf[:]); C.callGoStackCheck() } +func stack3120() { var buf [3120]byte; use(buf[:]); C.callGoStackCheck() } +func stack3124() { var buf [3124]byte; use(buf[:]); C.callGoStackCheck() } +func stack3128() { var buf [3128]byte; use(buf[:]); C.callGoStackCheck() } +func stack3132() { var buf [3132]byte; use(buf[:]); C.callGoStackCheck() } +func stack3136() { var buf [3136]byte; use(buf[:]); C.callGoStackCheck() } +func stack3140() { var buf [3140]byte; use(buf[:]); C.callGoStackCheck() } +func stack3144() { var buf [3144]byte; use(buf[:]); C.callGoStackCheck() } +func stack3148() { var buf [3148]byte; use(buf[:]); C.callGoStackCheck() } +func stack3152() { var buf [3152]byte; use(buf[:]); C.callGoStackCheck() } +func stack3156() { var buf [3156]byte; use(buf[:]); C.callGoStackCheck() } +func stack3160() { var buf [3160]byte; use(buf[:]); C.callGoStackCheck() } +func stack3164() { var buf [3164]byte; use(buf[:]); C.callGoStackCheck() } +func stack3168() { var buf [3168]byte; use(buf[:]); C.callGoStackCheck() } +func stack3172() { var buf [3172]byte; use(buf[:]); C.callGoStackCheck() } +func stack3176() { var buf [3176]byte; use(buf[:]); C.callGoStackCheck() } +func stack3180() { var buf [3180]byte; use(buf[:]); C.callGoStackCheck() } +func stack3184() { var buf [3184]byte; use(buf[:]); C.callGoStackCheck() } +func stack3188() { var buf [3188]byte; use(buf[:]); C.callGoStackCheck() } +func stack3192() { var buf [3192]byte; use(buf[:]); C.callGoStackCheck() } +func stack3196() { var buf [3196]byte; use(buf[:]); C.callGoStackCheck() } +func stack3200() { var buf [3200]byte; use(buf[:]); C.callGoStackCheck() } +func stack3204() { var buf [3204]byte; use(buf[:]); C.callGoStackCheck() } +func stack3208() { var buf [3208]byte; use(buf[:]); C.callGoStackCheck() } +func stack3212() { var buf [3212]byte; use(buf[:]); C.callGoStackCheck() } +func stack3216() { var buf [3216]byte; use(buf[:]); C.callGoStackCheck() } +func stack3220() { var buf [3220]byte; use(buf[:]); C.callGoStackCheck() } +func stack3224() { var buf [3224]byte; use(buf[:]); C.callGoStackCheck() } +func stack3228() { var buf [3228]byte; use(buf[:]); C.callGoStackCheck() } +func stack3232() { var buf [3232]byte; use(buf[:]); C.callGoStackCheck() } +func stack3236() { var buf [3236]byte; use(buf[:]); C.callGoStackCheck() } +func stack3240() { var buf [3240]byte; use(buf[:]); C.callGoStackCheck() } +func stack3244() { var buf [3244]byte; use(buf[:]); C.callGoStackCheck() } +func stack3248() { var buf [3248]byte; use(buf[:]); C.callGoStackCheck() } +func stack3252() { var buf [3252]byte; use(buf[:]); C.callGoStackCheck() } +func stack3256() { var buf [3256]byte; use(buf[:]); C.callGoStackCheck() } +func stack3260() { var buf [3260]byte; use(buf[:]); C.callGoStackCheck() } +func stack3264() { var buf [3264]byte; use(buf[:]); C.callGoStackCheck() } +func stack3268() { var buf [3268]byte; use(buf[:]); C.callGoStackCheck() } +func stack3272() { var buf [3272]byte; use(buf[:]); C.callGoStackCheck() } +func stack3276() { var buf [3276]byte; use(buf[:]); C.callGoStackCheck() } +func stack3280() { var buf [3280]byte; use(buf[:]); C.callGoStackCheck() } +func stack3284() { var buf [3284]byte; use(buf[:]); C.callGoStackCheck() } +func stack3288() { var buf [3288]byte; use(buf[:]); C.callGoStackCheck() } +func stack3292() { var buf [3292]byte; use(buf[:]); C.callGoStackCheck() } +func stack3296() { var buf [3296]byte; use(buf[:]); C.callGoStackCheck() } +func stack3300() { var buf [3300]byte; use(buf[:]); C.callGoStackCheck() } +func stack3304() { var buf [3304]byte; use(buf[:]); C.callGoStackCheck() } +func stack3308() { var buf [3308]byte; use(buf[:]); C.callGoStackCheck() } +func stack3312() { var buf [3312]byte; use(buf[:]); C.callGoStackCheck() } +func stack3316() { var buf [3316]byte; use(buf[:]); C.callGoStackCheck() } +func stack3320() { var buf [3320]byte; use(buf[:]); C.callGoStackCheck() } +func stack3324() { var buf [3324]byte; use(buf[:]); C.callGoStackCheck() } +func stack3328() { var buf [3328]byte; use(buf[:]); C.callGoStackCheck() } +func stack3332() { var buf [3332]byte; use(buf[:]); C.callGoStackCheck() } +func stack3336() { var buf [3336]byte; use(buf[:]); C.callGoStackCheck() } +func stack3340() { var buf [3340]byte; use(buf[:]); C.callGoStackCheck() } +func stack3344() { var buf [3344]byte; use(buf[:]); C.callGoStackCheck() } +func stack3348() { var buf [3348]byte; use(buf[:]); C.callGoStackCheck() } +func stack3352() { var buf [3352]byte; use(buf[:]); C.callGoStackCheck() } +func stack3356() { var buf [3356]byte; use(buf[:]); C.callGoStackCheck() } +func stack3360() { var buf [3360]byte; use(buf[:]); C.callGoStackCheck() } +func stack3364() { var buf [3364]byte; use(buf[:]); C.callGoStackCheck() } +func stack3368() { var buf [3368]byte; use(buf[:]); C.callGoStackCheck() } +func stack3372() { var buf [3372]byte; use(buf[:]); C.callGoStackCheck() } +func stack3376() { var buf [3376]byte; use(buf[:]); C.callGoStackCheck() } +func stack3380() { var buf [3380]byte; use(buf[:]); C.callGoStackCheck() } +func stack3384() { var buf [3384]byte; use(buf[:]); C.callGoStackCheck() } +func stack3388() { var buf [3388]byte; use(buf[:]); C.callGoStackCheck() } +func stack3392() { var buf [3392]byte; use(buf[:]); C.callGoStackCheck() } +func stack3396() { var buf [3396]byte; use(buf[:]); C.callGoStackCheck() } +func stack3400() { var buf [3400]byte; use(buf[:]); C.callGoStackCheck() } +func stack3404() { var buf [3404]byte; use(buf[:]); C.callGoStackCheck() } +func stack3408() { var buf [3408]byte; use(buf[:]); C.callGoStackCheck() } +func stack3412() { var buf [3412]byte; use(buf[:]); C.callGoStackCheck() } +func stack3416() { var buf [3416]byte; use(buf[:]); C.callGoStackCheck() } +func stack3420() { var buf [3420]byte; use(buf[:]); C.callGoStackCheck() } +func stack3424() { var buf [3424]byte; use(buf[:]); C.callGoStackCheck() } +func stack3428() { var buf [3428]byte; use(buf[:]); C.callGoStackCheck() } +func stack3432() { var buf [3432]byte; use(buf[:]); C.callGoStackCheck() } +func stack3436() { var buf [3436]byte; use(buf[:]); C.callGoStackCheck() } +func stack3440() { var buf [3440]byte; use(buf[:]); C.callGoStackCheck() } +func stack3444() { var buf [3444]byte; use(buf[:]); C.callGoStackCheck() } +func stack3448() { var buf [3448]byte; use(buf[:]); C.callGoStackCheck() } +func stack3452() { var buf [3452]byte; use(buf[:]); C.callGoStackCheck() } +func stack3456() { var buf [3456]byte; use(buf[:]); C.callGoStackCheck() } +func stack3460() { var buf [3460]byte; use(buf[:]); C.callGoStackCheck() } +func stack3464() { var buf [3464]byte; use(buf[:]); C.callGoStackCheck() } +func stack3468() { var buf [3468]byte; use(buf[:]); C.callGoStackCheck() } +func stack3472() { var buf [3472]byte; use(buf[:]); C.callGoStackCheck() } +func stack3476() { var buf [3476]byte; use(buf[:]); C.callGoStackCheck() } +func stack3480() { var buf [3480]byte; use(buf[:]); C.callGoStackCheck() } +func stack3484() { var buf [3484]byte; use(buf[:]); C.callGoStackCheck() } +func stack3488() { var buf [3488]byte; use(buf[:]); C.callGoStackCheck() } +func stack3492() { var buf [3492]byte; use(buf[:]); C.callGoStackCheck() } +func stack3496() { var buf [3496]byte; use(buf[:]); C.callGoStackCheck() } +func stack3500() { var buf [3500]byte; use(buf[:]); C.callGoStackCheck() } +func stack3504() { var buf [3504]byte; use(buf[:]); C.callGoStackCheck() } +func stack3508() { var buf [3508]byte; use(buf[:]); C.callGoStackCheck() } +func stack3512() { var buf [3512]byte; use(buf[:]); C.callGoStackCheck() } +func stack3516() { var buf [3516]byte; use(buf[:]); C.callGoStackCheck() } +func stack3520() { var buf [3520]byte; use(buf[:]); C.callGoStackCheck() } +func stack3524() { var buf [3524]byte; use(buf[:]); C.callGoStackCheck() } +func stack3528() { var buf [3528]byte; use(buf[:]); C.callGoStackCheck() } +func stack3532() { var buf [3532]byte; use(buf[:]); C.callGoStackCheck() } +func stack3536() { var buf [3536]byte; use(buf[:]); C.callGoStackCheck() } +func stack3540() { var buf [3540]byte; use(buf[:]); C.callGoStackCheck() } +func stack3544() { var buf [3544]byte; use(buf[:]); C.callGoStackCheck() } +func stack3548() { var buf [3548]byte; use(buf[:]); C.callGoStackCheck() } +func stack3552() { var buf [3552]byte; use(buf[:]); C.callGoStackCheck() } +func stack3556() { var buf [3556]byte; use(buf[:]); C.callGoStackCheck() } +func stack3560() { var buf [3560]byte; use(buf[:]); C.callGoStackCheck() } +func stack3564() { var buf [3564]byte; use(buf[:]); C.callGoStackCheck() } +func stack3568() { var buf [3568]byte; use(buf[:]); C.callGoStackCheck() } +func stack3572() { var buf [3572]byte; use(buf[:]); C.callGoStackCheck() } +func stack3576() { var buf [3576]byte; use(buf[:]); C.callGoStackCheck() } +func stack3580() { var buf [3580]byte; use(buf[:]); C.callGoStackCheck() } +func stack3584() { var buf [3584]byte; use(buf[:]); C.callGoStackCheck() } +func stack3588() { var buf [3588]byte; use(buf[:]); C.callGoStackCheck() } +func stack3592() { var buf [3592]byte; use(buf[:]); C.callGoStackCheck() } +func stack3596() { var buf [3596]byte; use(buf[:]); C.callGoStackCheck() } +func stack3600() { var buf [3600]byte; use(buf[:]); C.callGoStackCheck() } +func stack3604() { var buf [3604]byte; use(buf[:]); C.callGoStackCheck() } +func stack3608() { var buf [3608]byte; use(buf[:]); C.callGoStackCheck() } +func stack3612() { var buf [3612]byte; use(buf[:]); C.callGoStackCheck() } +func stack3616() { var buf [3616]byte; use(buf[:]); C.callGoStackCheck() } +func stack3620() { var buf [3620]byte; use(buf[:]); C.callGoStackCheck() } +func stack3624() { var buf [3624]byte; use(buf[:]); C.callGoStackCheck() } +func stack3628() { var buf [3628]byte; use(buf[:]); C.callGoStackCheck() } +func stack3632() { var buf [3632]byte; use(buf[:]); C.callGoStackCheck() } +func stack3636() { var buf [3636]byte; use(buf[:]); C.callGoStackCheck() } +func stack3640() { var buf [3640]byte; use(buf[:]); C.callGoStackCheck() } +func stack3644() { var buf [3644]byte; use(buf[:]); C.callGoStackCheck() } +func stack3648() { var buf [3648]byte; use(buf[:]); C.callGoStackCheck() } +func stack3652() { var buf [3652]byte; use(buf[:]); C.callGoStackCheck() } +func stack3656() { var buf [3656]byte; use(buf[:]); C.callGoStackCheck() } +func stack3660() { var buf [3660]byte; use(buf[:]); C.callGoStackCheck() } +func stack3664() { var buf [3664]byte; use(buf[:]); C.callGoStackCheck() } +func stack3668() { var buf [3668]byte; use(buf[:]); C.callGoStackCheck() } +func stack3672() { var buf [3672]byte; use(buf[:]); C.callGoStackCheck() } +func stack3676() { var buf [3676]byte; use(buf[:]); C.callGoStackCheck() } +func stack3680() { var buf [3680]byte; use(buf[:]); C.callGoStackCheck() } +func stack3684() { var buf [3684]byte; use(buf[:]); C.callGoStackCheck() } +func stack3688() { var buf [3688]byte; use(buf[:]); C.callGoStackCheck() } +func stack3692() { var buf [3692]byte; use(buf[:]); C.callGoStackCheck() } +func stack3696() { var buf [3696]byte; use(buf[:]); C.callGoStackCheck() } +func stack3700() { var buf [3700]byte; use(buf[:]); C.callGoStackCheck() } +func stack3704() { var buf [3704]byte; use(buf[:]); C.callGoStackCheck() } +func stack3708() { var buf [3708]byte; use(buf[:]); C.callGoStackCheck() } +func stack3712() { var buf [3712]byte; use(buf[:]); C.callGoStackCheck() } +func stack3716() { var buf [3716]byte; use(buf[:]); C.callGoStackCheck() } +func stack3720() { var buf [3720]byte; use(buf[:]); C.callGoStackCheck() } +func stack3724() { var buf [3724]byte; use(buf[:]); C.callGoStackCheck() } +func stack3728() { var buf [3728]byte; use(buf[:]); C.callGoStackCheck() } +func stack3732() { var buf [3732]byte; use(buf[:]); C.callGoStackCheck() } +func stack3736() { var buf [3736]byte; use(buf[:]); C.callGoStackCheck() } +func stack3740() { var buf [3740]byte; use(buf[:]); C.callGoStackCheck() } +func stack3744() { var buf [3744]byte; use(buf[:]); C.callGoStackCheck() } +func stack3748() { var buf [3748]byte; use(buf[:]); C.callGoStackCheck() } +func stack3752() { var buf [3752]byte; use(buf[:]); C.callGoStackCheck() } +func stack3756() { var buf [3756]byte; use(buf[:]); C.callGoStackCheck() } +func stack3760() { var buf [3760]byte; use(buf[:]); C.callGoStackCheck() } +func stack3764() { var buf [3764]byte; use(buf[:]); C.callGoStackCheck() } +func stack3768() { var buf [3768]byte; use(buf[:]); C.callGoStackCheck() } +func stack3772() { var buf [3772]byte; use(buf[:]); C.callGoStackCheck() } +func stack3776() { var buf [3776]byte; use(buf[:]); C.callGoStackCheck() } +func stack3780() { var buf [3780]byte; use(buf[:]); C.callGoStackCheck() } +func stack3784() { var buf [3784]byte; use(buf[:]); C.callGoStackCheck() } +func stack3788() { var buf [3788]byte; use(buf[:]); C.callGoStackCheck() } +func stack3792() { var buf [3792]byte; use(buf[:]); C.callGoStackCheck() } +func stack3796() { var buf [3796]byte; use(buf[:]); C.callGoStackCheck() } +func stack3800() { var buf [3800]byte; use(buf[:]); C.callGoStackCheck() } +func stack3804() { var buf [3804]byte; use(buf[:]); C.callGoStackCheck() } +func stack3808() { var buf [3808]byte; use(buf[:]); C.callGoStackCheck() } +func stack3812() { var buf [3812]byte; use(buf[:]); C.callGoStackCheck() } +func stack3816() { var buf [3816]byte; use(buf[:]); C.callGoStackCheck() } +func stack3820() { var buf [3820]byte; use(buf[:]); C.callGoStackCheck() } +func stack3824() { var buf [3824]byte; use(buf[:]); C.callGoStackCheck() } +func stack3828() { var buf [3828]byte; use(buf[:]); C.callGoStackCheck() } +func stack3832() { var buf [3832]byte; use(buf[:]); C.callGoStackCheck() } +func stack3836() { var buf [3836]byte; use(buf[:]); C.callGoStackCheck() } +func stack3840() { var buf [3840]byte; use(buf[:]); C.callGoStackCheck() } +func stack3844() { var buf [3844]byte; use(buf[:]); C.callGoStackCheck() } +func stack3848() { var buf [3848]byte; use(buf[:]); C.callGoStackCheck() } +func stack3852() { var buf [3852]byte; use(buf[:]); C.callGoStackCheck() } +func stack3856() { var buf [3856]byte; use(buf[:]); C.callGoStackCheck() } +func stack3860() { var buf [3860]byte; use(buf[:]); C.callGoStackCheck() } +func stack3864() { var buf [3864]byte; use(buf[:]); C.callGoStackCheck() } +func stack3868() { var buf [3868]byte; use(buf[:]); C.callGoStackCheck() } +func stack3872() { var buf [3872]byte; use(buf[:]); C.callGoStackCheck() } +func stack3876() { var buf [3876]byte; use(buf[:]); C.callGoStackCheck() } +func stack3880() { var buf [3880]byte; use(buf[:]); C.callGoStackCheck() } +func stack3884() { var buf [3884]byte; use(buf[:]); C.callGoStackCheck() } +func stack3888() { var buf [3888]byte; use(buf[:]); C.callGoStackCheck() } +func stack3892() { var buf [3892]byte; use(buf[:]); C.callGoStackCheck() } +func stack3896() { var buf [3896]byte; use(buf[:]); C.callGoStackCheck() } +func stack3900() { var buf [3900]byte; use(buf[:]); C.callGoStackCheck() } +func stack3904() { var buf [3904]byte; use(buf[:]); C.callGoStackCheck() } +func stack3908() { var buf [3908]byte; use(buf[:]); C.callGoStackCheck() } +func stack3912() { var buf [3912]byte; use(buf[:]); C.callGoStackCheck() } +func stack3916() { var buf [3916]byte; use(buf[:]); C.callGoStackCheck() } +func stack3920() { var buf [3920]byte; use(buf[:]); C.callGoStackCheck() } +func stack3924() { var buf [3924]byte; use(buf[:]); C.callGoStackCheck() } +func stack3928() { var buf [3928]byte; use(buf[:]); C.callGoStackCheck() } +func stack3932() { var buf [3932]byte; use(buf[:]); C.callGoStackCheck() } +func stack3936() { var buf [3936]byte; use(buf[:]); C.callGoStackCheck() } +func stack3940() { var buf [3940]byte; use(buf[:]); C.callGoStackCheck() } +func stack3944() { var buf [3944]byte; use(buf[:]); C.callGoStackCheck() } +func stack3948() { var buf [3948]byte; use(buf[:]); C.callGoStackCheck() } +func stack3952() { var buf [3952]byte; use(buf[:]); C.callGoStackCheck() } +func stack3956() { var buf [3956]byte; use(buf[:]); C.callGoStackCheck() } +func stack3960() { var buf [3960]byte; use(buf[:]); C.callGoStackCheck() } +func stack3964() { var buf [3964]byte; use(buf[:]); C.callGoStackCheck() } +func stack3968() { var buf [3968]byte; use(buf[:]); C.callGoStackCheck() } +func stack3972() { var buf [3972]byte; use(buf[:]); C.callGoStackCheck() } +func stack3976() { var buf [3976]byte; use(buf[:]); C.callGoStackCheck() } +func stack3980() { var buf [3980]byte; use(buf[:]); C.callGoStackCheck() } +func stack3984() { var buf [3984]byte; use(buf[:]); C.callGoStackCheck() } +func stack3988() { var buf [3988]byte; use(buf[:]); C.callGoStackCheck() } +func stack3992() { var buf [3992]byte; use(buf[:]); C.callGoStackCheck() } +func stack3996() { var buf [3996]byte; use(buf[:]); C.callGoStackCheck() } +func stack4000() { var buf [4000]byte; use(buf[:]); C.callGoStackCheck() } +func stack4004() { var buf [4004]byte; use(buf[:]); C.callGoStackCheck() } +func stack4008() { var buf [4008]byte; use(buf[:]); C.callGoStackCheck() } +func stack4012() { var buf [4012]byte; use(buf[:]); C.callGoStackCheck() } +func stack4016() { var buf [4016]byte; use(buf[:]); C.callGoStackCheck() } +func stack4020() { var buf [4020]byte; use(buf[:]); C.callGoStackCheck() } +func stack4024() { var buf [4024]byte; use(buf[:]); C.callGoStackCheck() } +func stack4028() { var buf [4028]byte; use(buf[:]); C.callGoStackCheck() } +func stack4032() { var buf [4032]byte; use(buf[:]); C.callGoStackCheck() } +func stack4036() { var buf [4036]byte; use(buf[:]); C.callGoStackCheck() } +func stack4040() { var buf [4040]byte; use(buf[:]); C.callGoStackCheck() } +func stack4044() { var buf [4044]byte; use(buf[:]); C.callGoStackCheck() } +func stack4048() { var buf [4048]byte; use(buf[:]); C.callGoStackCheck() } +func stack4052() { var buf [4052]byte; use(buf[:]); C.callGoStackCheck() } +func stack4056() { var buf [4056]byte; use(buf[:]); C.callGoStackCheck() } +func stack4060() { var buf [4060]byte; use(buf[:]); C.callGoStackCheck() } +func stack4064() { var buf [4064]byte; use(buf[:]); C.callGoStackCheck() } +func stack4068() { var buf [4068]byte; use(buf[:]); C.callGoStackCheck() } +func stack4072() { var buf [4072]byte; use(buf[:]); C.callGoStackCheck() } +func stack4076() { var buf [4076]byte; use(buf[:]); C.callGoStackCheck() } +func stack4080() { var buf [4080]byte; use(buf[:]); C.callGoStackCheck() } +func stack4084() { var buf [4084]byte; use(buf[:]); C.callGoStackCheck() } +func stack4088() { var buf [4088]byte; use(buf[:]); C.callGoStackCheck() } +func stack4092() { var buf [4092]byte; use(buf[:]); C.callGoStackCheck() } +func stack4096() { var buf [4096]byte; use(buf[:]); C.callGoStackCheck() } +func stack4100() { var buf [4100]byte; use(buf[:]); C.callGoStackCheck() } +func stack4104() { var buf [4104]byte; use(buf[:]); C.callGoStackCheck() } +func stack4108() { var buf [4108]byte; use(buf[:]); C.callGoStackCheck() } +func stack4112() { var buf [4112]byte; use(buf[:]); C.callGoStackCheck() } +func stack4116() { var buf [4116]byte; use(buf[:]); C.callGoStackCheck() } +func stack4120() { var buf [4120]byte; use(buf[:]); C.callGoStackCheck() } +func stack4124() { var buf [4124]byte; use(buf[:]); C.callGoStackCheck() } +func stack4128() { var buf [4128]byte; use(buf[:]); C.callGoStackCheck() } +func stack4132() { var buf [4132]byte; use(buf[:]); C.callGoStackCheck() } +func stack4136() { var buf [4136]byte; use(buf[:]); C.callGoStackCheck() } +func stack4140() { var buf [4140]byte; use(buf[:]); C.callGoStackCheck() } +func stack4144() { var buf [4144]byte; use(buf[:]); C.callGoStackCheck() } +func stack4148() { var buf [4148]byte; use(buf[:]); C.callGoStackCheck() } +func stack4152() { var buf [4152]byte; use(buf[:]); C.callGoStackCheck() } +func stack4156() { var buf [4156]byte; use(buf[:]); C.callGoStackCheck() } +func stack4160() { var buf [4160]byte; use(buf[:]); C.callGoStackCheck() } +func stack4164() { var buf [4164]byte; use(buf[:]); C.callGoStackCheck() } +func stack4168() { var buf [4168]byte; use(buf[:]); C.callGoStackCheck() } +func stack4172() { var buf [4172]byte; use(buf[:]); C.callGoStackCheck() } +func stack4176() { var buf [4176]byte; use(buf[:]); C.callGoStackCheck() } +func stack4180() { var buf [4180]byte; use(buf[:]); C.callGoStackCheck() } +func stack4184() { var buf [4184]byte; use(buf[:]); C.callGoStackCheck() } +func stack4188() { var buf [4188]byte; use(buf[:]); C.callGoStackCheck() } +func stack4192() { var buf [4192]byte; use(buf[:]); C.callGoStackCheck() } +func stack4196() { var buf [4196]byte; use(buf[:]); C.callGoStackCheck() } +func stack4200() { var buf [4200]byte; use(buf[:]); C.callGoStackCheck() } +func stack4204() { var buf [4204]byte; use(buf[:]); C.callGoStackCheck() } +func stack4208() { var buf [4208]byte; use(buf[:]); C.callGoStackCheck() } +func stack4212() { var buf [4212]byte; use(buf[:]); C.callGoStackCheck() } +func stack4216() { var buf [4216]byte; use(buf[:]); C.callGoStackCheck() } +func stack4220() { var buf [4220]byte; use(buf[:]); C.callGoStackCheck() } +func stack4224() { var buf [4224]byte; use(buf[:]); C.callGoStackCheck() } +func stack4228() { var buf [4228]byte; use(buf[:]); C.callGoStackCheck() } +func stack4232() { var buf [4232]byte; use(buf[:]); C.callGoStackCheck() } +func stack4236() { var buf [4236]byte; use(buf[:]); C.callGoStackCheck() } +func stack4240() { var buf [4240]byte; use(buf[:]); C.callGoStackCheck() } +func stack4244() { var buf [4244]byte; use(buf[:]); C.callGoStackCheck() } +func stack4248() { var buf [4248]byte; use(buf[:]); C.callGoStackCheck() } +func stack4252() { var buf [4252]byte; use(buf[:]); C.callGoStackCheck() } +func stack4256() { var buf [4256]byte; use(buf[:]); C.callGoStackCheck() } +func stack4260() { var buf [4260]byte; use(buf[:]); C.callGoStackCheck() } +func stack4264() { var buf [4264]byte; use(buf[:]); C.callGoStackCheck() } +func stack4268() { var buf [4268]byte; use(buf[:]); C.callGoStackCheck() } +func stack4272() { var buf [4272]byte; use(buf[:]); C.callGoStackCheck() } +func stack4276() { var buf [4276]byte; use(buf[:]); C.callGoStackCheck() } +func stack4280() { var buf [4280]byte; use(buf[:]); C.callGoStackCheck() } +func stack4284() { var buf [4284]byte; use(buf[:]); C.callGoStackCheck() } +func stack4288() { var buf [4288]byte; use(buf[:]); C.callGoStackCheck() } +func stack4292() { var buf [4292]byte; use(buf[:]); C.callGoStackCheck() } +func stack4296() { var buf [4296]byte; use(buf[:]); C.callGoStackCheck() } +func stack4300() { var buf [4300]byte; use(buf[:]); C.callGoStackCheck() } +func stack4304() { var buf [4304]byte; use(buf[:]); C.callGoStackCheck() } +func stack4308() { var buf [4308]byte; use(buf[:]); C.callGoStackCheck() } +func stack4312() { var buf [4312]byte; use(buf[:]); C.callGoStackCheck() } +func stack4316() { var buf [4316]byte; use(buf[:]); C.callGoStackCheck() } +func stack4320() { var buf [4320]byte; use(buf[:]); C.callGoStackCheck() } +func stack4324() { var buf [4324]byte; use(buf[:]); C.callGoStackCheck() } +func stack4328() { var buf [4328]byte; use(buf[:]); C.callGoStackCheck() } +func stack4332() { var buf [4332]byte; use(buf[:]); C.callGoStackCheck() } +func stack4336() { var buf [4336]byte; use(buf[:]); C.callGoStackCheck() } +func stack4340() { var buf [4340]byte; use(buf[:]); C.callGoStackCheck() } +func stack4344() { var buf [4344]byte; use(buf[:]); C.callGoStackCheck() } +func stack4348() { var buf [4348]byte; use(buf[:]); C.callGoStackCheck() } +func stack4352() { var buf [4352]byte; use(buf[:]); C.callGoStackCheck() } +func stack4356() { var buf [4356]byte; use(buf[:]); C.callGoStackCheck() } +func stack4360() { var buf [4360]byte; use(buf[:]); C.callGoStackCheck() } +func stack4364() { var buf [4364]byte; use(buf[:]); C.callGoStackCheck() } +func stack4368() { var buf [4368]byte; use(buf[:]); C.callGoStackCheck() } +func stack4372() { var buf [4372]byte; use(buf[:]); C.callGoStackCheck() } +func stack4376() { var buf [4376]byte; use(buf[:]); C.callGoStackCheck() } +func stack4380() { var buf [4380]byte; use(buf[:]); C.callGoStackCheck() } +func stack4384() { var buf [4384]byte; use(buf[:]); C.callGoStackCheck() } +func stack4388() { var buf [4388]byte; use(buf[:]); C.callGoStackCheck() } +func stack4392() { var buf [4392]byte; use(buf[:]); C.callGoStackCheck() } +func stack4396() { var buf [4396]byte; use(buf[:]); C.callGoStackCheck() } +func stack4400() { var buf [4400]byte; use(buf[:]); C.callGoStackCheck() } +func stack4404() { var buf [4404]byte; use(buf[:]); C.callGoStackCheck() } +func stack4408() { var buf [4408]byte; use(buf[:]); C.callGoStackCheck() } +func stack4412() { var buf [4412]byte; use(buf[:]); C.callGoStackCheck() } +func stack4416() { var buf [4416]byte; use(buf[:]); C.callGoStackCheck() } +func stack4420() { var buf [4420]byte; use(buf[:]); C.callGoStackCheck() } +func stack4424() { var buf [4424]byte; use(buf[:]); C.callGoStackCheck() } +func stack4428() { var buf [4428]byte; use(buf[:]); C.callGoStackCheck() } +func stack4432() { var buf [4432]byte; use(buf[:]); C.callGoStackCheck() } +func stack4436() { var buf [4436]byte; use(buf[:]); C.callGoStackCheck() } +func stack4440() { var buf [4440]byte; use(buf[:]); C.callGoStackCheck() } +func stack4444() { var buf [4444]byte; use(buf[:]); C.callGoStackCheck() } +func stack4448() { var buf [4448]byte; use(buf[:]); C.callGoStackCheck() } +func stack4452() { var buf [4452]byte; use(buf[:]); C.callGoStackCheck() } +func stack4456() { var buf [4456]byte; use(buf[:]); C.callGoStackCheck() } +func stack4460() { var buf [4460]byte; use(buf[:]); C.callGoStackCheck() } +func stack4464() { var buf [4464]byte; use(buf[:]); C.callGoStackCheck() } +func stack4468() { var buf [4468]byte; use(buf[:]); C.callGoStackCheck() } +func stack4472() { var buf [4472]byte; use(buf[:]); C.callGoStackCheck() } +func stack4476() { var buf [4476]byte; use(buf[:]); C.callGoStackCheck() } +func stack4480() { var buf [4480]byte; use(buf[:]); C.callGoStackCheck() } +func stack4484() { var buf [4484]byte; use(buf[:]); C.callGoStackCheck() } +func stack4488() { var buf [4488]byte; use(buf[:]); C.callGoStackCheck() } +func stack4492() { var buf [4492]byte; use(buf[:]); C.callGoStackCheck() } +func stack4496() { var buf [4496]byte; use(buf[:]); C.callGoStackCheck() } +func stack4500() { var buf [4500]byte; use(buf[:]); C.callGoStackCheck() } +func stack4504() { var buf [4504]byte; use(buf[:]); C.callGoStackCheck() } +func stack4508() { var buf [4508]byte; use(buf[:]); C.callGoStackCheck() } +func stack4512() { var buf [4512]byte; use(buf[:]); C.callGoStackCheck() } +func stack4516() { var buf [4516]byte; use(buf[:]); C.callGoStackCheck() } +func stack4520() { var buf [4520]byte; use(buf[:]); C.callGoStackCheck() } +func stack4524() { var buf [4524]byte; use(buf[:]); C.callGoStackCheck() } +func stack4528() { var buf [4528]byte; use(buf[:]); C.callGoStackCheck() } +func stack4532() { var buf [4532]byte; use(buf[:]); C.callGoStackCheck() } +func stack4536() { var buf [4536]byte; use(buf[:]); C.callGoStackCheck() } +func stack4540() { var buf [4540]byte; use(buf[:]); C.callGoStackCheck() } +func stack4544() { var buf [4544]byte; use(buf[:]); C.callGoStackCheck() } +func stack4548() { var buf [4548]byte; use(buf[:]); C.callGoStackCheck() } +func stack4552() { var buf [4552]byte; use(buf[:]); C.callGoStackCheck() } +func stack4556() { var buf [4556]byte; use(buf[:]); C.callGoStackCheck() } +func stack4560() { var buf [4560]byte; use(buf[:]); C.callGoStackCheck() } +func stack4564() { var buf [4564]byte; use(buf[:]); C.callGoStackCheck() } +func stack4568() { var buf [4568]byte; use(buf[:]); C.callGoStackCheck() } +func stack4572() { var buf [4572]byte; use(buf[:]); C.callGoStackCheck() } +func stack4576() { var buf [4576]byte; use(buf[:]); C.callGoStackCheck() } +func stack4580() { var buf [4580]byte; use(buf[:]); C.callGoStackCheck() } +func stack4584() { var buf [4584]byte; use(buf[:]); C.callGoStackCheck() } +func stack4588() { var buf [4588]byte; use(buf[:]); C.callGoStackCheck() } +func stack4592() { var buf [4592]byte; use(buf[:]); C.callGoStackCheck() } +func stack4596() { var buf [4596]byte; use(buf[:]); C.callGoStackCheck() } +func stack4600() { var buf [4600]byte; use(buf[:]); C.callGoStackCheck() } +func stack4604() { var buf [4604]byte; use(buf[:]); C.callGoStackCheck() } +func stack4608() { var buf [4608]byte; use(buf[:]); C.callGoStackCheck() } +func stack4612() { var buf [4612]byte; use(buf[:]); C.callGoStackCheck() } +func stack4616() { var buf [4616]byte; use(buf[:]); C.callGoStackCheck() } +func stack4620() { var buf [4620]byte; use(buf[:]); C.callGoStackCheck() } +func stack4624() { var buf [4624]byte; use(buf[:]); C.callGoStackCheck() } +func stack4628() { var buf [4628]byte; use(buf[:]); C.callGoStackCheck() } +func stack4632() { var buf [4632]byte; use(buf[:]); C.callGoStackCheck() } +func stack4636() { var buf [4636]byte; use(buf[:]); C.callGoStackCheck() } +func stack4640() { var buf [4640]byte; use(buf[:]); C.callGoStackCheck() } +func stack4644() { var buf [4644]byte; use(buf[:]); C.callGoStackCheck() } +func stack4648() { var buf [4648]byte; use(buf[:]); C.callGoStackCheck() } +func stack4652() { var buf [4652]byte; use(buf[:]); C.callGoStackCheck() } +func stack4656() { var buf [4656]byte; use(buf[:]); C.callGoStackCheck() } +func stack4660() { var buf [4660]byte; use(buf[:]); C.callGoStackCheck() } +func stack4664() { var buf [4664]byte; use(buf[:]); C.callGoStackCheck() } +func stack4668() { var buf [4668]byte; use(buf[:]); C.callGoStackCheck() } +func stack4672() { var buf [4672]byte; use(buf[:]); C.callGoStackCheck() } +func stack4676() { var buf [4676]byte; use(buf[:]); C.callGoStackCheck() } +func stack4680() { var buf [4680]byte; use(buf[:]); C.callGoStackCheck() } +func stack4684() { var buf [4684]byte; use(buf[:]); C.callGoStackCheck() } +func stack4688() { var buf [4688]byte; use(buf[:]); C.callGoStackCheck() } +func stack4692() { var buf [4692]byte; use(buf[:]); C.callGoStackCheck() } +func stack4696() { var buf [4696]byte; use(buf[:]); C.callGoStackCheck() } +func stack4700() { var buf [4700]byte; use(buf[:]); C.callGoStackCheck() } +func stack4704() { var buf [4704]byte; use(buf[:]); C.callGoStackCheck() } +func stack4708() { var buf [4708]byte; use(buf[:]); C.callGoStackCheck() } +func stack4712() { var buf [4712]byte; use(buf[:]); C.callGoStackCheck() } +func stack4716() { var buf [4716]byte; use(buf[:]); C.callGoStackCheck() } +func stack4720() { var buf [4720]byte; use(buf[:]); C.callGoStackCheck() } +func stack4724() { var buf [4724]byte; use(buf[:]); C.callGoStackCheck() } +func stack4728() { var buf [4728]byte; use(buf[:]); C.callGoStackCheck() } +func stack4732() { var buf [4732]byte; use(buf[:]); C.callGoStackCheck() } +func stack4736() { var buf [4736]byte; use(buf[:]); C.callGoStackCheck() } +func stack4740() { var buf [4740]byte; use(buf[:]); C.callGoStackCheck() } +func stack4744() { var buf [4744]byte; use(buf[:]); C.callGoStackCheck() } +func stack4748() { var buf [4748]byte; use(buf[:]); C.callGoStackCheck() } +func stack4752() { var buf [4752]byte; use(buf[:]); C.callGoStackCheck() } +func stack4756() { var buf [4756]byte; use(buf[:]); C.callGoStackCheck() } +func stack4760() { var buf [4760]byte; use(buf[:]); C.callGoStackCheck() } +func stack4764() { var buf [4764]byte; use(buf[:]); C.callGoStackCheck() } +func stack4768() { var buf [4768]byte; use(buf[:]); C.callGoStackCheck() } +func stack4772() { var buf [4772]byte; use(buf[:]); C.callGoStackCheck() } +func stack4776() { var buf [4776]byte; use(buf[:]); C.callGoStackCheck() } +func stack4780() { var buf [4780]byte; use(buf[:]); C.callGoStackCheck() } +func stack4784() { var buf [4784]byte; use(buf[:]); C.callGoStackCheck() } +func stack4788() { var buf [4788]byte; use(buf[:]); C.callGoStackCheck() } +func stack4792() { var buf [4792]byte; use(buf[:]); C.callGoStackCheck() } +func stack4796() { var buf [4796]byte; use(buf[:]); C.callGoStackCheck() } +func stack4800() { var buf [4800]byte; use(buf[:]); C.callGoStackCheck() } +func stack4804() { var buf [4804]byte; use(buf[:]); C.callGoStackCheck() } +func stack4808() { var buf [4808]byte; use(buf[:]); C.callGoStackCheck() } +func stack4812() { var buf [4812]byte; use(buf[:]); C.callGoStackCheck() } +func stack4816() { var buf [4816]byte; use(buf[:]); C.callGoStackCheck() } +func stack4820() { var buf [4820]byte; use(buf[:]); C.callGoStackCheck() } +func stack4824() { var buf [4824]byte; use(buf[:]); C.callGoStackCheck() } +func stack4828() { var buf [4828]byte; use(buf[:]); C.callGoStackCheck() } +func stack4832() { var buf [4832]byte; use(buf[:]); C.callGoStackCheck() } +func stack4836() { var buf [4836]byte; use(buf[:]); C.callGoStackCheck() } +func stack4840() { var buf [4840]byte; use(buf[:]); C.callGoStackCheck() } +func stack4844() { var buf [4844]byte; use(buf[:]); C.callGoStackCheck() } +func stack4848() { var buf [4848]byte; use(buf[:]); C.callGoStackCheck() } +func stack4852() { var buf [4852]byte; use(buf[:]); C.callGoStackCheck() } +func stack4856() { var buf [4856]byte; use(buf[:]); C.callGoStackCheck() } +func stack4860() { var buf [4860]byte; use(buf[:]); C.callGoStackCheck() } +func stack4864() { var buf [4864]byte; use(buf[:]); C.callGoStackCheck() } +func stack4868() { var buf [4868]byte; use(buf[:]); C.callGoStackCheck() } +func stack4872() { var buf [4872]byte; use(buf[:]); C.callGoStackCheck() } +func stack4876() { var buf [4876]byte; use(buf[:]); C.callGoStackCheck() } +func stack4880() { var buf [4880]byte; use(buf[:]); C.callGoStackCheck() } +func stack4884() { var buf [4884]byte; use(buf[:]); C.callGoStackCheck() } +func stack4888() { var buf [4888]byte; use(buf[:]); C.callGoStackCheck() } +func stack4892() { var buf [4892]byte; use(buf[:]); C.callGoStackCheck() } +func stack4896() { var buf [4896]byte; use(buf[:]); C.callGoStackCheck() } +func stack4900() { var buf [4900]byte; use(buf[:]); C.callGoStackCheck() } +func stack4904() { var buf [4904]byte; use(buf[:]); C.callGoStackCheck() } +func stack4908() { var buf [4908]byte; use(buf[:]); C.callGoStackCheck() } +func stack4912() { var buf [4912]byte; use(buf[:]); C.callGoStackCheck() } +func stack4916() { var buf [4916]byte; use(buf[:]); C.callGoStackCheck() } +func stack4920() { var buf [4920]byte; use(buf[:]); C.callGoStackCheck() } +func stack4924() { var buf [4924]byte; use(buf[:]); C.callGoStackCheck() } +func stack4928() { var buf [4928]byte; use(buf[:]); C.callGoStackCheck() } +func stack4932() { var buf [4932]byte; use(buf[:]); C.callGoStackCheck() } +func stack4936() { var buf [4936]byte; use(buf[:]); C.callGoStackCheck() } +func stack4940() { var buf [4940]byte; use(buf[:]); C.callGoStackCheck() } +func stack4944() { var buf [4944]byte; use(buf[:]); C.callGoStackCheck() } +func stack4948() { var buf [4948]byte; use(buf[:]); C.callGoStackCheck() } +func stack4952() { var buf [4952]byte; use(buf[:]); C.callGoStackCheck() } +func stack4956() { var buf [4956]byte; use(buf[:]); C.callGoStackCheck() } +func stack4960() { var buf [4960]byte; use(buf[:]); C.callGoStackCheck() } +func stack4964() { var buf [4964]byte; use(buf[:]); C.callGoStackCheck() } +func stack4968() { var buf [4968]byte; use(buf[:]); C.callGoStackCheck() } +func stack4972() { var buf [4972]byte; use(buf[:]); C.callGoStackCheck() } +func stack4976() { var buf [4976]byte; use(buf[:]); C.callGoStackCheck() } +func stack4980() { var buf [4980]byte; use(buf[:]); C.callGoStackCheck() } +func stack4984() { var buf [4984]byte; use(buf[:]); C.callGoStackCheck() } +func stack4988() { var buf [4988]byte; use(buf[:]); C.callGoStackCheck() } +func stack4992() { var buf [4992]byte; use(buf[:]); C.callGoStackCheck() } +func stack4996() { var buf [4996]byte; use(buf[:]); C.callGoStackCheck() } +func stack5000() { var buf [5000]byte; use(buf[:]); C.callGoStackCheck() } diff --git a/libgo/misc/cgo/test/callback_c.c b/libgo/misc/cgo/test/callback_c.c new file mode 100644 index 00000000000..8921b7306c6 --- /dev/null +++ b/libgo/misc/cgo/test/callback_c.c @@ -0,0 +1,90 @@ +// Copyright 2011 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. + +#include +#include +#include +#include "_cgo_export.h" + +void +callback(void *f) +{ + // use some stack space + volatile char data[64*1024]; + + data[0] = 0; + goCallback(f); + data[sizeof(data)-1] = 0; +} + +void +callGoFoo(void) +{ + extern void goFoo(void); + goFoo(); +} + +void +IntoC(void) +{ + BackIntoGo(); +} + +#ifdef WIN32 +#include +long long +mysleep(int seconds) { + long long st = GetTickCount(); + Sleep(1000 * seconds); + return st; +} +#else +#include +long long +mysleep(int seconds) { + long long st; + struct timeval tv; + gettimeofday(&tv, NULL); + st = tv.tv_sec * 1000 + tv.tv_usec / 1000; + sleep(seconds); + return st; +} +#endif + +long long +twoSleep(int n) +{ + BackgroundSleep(n); + return mysleep(n); +} + +void +callGoStackCheck(void) +{ + extern void goStackCheck(void); + goStackCheck(); +} + +int +returnAfterGrow(void) +{ + extern int goReturnVal(void); + goReturnVal(); + return 123456; +} + +int +returnAfterGrowFromGo(void) +{ + extern int goReturnVal(void); + return goReturnVal(); +} + +void +callGoWithString(void) +{ + extern void goWithString(GoString); + const char *str = "string passed from C to Go"; + goWithString((GoString){str, strlen(str)}); +} diff --git a/libgo/misc/cgo/test/callback_c_gc.c b/libgo/misc/cgo/test/callback_c_gc.c new file mode 100644 index 00000000000..eb720eba7c4 --- /dev/null +++ b/libgo/misc/cgo/test/callback_c_gc.c @@ -0,0 +1,25 @@ +// 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. + +// +build gc + +#include "_cgo_export.h" +#include +#include +#include + +/* Test calling panic from C. This is what SWIG does. */ + +extern void crosscall2(void (*fn)(void *, int), void *, int); +extern void _cgo_panic(void *, int); +extern void _cgo_allocate(void *, int); + +void +callPanic(void) +{ + struct { const char *p; } a; + a.p = "panic from C"; + crosscall2(_cgo_panic, &a, sizeof a); + *(int*)1 = 1; +} diff --git a/libgo/misc/cgo/test/callback_c_gccgo.c b/libgo/misc/cgo/test/callback_c_gccgo.c new file mode 100644 index 00000000000..4eaa8184b30 --- /dev/null +++ b/libgo/misc/cgo/test/callback_c_gccgo.c @@ -0,0 +1,21 @@ +// 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. + +// +build gccgo + +#include "_cgo_export.h" +#include +#include +#include + +/* Test calling panic from C. This is what SWIG does. */ + +extern void _cgo_panic(const char *); +extern void *_cgo_allocate(size_t); + +void +callPanic(void) +{ + _cgo_panic("panic from C"); +} diff --git a/libgo/misc/cgo/test/cflags.go b/libgo/misc/cgo/test/cflags.go new file mode 100644 index 00000000000..bc290bfcd5a --- /dev/null +++ b/libgo/misc/cgo/test/cflags.go @@ -0,0 +1,32 @@ +// 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. + +// Test that the #cgo CFLAGS directive works, +// with and without platform filters. +// See https://golang.org/issue/5224 for details. +package cgotest + +/* +#cgo CFLAGS: -DCOMMON_VALUE=123 +#cgo windows CFLAGS: -DIS_WINDOWS=1 +#cgo !windows CFLAGS: -DIS_WINDOWS=0 +int common = COMMON_VALUE; +int is_windows = IS_WINDOWS; +*/ +import "C" + +import ( + "runtime" + "testing" +) + +func testCflags(t *testing.T) { + is_windows := C.is_windows == 1 + if is_windows != (runtime.GOOS == "windows") { + t.Errorf("is_windows: %v, runtime.GOOS: %s", is_windows, runtime.GOOS) + } + if C.common != 123 { + t.Errorf("common: %v (expected 123)", C.common) + } +} diff --git a/libgo/misc/cgo/test/cgo_linux_test.go b/libgo/misc/cgo/test/cgo_linux_test.go new file mode 100644 index 00000000000..9c15f69e401 --- /dev/null +++ b/libgo/misc/cgo/test/cgo_linux_test.go @@ -0,0 +1,12 @@ +// Copyright 2012 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 cgotest + +import "testing" + +func TestSetgid(t *testing.T) { testSetgid(t) } +func Test6997(t *testing.T) { test6997(t) } +func TestBuildID(t *testing.T) { testBuildID(t) } +func Test9400(t *testing.T) { test9400(t) } diff --git a/libgo/misc/cgo/test/cgo_stubs_android_test.go b/libgo/misc/cgo/test/cgo_stubs_android_test.go new file mode 100644 index 00000000000..710e094cf77 --- /dev/null +++ b/libgo/misc/cgo/test/cgo_stubs_android_test.go @@ -0,0 +1,13 @@ +// Copyright 2012 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 cgotest + +import "testing" + +// Stubs for tests that fails to build on Android +func test6997(t *testing.T) {} +func test3775(t *testing.T) {} +func test8694(t *testing.T) {} +func testSigaltstack(t *testing.T) {} diff --git a/libgo/misc/cgo/test/cgo_test.go b/libgo/misc/cgo/test/cgo_test.go new file mode 100644 index 00000000000..a6de999752b --- /dev/null +++ b/libgo/misc/cgo/test/cgo_test.go @@ -0,0 +1,80 @@ +// Copyright 2011 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 cgotest + +import "testing" + +// The actual test functions are in non-_test.go files +// so that they can use cgo (import "C"). +// These wrappers are here for gotest to find. + +func TestAlign(t *testing.T) { testAlign(t) } +func TestConst(t *testing.T) { testConst(t) } +func TestEnum(t *testing.T) { testEnum(t) } +func TestAtol(t *testing.T) { testAtol(t) } +func TestErrno(t *testing.T) { testErrno(t) } +func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) } +func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) } +func TestCallback(t *testing.T) { testCallback(t) } +func TestCallbackGC(t *testing.T) { testCallbackGC(t) } +func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) } +func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) } +func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) } +func TestPanicFromC(t *testing.T) { testPanicFromC(t) } +func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } +func TestBlocking(t *testing.T) { testBlocking(t) } +func Test1328(t *testing.T) { test1328(t) } +func TestParallelSleep(t *testing.T) { testParallelSleep(t) } +func TestSetEnv(t *testing.T) { testSetEnv(t) } +func TestHelpers(t *testing.T) { testHelpers(t) } +func TestLibgcc(t *testing.T) { testLibgcc(t) } +func Test1635(t *testing.T) { test1635(t) } +func TestPrintf(t *testing.T) { testPrintf(t) } +func Test4029(t *testing.T) { test4029(t) } +func TestBoolAlign(t *testing.T) { testBoolAlign(t) } +func Test3729(t *testing.T) { test3729(t) } +func Test3775(t *testing.T) { test3775(t) } +func TestCthread(t *testing.T) { testCthread(t) } +func TestCallbackCallers(t *testing.T) { testCallbackCallers(t) } +func Test5227(t *testing.T) { test5227(t) } +func TestCflags(t *testing.T) { testCflags(t) } +func Test5337(t *testing.T) { test5337(t) } +func Test5548(t *testing.T) { test5548(t) } +func Test5603(t *testing.T) { test5603(t) } +func Test6833(t *testing.T) { test6833(t) } +func Test3250(t *testing.T) { test3250(t) } +func TestCallbackStack(t *testing.T) { testCallbackStack(t) } +func TestFpVar(t *testing.T) { testFpVar(t) } +func Test4339(t *testing.T) { test4339(t) } +func Test6390(t *testing.T) { test6390(t) } +func Test5986(t *testing.T) { test5986(t) } +func Test7665(t *testing.T) { test7665(t) } +func TestNaming(t *testing.T) { testNaming(t) } +func Test7560(t *testing.T) { test7560(t) } +func Test5242(t *testing.T) { test5242(t) } +func Test8092(t *testing.T) { test8092(t) } +func Test7978(t *testing.T) { test7978(t) } +func Test8694(t *testing.T) { test8694(t) } +func Test8517(t *testing.T) { test8517(t) } +func Test8811(t *testing.T) { test8811(t) } +func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) } +func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) } +func Test9026(t *testing.T) { test9026(t) } +func Test9510(t *testing.T) { test9510(t) } +func Test9557(t *testing.T) { test9557(t) } +func Test10303(t *testing.T) { test10303(t, 10) } +func Test11925(t *testing.T) { test11925(t) } +func Test12030(t *testing.T) { test12030(t) } +func TestGCC68255(t *testing.T) { testGCC68255(t) } +func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) } +func Test14838(t *testing.T) { test14838(t) } +func Test8756(t *testing.T) { test8756(t) } +func Test17065(t *testing.T) { test17065(t) } +func TestThreadLock(t *testing.T) { testThreadLockFunc(t) } +func TestCheckConst(t *testing.T) { testCheckConst(t) } +func Test17537(t *testing.T) { test17537(t) } +func Test18126(t *testing.T) { test18126(t) } + +func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/libgo/misc/cgo/test/cgo_thread_lock.go b/libgo/misc/cgo/test/cgo_thread_lock.go new file mode 100644 index 00000000000..b1050685182 --- /dev/null +++ b/libgo/misc/cgo/test/cgo_thread_lock.go @@ -0,0 +1,53 @@ +// 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. + +// +build linux,freebsd,openbsd + +package cgotest + +/* +#include +#include +void Gosched(void); +static int Ctid(void) { Gosched(); return syscall(SYS_gettid); } +*/ +import "C" + +import ( + "runtime" + "syscall" + "testing" + "time" +) + +//export Gosched +func Gosched() { + runtime.Gosched() +} + +func init() { + testThreadLockFunc = testThreadLock +} + +func testThreadLock(t *testing.T) { + stop := make(chan int) + go func() { + // We need the G continue running, + // so the M has a chance to run this G. + for { + select { + case <-stop: + return + case <-time.After(time.Millisecond * 100): + } + } + }() + defer close(stop) + + for i := 0; i < 1000; i++ { + if C.int(syscall.Gettid()) != C.Ctid() { + t.Fatalf("cgo has not locked OS thread") + } + } +} diff --git a/libgo/misc/cgo/test/cgo_unix_test.go b/libgo/misc/cgo/test/cgo_unix_test.go new file mode 100644 index 00000000000..e3d59166498 --- /dev/null +++ b/libgo/misc/cgo/test/cgo_unix_test.go @@ -0,0 +1,13 @@ +// 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. + +// +build !windows + +package cgotest + +import "testing" + +func TestSigaltstack(t *testing.T) { testSigaltstack(t) } +func TestSigprocmask(t *testing.T) { testSigprocmask(t) } +func Test18146(t *testing.T) { test18146(t) } diff --git a/libgo/misc/cgo/test/checkconst.go b/libgo/misc/cgo/test/checkconst.go new file mode 100644 index 00000000000..0160c1e0ced --- /dev/null +++ b/libgo/misc/cgo/test/checkconst.go @@ -0,0 +1,33 @@ +// 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 a constant in conjunction with pointer checking. + +package cgotest + +/* +#include + +#define CheckConstVal 0 + +typedef struct { + int *p; +} CheckConstStruct; + +static void CheckConstFunc(CheckConstStruct *p, int e) { +} +*/ +import "C" + +import ( + "testing" + "unsafe" +) + +func testCheckConst(t *testing.T) { + // The test is that this compiles successfully. + p := C.malloc(C.size_t(unsafe.Sizeof(C.int(0)))) + defer C.free(p) + C.CheckConstFunc(&C.CheckConstStruct{(*C.int)(p)}, C.CheckConstVal) +} diff --git a/libgo/misc/cgo/test/complex.go b/libgo/misc/cgo/test/complex.go new file mode 100644 index 00000000000..ca0a97d9b34 --- /dev/null +++ b/libgo/misc/cgo/test/complex.go @@ -0,0 +1,24 @@ +// 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 cgotest + +/* +struct { + float x; + _Complex float y; +} cplxAlign = { 3.14, 2.17 }; +*/ +import "C" + +import "testing" + +func TestComplexAlign(t *testing.T) { + if C.cplxAlign.x != 3.14 { + t.Errorf("got %v, expected 3.14", C.cplxAlign.x) + } + if C.cplxAlign.y != 2.17 { + t.Errorf("got %v, expected 2.17", C.cplxAlign.y) + } +} diff --git a/libgo/misc/cgo/test/cthread.go b/libgo/misc/cgo/test/cthread.go new file mode 100644 index 00000000000..af44911756a --- /dev/null +++ b/libgo/misc/cgo/test/cthread.go @@ -0,0 +1,44 @@ +// 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 cgotest + +// extern void doAdd(int, int); +import "C" + +import ( + "runtime" + "sync" + "testing" +) + +var sum struct { + sync.Mutex + i int +} + +//export Add +func Add(x int) { + defer func() { + recover() + }() + sum.Lock() + sum.i += x + sum.Unlock() + var p *int + *p = 2 +} + +func testCthread(t *testing.T) { + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add") + } + sum.i = 0 + C.doAdd(10, 6) + + want := 10 * (10 - 1) / 2 * 6 + if sum.i != want { + t.Fatalf("sum=%d, want %d", sum.i, want) + } +} diff --git a/libgo/misc/cgo/test/cthread_unix.c b/libgo/misc/cgo/test/cthread_unix.c new file mode 100644 index 00000000000..6323e4980e8 --- /dev/null +++ b/libgo/misc/cgo/test/cthread_unix.c @@ -0,0 +1,34 @@ +// 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. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +#include +#include "_cgo_export.h" + +static void* +addThread(void *p) +{ + int i, max; + + max = *(int*)p; + for(i=0; i MaxThread) + nthread = MaxThread; + for(i=0; i +#include +#include "_cgo_export.h" + +__stdcall +static unsigned int +addThread(void *p) +{ + int i, max; + + max = *(int*)p; + for(i=0; i MaxThread) + nthread = MaxThread; + for(i=0; i +*/ +import "C" +import ( + "os" + "runtime" + "testing" + "unsafe" +) + +// This is really an os package test but here for convenience. +func testSetEnv(t *testing.T) { + if runtime.GOOS == "windows" { + // Go uses SetEnvironmentVariable on windows. Howerver, + // C runtime takes a *copy* at process startup of thei + // OS environment, and stores it in environ/envp. + // It is this copy that getenv/putenv manipulate. + t.Logf("skipping test") + return + } + const key = "CGO_OS_TEST_KEY" + const val = "CGO_OS_TEST_VALUE" + os.Setenv(key, val) + keyc := C.CString(key) + defer C.free(unsafe.Pointer(keyc)) + v := C.getenv(keyc) + if uintptr(unsafe.Pointer(v)) == 0 { + t.Fatal("getenv returned NULL") + } + vs := C.GoString(v) + if vs != val { + t.Fatalf("getenv() = %q; want %q", vs, val) + } +} diff --git a/libgo/misc/cgo/test/exports.go b/libgo/misc/cgo/test/exports.go new file mode 100644 index 00000000000..71e5dcdd3df --- /dev/null +++ b/libgo/misc/cgo/test/exports.go @@ -0,0 +1,18 @@ +// Copyright 2011 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 cgotest + +import "C" +import "runtime" + +//export ReturnIntLong +func ReturnIntLong() (int, C.long) { + return 1, 2 +} + +//export gc +func gc() { + runtime.GC() +} diff --git a/libgo/misc/cgo/test/fpvar.go b/libgo/misc/cgo/test/fpvar.go new file mode 100644 index 00000000000..7aab8ca2fc2 --- /dev/null +++ b/libgo/misc/cgo/test/fpvar.go @@ -0,0 +1,50 @@ +// 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. + +// This file contains test cases for cgo with function pointer variables. + +package cgotest + +/* +typedef int (*intFunc) (); + +int +bridge_int_func(intFunc f) +{ + return f(); +} + +int fortytwo() +{ + return 42; +} + +*/ +import "C" +import "testing" + +func callBridge(f C.intFunc) int { + return int(C.bridge_int_func(f)) +} + +func callCBridge(f C.intFunc) C.int { + return C.bridge_int_func(f) +} + +func testFpVar(t *testing.T) { + const expected = 42 + f := C.intFunc(C.fortytwo) + res1 := C.bridge_int_func(f) + if r1 := int(res1); r1 != expected { + t.Errorf("got %d, want %d", r1, expected) + } + res2 := callCBridge(f) + if r2 := int(res2); r2 != expected { + t.Errorf("got %d, want %d", r2, expected) + } + r3 := callBridge(f) + if r3 != expected { + t.Errorf("got %d, want %d", r3, expected) + } +} diff --git a/libgo/misc/cgo/test/gcc68255.go b/libgo/misc/cgo/test/gcc68255.go new file mode 100644 index 00000000000..23e103dc109 --- /dev/null +++ b/libgo/misc/cgo/test/gcc68255.go @@ -0,0 +1,17 @@ +// 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 cgotest + +import ( + "testing" + + "./gcc68255" +) + +func testGCC68255(t *testing.T) { + if !gcc68255.F() { + t.Error("C global variable was not initialized") + } +} diff --git a/libgo/misc/cgo/test/gcc68255/a.go b/libgo/misc/cgo/test/gcc68255/a.go new file mode 100644 index 00000000000..e106dee3ec0 --- /dev/null +++ b/libgo/misc/cgo/test/gcc68255/a.go @@ -0,0 +1,17 @@ +// 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. + +// Test that it's OK to have C code that does nothing other than +// initialize a global variable. This used to fail with gccgo. + +package gcc68255 + +/* +#include "c.h" +*/ +import "C" + +func F() bool { + return C.v != nil +} diff --git a/libgo/misc/cgo/test/gcc68255/c.c b/libgo/misc/cgo/test/gcc68255/c.c new file mode 100644 index 00000000000..a4fe193825b --- /dev/null +++ b/libgo/misc/cgo/test/gcc68255/c.c @@ -0,0 +1,8 @@ +// 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. + +static void f(void) { +} + +void (*v)(void) = f; diff --git a/libgo/misc/cgo/test/gcc68255/c.h b/libgo/misc/cgo/test/gcc68255/c.h new file mode 100644 index 00000000000..05ecd8187c7 --- /dev/null +++ b/libgo/misc/cgo/test/gcc68255/c.h @@ -0,0 +1,5 @@ +// 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. + +extern void (*v)(void); diff --git a/libgo/misc/cgo/test/helpers.go b/libgo/misc/cgo/test/helpers.go new file mode 100644 index 00000000000..f6a822a1065 --- /dev/null +++ b/libgo/misc/cgo/test/helpers.go @@ -0,0 +1,35 @@ +// Copyright 2011 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 cgotest + +// const char *greeting = "hello, world"; +import "C" + +import ( + "reflect" + "testing" + "unsafe" +) + +const greeting = "hello, world" + +type testPair struct { + Name string + Got, Want interface{} +} + +var testPairs = []testPair{ + {"GoString", C.GoString(C.greeting), greeting}, + {"GoStringN", C.GoStringN(C.greeting, 5), greeting[:5]}, + {"GoBytes", C.GoBytes(unsafe.Pointer(C.greeting), 5), []byte(greeting[:5])}, +} + +func testHelpers(t *testing.T) { + for _, pair := range testPairs { + if !reflect.DeepEqual(pair.Got, pair.Want) { + t.Errorf("%s: got %#v, want %#v", pair.Name, pair.Got, pair.Want) + } + } +} diff --git a/libgo/misc/cgo/test/issue10303.go b/libgo/misc/cgo/test/issue10303.go new file mode 100644 index 00000000000..66e2644d066 --- /dev/null +++ b/libgo/misc/cgo/test/issue10303.go @@ -0,0 +1,76 @@ +// 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 10303. Pointers passed to C were not marked as escaping (bug in cgo). + +package cgotest + +import "runtime" + +/* +typedef int *intptr; + +void setintstar(int *x) { + *x = 1; +} + +void setintptr(intptr x) { + *x = 1; +} + +void setvoidptr(void *x) { + *(int*)x = 1; +} + +typedef struct Struct Struct; +struct Struct { + int *P; +}; + +void setstruct(Struct s) { + *s.P = 1; +} + +*/ +import "C" + +import ( + "testing" + "unsafe" +) + +func test10303(t *testing.T, n int) { + if runtime.Compiler == "gccgo" { + t.Skip("gccgo permits C pointers on the stack") + } + + // Run at a few different stack depths just to avoid an unlucky pass + // due to variables ending up on different pages. + if n > 0 { + test10303(t, n-1) + } + if t.Failed() { + return + } + var x, y, z, v, si C.int + var s C.Struct + C.setintstar(&x) + C.setintptr(&y) + C.setvoidptr(unsafe.Pointer(&v)) + s.P = &si + C.setstruct(s) + + if uintptr(unsafe.Pointer(&x))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff { + t.Error("C int* argument on stack") + } + if uintptr(unsafe.Pointer(&y))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff { + t.Error("C intptr argument on stack") + } + if uintptr(unsafe.Pointer(&v))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff { + t.Error("C void* argument on stack") + } + if uintptr(unsafe.Pointer(&si))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff { + t.Error("C struct field pointer on stack") + } +} diff --git a/libgo/misc/cgo/test/issue11925.go b/libgo/misc/cgo/test/issue11925.go new file mode 100644 index 00000000000..c5c8a269f79 --- /dev/null +++ b/libgo/misc/cgo/test/issue11925.go @@ -0,0 +1,37 @@ +// 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 11925. Structs with zero-length trailing fields are now +// padded by the Go compiler. + +package cgotest + +/* +struct a11925 { + int i; + char a[0]; + char b[0]; +}; + +struct b11925 { + int i; + char a[0]; + char b[]; +}; +*/ +import "C" + +import ( + "testing" + "unsafe" +) + +func test11925(t *testing.T) { + if C.sizeof_struct_a11925 != unsafe.Sizeof(C.struct_a11925{}) { + t.Errorf("size of a changed: C %d, Go %d", C.sizeof_struct_a11925, unsafe.Sizeof(C.struct_a11925{})) + } + if C.sizeof_struct_b11925 != unsafe.Sizeof(C.struct_b11925{}) { + t.Errorf("size of b changed: C %d, Go %d", C.sizeof_struct_b11925, unsafe.Sizeof(C.struct_b11925{})) + } +} diff --git a/libgo/misc/cgo/test/issue12030.go b/libgo/misc/cgo/test/issue12030.go new file mode 100644 index 00000000000..f863c58aa2a --- /dev/null +++ b/libgo/misc/cgo/test/issue12030.go @@ -0,0 +1,35 @@ +// 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 12030. sprintf is defined in both ntdll and msvcrt, +// Normally we want the one in the msvcrt. + +package cgotest + +/* +#include +#include +void issue12030conv(char *buf, double x) { + sprintf(buf, "d=%g", x); +} +*/ +import "C" + +import ( + "fmt" + "testing" + "unsafe" +) + +func test12030(t *testing.T) { + buf := (*C.char)(C.malloc(256)) + defer C.free(unsafe.Pointer(buf)) + for _, f := range []float64{1.0, 2.0, 3.14} { + C.issue12030conv(buf, C.double(f)) + got := C.GoString(buf) + if want := fmt.Sprintf("d=%g", f); got != want { + t.Fatalf("C.sprintf failed for %g: %q != %q", f, got, want) + } + } +} diff --git a/libgo/misc/cgo/test/issue1222.go b/libgo/misc/cgo/test/issue1222.go new file mode 100644 index 00000000000..4868da8e185 --- /dev/null +++ b/libgo/misc/cgo/test/issue1222.go @@ -0,0 +1,29 @@ +// Copyright 2010 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. + +// This file contains test cases for cgo. + +package cgotest + +/* +// issue 1222 +typedef union { + long align; +} xxpthread_mutex_t; + +struct ibv_async_event { + union { + int x; + } element; +}; + +struct ibv_context { + xxpthread_mutex_t mutex; +}; +*/ +import "C" + +type AsyncEvent struct { + event C.struct_ibv_async_event +} diff --git a/libgo/misc/cgo/test/issue1328.go b/libgo/misc/cgo/test/issue1328.go new file mode 100644 index 00000000000..2401c10e300 --- /dev/null +++ b/libgo/misc/cgo/test/issue1328.go @@ -0,0 +1,30 @@ +// Copyright 2011 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 cgotest + +import "testing" + +// extern void BackIntoGo(void); +// void IntoC(void); +import "C" + +//export BackIntoGo +func BackIntoGo() { + x := 1 + + for i := 0; i < 10000; i++ { + xvariadic(x) + if x != 1 { + panic("x is not 1?") + } + } +} + +func xvariadic(x ...interface{}) { +} + +func test1328(t *testing.T) { + C.IntoC() +} diff --git a/libgo/misc/cgo/test/issue13402.go b/libgo/misc/cgo/test/issue13402.go new file mode 100644 index 00000000000..3af24c2d3c2 --- /dev/null +++ b/libgo/misc/cgo/test/issue13402.go @@ -0,0 +1,10 @@ +// 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 cgotest + +import "C" + +var _ C.complexfloat +var _ C.complexdouble diff --git a/libgo/misc/cgo/test/issue13930.go b/libgo/misc/cgo/test/issue13930.go new file mode 100644 index 00000000000..c4a08ee7c9e --- /dev/null +++ b/libgo/misc/cgo/test/issue13930.go @@ -0,0 +1,13 @@ +// 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 13930. Test that cgo's multiple-value special form for +// C function calls works in variable declaration statements. + +package cgotest + +// #include +import "C" + +var _, _ = C.abs(0) diff --git a/libgo/misc/cgo/test/issue14838.go b/libgo/misc/cgo/test/issue14838.go new file mode 100644 index 00000000000..c8e1681295e --- /dev/null +++ b/libgo/misc/cgo/test/issue14838.go @@ -0,0 +1,37 @@ +// 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 14838. add CBytes function + +package cgotest + +/* +#include + +int check_cbytes(char *b, size_t l) { + int i; + for (i = 0; i < l; i++) { + if (b[i] != i) { + return 0; + } + } + return 1; +} +*/ +import "C" + +import ( + "testing" + "unsafe" +) + +func test14838(t *testing.T) { + data := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + cData := C.CBytes(data) + defer C.free(cData) + + if C.check_cbytes((*C.char)(cData), C.size_t(len(data))) == 0 { + t.Fatalf("mismatched data: expected %v, got %v", data, (*(*[10]byte)(unsafe.Pointer(cData)))[:]) + } +} diff --git a/libgo/misc/cgo/test/issue1560.go b/libgo/misc/cgo/test/issue1560.go new file mode 100644 index 00000000000..30f61522257 --- /dev/null +++ b/libgo/misc/cgo/test/issue1560.go @@ -0,0 +1,50 @@ +// Copyright 2011 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 cgotest + +/* +// mysleep returns the absolute start time in ms. +long long mysleep(int seconds); + +// twoSleep returns the absolute start time of the first sleep +// in ms. +long long twoSleep(int); +*/ +import "C" + +import ( + "testing" + "time" +) + +var sleepDone = make(chan int64) + +// parallelSleep returns the absolute difference between the start time +// of the two sleeps. +func parallelSleep(n int) int64 { + t := int64(C.twoSleep(C.int(n))) - <-sleepDone + if t < 0 { + return -t + } + return t +} + +//export BackgroundSleep +func BackgroundSleep(n int32) { + go func() { + sleepDone <- int64(C.mysleep(C.int(n))) + }() +} + +func testParallelSleep(t *testing.T) { + sleepSec := 1 + dt := time.Duration(parallelSleep(sleepSec)) * time.Millisecond + t.Logf("difference in start time for two sleep(%d) is %v", sleepSec, dt) + // bug used to run sleeps in serial, producing a 2*sleepSec-second delay. + // we detect if the start times of those sleeps are > 0.5*sleepSec-second. + if dt >= time.Duration(sleepSec)*time.Second/2 { + t.Fatalf("parallel %d-second sleeps slept for %f seconds", sleepSec, dt.Seconds()) + } +} diff --git a/libgo/misc/cgo/test/issue1635.go b/libgo/misc/cgo/test/issue1635.go new file mode 100644 index 00000000000..25899271c93 --- /dev/null +++ b/libgo/misc/cgo/test/issue1635.go @@ -0,0 +1,38 @@ +// Copyright 2012 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 cgotest + +/* +// Mac OS X's gcc will generate scattered relocation 2/1 for +// this function on Darwin/386, and 8l couldn't handle it. +// this example is in issue 1635 +#include +void scatter() { + void *p = scatter; + printf("scatter = %p\n", p); +} + +// Adding this explicit extern declaration makes this a test for +// https://gcc.gnu.org/PR68072 aka https://golang.org/issue/13344 . +// It used to cause a cgo error when building with GCC 6. +extern int hola; + +// this example is in issue 3253 +int hola = 0; +int testHola() { return hola; } +*/ +import "C" + +import "testing" + +func test1635(t *testing.T) { + C.scatter() + if v := C.hola; v != 0 { + t.Fatalf("C.hola is %d, should be 0", v) + } + if v := C.testHola(); v != 0 { + t.Fatalf("C.testHola() is %d, should be 0", v) + } +} diff --git a/libgo/misc/cgo/test/issue17065.go b/libgo/misc/cgo/test/issue17065.go new file mode 100644 index 00000000000..ede30bc3e63 --- /dev/null +++ b/libgo/misc/cgo/test/issue17065.go @@ -0,0 +1,29 @@ +// 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 cgotest + +/* +// Test that C symbols larger than a page play nicely with the race detector. +// See issue 17065. + +int ii[65537]; +*/ +import "C" + +import ( + "runtime" + "testing" +) + +var sink C.int + +func test17065(t *testing.T) { + if runtime.GOOS == "darwin" { + t.Skip("broken on darwin; issue 17065") + } + for i := range C.ii { + sink = C.ii[i] + } +} diff --git a/libgo/misc/cgo/test/issue17537.go b/libgo/misc/cgo/test/issue17537.go new file mode 100644 index 00000000000..777104e5122 --- /dev/null +++ b/libgo/misc/cgo/test/issue17537.go @@ -0,0 +1,58 @@ +// 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 17537. The void* cast introduced by cgo to avoid problems +// with const/volatile qualifiers breaks C preprocessor macros that +// emulate functions. + +package cgotest + +/* +#include + +typedef struct { + int i; +} S17537; + +int I17537(S17537 *p); + +#define I17537(p) ((p)->i) + +// Calling this function used to fail without the cast. +const int F17537(const char **p) { + return **p; +} + +// Calling this function used to trigger an error from the C compiler +// (issue 18298). +void F18298(const void *const *p) { +} + +// Test that conversions between typedefs work as they used to. +typedef const void *T18298_1; +struct S18298 { int i; }; +typedef const struct S18298 *T18298_2; +void G18298(T18298_1 t) { +} +*/ +import "C" + +import "testing" + +func test17537(t *testing.T) { + v := C.S17537{i: 17537} + if got, want := C.I17537(&v), C.int(17537); got != want { + t.Errorf("got %d, want %d", got, want) + } + + p := (*C.char)(C.malloc(1)) + *p = 17 + if got, want := C.F17537(&p), C.int(17); got != want { + t.Errorf("got %d, want %d", got, want) + } + + C.F18298(nil) + var v18298 C.T18298_2 + C.G18298(C.T18298_1(v18298)) +} diff --git a/libgo/misc/cgo/test/issue18126.go b/libgo/misc/cgo/test/issue18126.go new file mode 100644 index 00000000000..ac94a66aab7 --- /dev/null +++ b/libgo/misc/cgo/test/issue18126.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. + +// Issue 18126: cgo check of void function returning errno. + +package cgotest + +/* +#include + +void Issue18126C(void **p) { +} +*/ +import "C" + +import ( + "testing" +) + +func test18126(t *testing.T) { + p := C.malloc(1) + _, err := C.Issue18126C(&p) + C.free(p) + _ = err +} diff --git a/libgo/misc/cgo/test/issue18146.go b/libgo/misc/cgo/test/issue18146.go new file mode 100644 index 00000000000..3c600463f03 --- /dev/null +++ b/libgo/misc/cgo/test/issue18146.go @@ -0,0 +1,128 @@ +// 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. + +// +build !windows + +// Issue 18146: pthread_create failure during syscall.Exec. + +package cgotest + +import "C" + +import ( + "bytes" + "crypto/md5" + "os" + "os/exec" + "runtime" + "syscall" + "testing" + "time" +) + +func test18146(t *testing.T) { + if runtime.GOOS == "darwin" { + t.Skipf("skipping flaky test on %s; see golang.org/issue/18202", runtime.GOOS) + } + + if runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" { + t.Skipf("skipping on %s", runtime.GOARCH) + } + + attempts := 1000 + threads := 4 + + if testing.Short() { + attempts = 100 + } + + // Restrict the number of attempts based on RLIMIT_NPROC. + // Tediously, RLIMIT_NPROC was left out of the syscall package, + // probably because it is not in POSIX.1, so we define it here. + // It is not defined on Solaris. + var nproc int + setNproc := true + switch runtime.GOOS { + default: + setNproc = false + case "linux": + nproc = 6 + case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd": + nproc = 7 + } + if setNproc { + var rlim syscall.Rlimit + if syscall.Getrlimit(nproc, &rlim) == nil { + max := int(rlim.Cur) / (threads + 5) + if attempts > max { + t.Logf("lowering attempts from %d to %d for RLIMIT_NPROC", attempts, max) + attempts = max + } + } + } + + if os.Getenv("test18146") == "exec" { + runtime.GOMAXPROCS(1) + for n := threads; n > 0; n-- { + go func() { + for { + _ = md5.Sum([]byte("Hello, !")) + } + }() + } + runtime.GOMAXPROCS(threads) + argv := append(os.Args, "-test.run=NoSuchTestExists") + if err := syscall.Exec(os.Args[0], argv, os.Environ()); err != nil { + t.Fatal(err) + } + } + + var cmds []*exec.Cmd + defer func() { + for _, cmd := range cmds { + cmd.Process.Kill() + } + }() + + args := append(append([]string(nil), os.Args[1:]...), "-test.run=Test18146") + for n := attempts; n > 0; n-- { + cmd := exec.Command(os.Args[0], args...) + cmd.Env = append(os.Environ(), "test18146=exec") + buf := bytes.NewBuffer(nil) + cmd.Stdout = buf + cmd.Stderr = buf + if err := cmd.Start(); err != nil { + // We are starting so many processes that on + // some systems (problem seen on Darwin, + // Dragonfly, OpenBSD) the fork call will fail + // with EAGAIN. + if pe, ok := err.(*os.PathError); ok { + err = pe.Err + } + if se, ok := err.(syscall.Errno); ok && (se == syscall.EAGAIN || se == syscall.EMFILE) { + time.Sleep(time.Millisecond) + continue + } + + t.Error(err) + return + } + cmds = append(cmds, cmd) + } + + failures := 0 + for _, cmd := range cmds { + err := cmd.Wait() + if err == nil { + continue + } + + t.Errorf("syscall.Exec failed: %v\n%s", err, cmd.Stdout) + failures++ + } + + if failures > 0 { + t.Logf("Failed %v of %v attempts.", failures, len(cmds)) + } +} diff --git a/libgo/misc/cgo/test/issue2462.go b/libgo/misc/cgo/test/issue2462.go new file mode 100644 index 00000000000..febca1eb085 --- /dev/null +++ b/libgo/misc/cgo/test/issue2462.go @@ -0,0 +1,102 @@ +// Copyright 2011 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 cgotest + +import "C" + +//export exportbyte +func exportbyte() byte { + return 0 +} + +//export exportbool +func exportbool() bool { + return false +} + +//export exportrune +func exportrune() rune { + return 0 +} + +//export exporterror +func exporterror() error { + return nil +} + +//export exportint +func exportint() int { + return 0 +} + +//export exportuint +func exportuint() uint { + return 0 +} + +//export exportuintptr +func exportuintptr() uintptr { + return (uintptr)(0) +} + +//export exportint8 +func exportint8() int8 { + return 0 +} + +//export exportuint8 +func exportuint8() uint8 { + return 0 +} + +//export exportint16 +func exportint16() int16 { + return 0 +} + +//export exportuint16 +func exportuint16() uint16 { + return 0 +} + +//export exportint32 +func exportint32() int32 { + return 0 +} + +//export exportuint32 +func exportuint32() uint32 { + return 0 +} + +//export exportint64 +func exportint64() int64 { + return 0 +} + +//export exportuint64 +func exportuint64() uint64 { + return 0 +} + +//export exportfloat32 +func exportfloat32() float32 { + return 0 +} + +//export exportfloat64 +func exportfloat64() float64 { + return 0 +} + +//export exportcomplex64 +func exportcomplex64() complex64 { + return 0 +} + +//export exportcomplex128 +func exportcomplex128() complex128 { + return 0 +} diff --git a/libgo/misc/cgo/test/issue3250.go b/libgo/misc/cgo/test/issue3250.go new file mode 100644 index 00000000000..f85c16b2dce --- /dev/null +++ b/libgo/misc/cgo/test/issue3250.go @@ -0,0 +1,95 @@ +// 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. + +// +build !windows + +package cgotest + +/* +#include +#include +#include +#include + +static void *thread(void *p) { + const int M = 100; + int i; + (void)p; + for (i = 0; i < M; i++) { + pthread_kill(pthread_self(), SIGCHLD); + usleep(rand() % 20 + 5); + } + return NULL; +} +void testSendSIG() { + const int N = 20; + int i; + pthread_t tid[N]; + for (i = 0; i < N; i++) { + usleep(rand() % 200 + 100); + pthread_create(&tid[i], 0, thread, NULL); + } + for (i = 0; i < N; i++) + pthread_join(tid[i], 0); +} +*/ +import "C" + +import ( + "os" + "os/signal" + "syscall" + "testing" + "time" +) + +func test3250(t *testing.T) { + t.Skip("skipped, see golang.org/issue/5885") + const ( + thres = 1 + sig = syscall.SIGCHLD + ) + type result struct { + n int + sig os.Signal + } + var ( + sigCh = make(chan os.Signal, 10) + waitStart = make(chan struct{}) + waitDone = make(chan result) + ) + + signal.Notify(sigCh, sig) + + go func() { + n := 0 + alarm := time.After(time.Second * 3) + for { + select { + case <-waitStart: + waitStart = nil + case v := <-sigCh: + n++ + if v != sig || n > thres { + waitDone <- result{n, v} + return + } + case <-alarm: + waitDone <- result{n, sig} + return + } + } + }() + + waitStart <- struct{}{} + C.testSendSIG() + r := <-waitDone + if r.sig != sig { + t.Fatalf("received signal %v, but want %v", r.sig, sig) + } + t.Logf("got %d signals\n", r.n) + if r.n <= thres { + t.Fatalf("expected more than %d", thres) + } +} diff --git a/libgo/misc/cgo/test/issue3250w.go b/libgo/misc/cgo/test/issue3250w.go new file mode 100644 index 00000000000..c2193aa1f1c --- /dev/null +++ b/libgo/misc/cgo/test/issue3250w.go @@ -0,0 +1,11 @@ +// 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. + +// +build windows + +package cgotest + +import "testing" + +func test3250(t *testing.T) {} diff --git a/libgo/misc/cgo/test/issue3261.go b/libgo/misc/cgo/test/issue3261.go new file mode 100644 index 00000000000..71375698d37 --- /dev/null +++ b/libgo/misc/cgo/test/issue3261.go @@ -0,0 +1,49 @@ +// Copyright 2012 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 cgotest + +/* +// libgcc on ARM might be compiled as thumb code, but our 5l +// can't handle that, so we have to disable this test on arm. +#ifdef __ARMEL__ +#include +int vabs(int x) { + puts("testLibgcc is disabled on ARM because 5l cannot handle thumb library."); + return (x < 0) ? -x : x; +} +#elif defined(__arm64__) && defined(__clang__) +#include +int vabs(int x) { + puts("testLibgcc is disabled on ARM64 with clang due to lack of libgcc."); + return (x < 0) ? -x : x; +} +#else +int __absvsi2(int); // dummy prototype for libgcc function +// we shouldn't name the function abs, as gcc might use +// the builtin one. +int vabs(int x) { return __absvsi2(x); } +#endif +*/ +import "C" + +import "testing" + +func testLibgcc(t *testing.T) { + var table = []struct { + in, out C.int + }{ + {0, 0}, + {1, 1}, + {-42, 42}, + {1000300, 1000300}, + {1 - 1<<31, 1<<31 - 1}, + } + for _, v := range table { + if o := C.vabs(v.in); o != v.out { + t.Fatalf("abs(%d) got %d, should be %d", v.in, o, v.out) + return + } + } +} diff --git a/libgo/misc/cgo/test/issue3729.go b/libgo/misc/cgo/test/issue3729.go new file mode 100644 index 00000000000..947b90a00de --- /dev/null +++ b/libgo/misc/cgo/test/issue3729.go @@ -0,0 +1,47 @@ +// Copyright 2012 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 3729: cmd/cgo: access errno from void C function +// void f(void) returns [0]byte, error in Go world. + +// +build !windows + +package cgotest + +/* +#include + +void g(void) { + errno = E2BIG; +} + +// try to pass some non-trivial arguments to function g2 +const char _expA = 0x42; +const float _expB = 3.14159; +const short _expC = 0x55aa; +const int _expD = 0xdeadbeef; +void g2(int x, char a, float b, short c, int d) { + if (a == _expA && b == _expB && c == _expC && d == _expD) + errno = x; + else + errno = -1; +} +*/ +import "C" + +import ( + "syscall" + "testing" +) + +func test3729(t *testing.T) { + _, e := C.g() + if e != syscall.E2BIG { + t.Errorf("got %q, expect %q", e, syscall.E2BIG) + } + _, e = C.g2(C.EINVAL, C._expA, C._expB, C._expC, C._expD) + if e != syscall.EINVAL { + t.Errorf("got %q, expect %q", e, syscall.EINVAL) + } +} diff --git a/libgo/misc/cgo/test/issue3729w.go b/libgo/misc/cgo/test/issue3729w.go new file mode 100644 index 00000000000..69296b506e7 --- /dev/null +++ b/libgo/misc/cgo/test/issue3729w.go @@ -0,0 +1,16 @@ +// Copyright 2012 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 3729: cmd/cgo: access errno from void C function +// void f(void) returns [0]byte, error in Go world. + +// +build windows + +package cgotest + +import "testing" + +func test3729(t *testing.T) { + t.Log("skip errno test on Windows") +} diff --git a/libgo/misc/cgo/test/issue3741.go b/libgo/misc/cgo/test/issue3741.go new file mode 100644 index 00000000000..314038c1fe8 --- /dev/null +++ b/libgo/misc/cgo/test/issue3741.go @@ -0,0 +1,22 @@ +// Copyright 2012 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 cgotest + +import "C" + +//export exportSliceIn +func exportSliceIn(s []byte) bool { + return len(s) == cap(s) +} + +//export exportSliceOut +func exportSliceOut() []byte { + return []byte{1} +} + +//export exportSliceInOut +func exportSliceInOut(s []byte) []byte { + return s +} diff --git a/libgo/misc/cgo/test/issue3775.go b/libgo/misc/cgo/test/issue3775.go new file mode 100644 index 00000000000..5aca7602c03 --- /dev/null +++ b/libgo/misc/cgo/test/issue3775.go @@ -0,0 +1,39 @@ +// +build !android + +package cgotest + +/* +void lockOSThreadCallback(void); +inline static void lockOSThreadC(void) +{ + lockOSThreadCallback(); +} +int usleep(unsigned usec); +*/ +import "C" + +import ( + "runtime" + "testing" +) + +func init() { + // Same as test3775 but run during init so that + // there are two levels of internal runtime lock + // (1 for init, 1 for cgo). + // This would have been broken by CL 11663043. + C.lockOSThreadC() +} + +func test3775(t *testing.T) { + // Used to panic because of the UnlockOSThread below. + C.lockOSThreadC() +} + +//export lockOSThreadCallback +func lockOSThreadCallback() { + runtime.LockOSThread() + runtime.UnlockOSThread() + go C.usleep(10000) + runtime.Gosched() +} diff --git a/libgo/misc/cgo/test/issue3945.go b/libgo/misc/cgo/test/issue3945.go new file mode 100644 index 00000000000..2f9fe23b8dc --- /dev/null +++ b/libgo/misc/cgo/test/issue3945.go @@ -0,0 +1,22 @@ +// Copyright 2012 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 cgotest + +// Test that cgo reserves enough stack space during cgo call. +// See https://golang.org/issue/3945 for details. + +// #include +// +// void say() { +// printf("%s from C\n", "hello"); +// } +// +import "C" + +import "testing" + +func testPrintf(t *testing.T) { + C.say() +} diff --git a/libgo/misc/cgo/test/issue4029.c b/libgo/misc/cgo/test/issue4029.c new file mode 100644 index 00000000000..eab36834501 --- /dev/null +++ b/libgo/misc/cgo/test/issue4029.c @@ -0,0 +1,10 @@ +// 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. + +// +build !windows + +void call4029(void *arg) { + void (*fn)(void) = arg; + fn(); +} diff --git a/libgo/misc/cgo/test/issue4029.go b/libgo/misc/cgo/test/issue4029.go new file mode 100644 index 00000000000..5789b99ef67 --- /dev/null +++ b/libgo/misc/cgo/test/issue4029.go @@ -0,0 +1,68 @@ +// Copyright 2012 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. + +// +build !windows + +package cgotest + +/* +#include +#cgo linux LDFLAGS: -ldl + +extern void call4029(void *arg); +*/ +import "C" + +import ( + "testing" +) + +var callbacks int + +//export IMPIsOpaque +func IMPIsOpaque() { + callbacks++ +} + +//export IMPInitWithFrame +func IMPInitWithFrame() { + callbacks++ +} + +//export IMPDrawRect +func IMPDrawRect() { + callbacks++ +} + +//export IMPWindowResize +func IMPWindowResize() { + callbacks++ +} + +func test4029(t *testing.T) { + loadThySelf(t, "IMPWindowResize") + loadThySelf(t, "IMPDrawRect") + loadThySelf(t, "IMPInitWithFrame") + loadThySelf(t, "IMPIsOpaque") + if callbacks != 4 { + t.Errorf("got %d callbacks, expected 4", callbacks) + } +} + +func loadThySelf(t *testing.T, symbol string) { + this_process := C.dlopen(nil, C.RTLD_NOW) + if this_process == nil { + t.Error("dlopen:", C.GoString(C.dlerror())) + return + } + defer C.dlclose(this_process) + + symbol_address := C.dlsym(this_process, C.CString(symbol)) + if symbol_address == nil { + t.Error("dlsym:", C.GoString(C.dlerror())) + return + } + t.Log(symbol, symbol_address) + C.call4029(symbol_address) +} diff --git a/libgo/misc/cgo/test/issue4029w.go b/libgo/misc/cgo/test/issue4029w.go new file mode 100644 index 00000000000..18c720191be --- /dev/null +++ b/libgo/misc/cgo/test/issue4029w.go @@ -0,0 +1,12 @@ +// Copyright 2012 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. + +// +build windows + +package cgotest + +import "testing" + +func test4029(t *testing.T) { +} diff --git a/libgo/misc/cgo/test/issue4054a.go b/libgo/misc/cgo/test/issue4054a.go new file mode 100644 index 00000000000..2abdac59047 --- /dev/null +++ b/libgo/misc/cgo/test/issue4054a.go @@ -0,0 +1,23 @@ +// Copyright 2012 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 cgotest + +/* +typedef enum { + A = 0, + B, + C, + D, + E, + F, + G, + H, + I, + J, +} issue4054a; +*/ +import "C" + +var issue4054a = []int{C.A, C.B, C.C, C.D, C.E, C.F, C.G, C.H, C.I, C.J} diff --git a/libgo/misc/cgo/test/issue4054b.go b/libgo/misc/cgo/test/issue4054b.go new file mode 100644 index 00000000000..048964c8937 --- /dev/null +++ b/libgo/misc/cgo/test/issue4054b.go @@ -0,0 +1,23 @@ +// Copyright 2012 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 cgotest + +/* +typedef enum { + A = 0, + B, + C, + D, + E, + F, + G, + H, + I, + J, +} issue4054b; +*/ +import "C" + +var issue4054b = []int{C.A, C.B, C.C, C.D, C.E, C.F, C.G, C.H, C.I, C.J} diff --git a/libgo/misc/cgo/test/issue4273.c b/libgo/misc/cgo/test/issue4273.c new file mode 100644 index 00000000000..cac98768dea --- /dev/null +++ b/libgo/misc/cgo/test/issue4273.c @@ -0,0 +1,10 @@ +// Copyright 2012 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. + +#ifdef __ELF__ +__attribute__((weak)) +__attribute__((visibility("hidden"))) +void _compilerrt_abort_impl(const char *file, int line, const char *func) { +} +#endif diff --git a/libgo/misc/cgo/test/issue4273b.c b/libgo/misc/cgo/test/issue4273b.c new file mode 100644 index 00000000000..71e3f0d976a --- /dev/null +++ b/libgo/misc/cgo/test/issue4273b.c @@ -0,0 +1,11 @@ +// Copyright 2012 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. + +#ifdef __ELF__ +extern void _compilerrt_abort_impl(const char *file, int line, const char *func); + +void __my_abort(const char *file, int line, const char *func) { + _compilerrt_abort_impl(file, line, func); +} +#endif diff --git a/libgo/misc/cgo/test/issue4339.c b/libgo/misc/cgo/test/issue4339.c new file mode 100644 index 00000000000..15d0004078c --- /dev/null +++ b/libgo/misc/cgo/test/issue4339.c @@ -0,0 +1,18 @@ +#include +#include "issue4339.h" + +static void +impl(void) +{ + //printf("impl\n"); +} + +Issue4339 exported4339 = {"bar", impl}; + +void +handle4339(Issue4339 *x) +{ + //printf("handle\n"); + x->bar(); + //printf("done\n"); +} diff --git a/libgo/misc/cgo/test/issue4339.go b/libgo/misc/cgo/test/issue4339.go new file mode 100644 index 00000000000..4fa4b2bbd7e --- /dev/null +++ b/libgo/misc/cgo/test/issue4339.go @@ -0,0 +1,16 @@ +// 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 cgotest + +/* +#include "issue4339.h" +*/ +import "C" + +import "testing" + +func test4339(t *testing.T) { + C.handle4339(&C.exported4339) +} diff --git a/libgo/misc/cgo/test/issue4339.h b/libgo/misc/cgo/test/issue4339.h new file mode 100644 index 00000000000..20f6cebb6b5 --- /dev/null +++ b/libgo/misc/cgo/test/issue4339.h @@ -0,0 +1,9 @@ +typedef struct Issue4339 Issue4339; + +struct Issue4339 { + char *name; + void (*bar)(void); +}; + +extern Issue4339 exported4339; +void handle4339(Issue4339*); diff --git a/libgo/misc/cgo/test/issue4417.go b/libgo/misc/cgo/test/issue4417.go new file mode 100644 index 00000000000..9b182870d8e --- /dev/null +++ b/libgo/misc/cgo/test/issue4417.go @@ -0,0 +1,42 @@ +// Copyright 2012 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 4417: cmd/cgo: bool alignment/padding issue. +// bool alignment is wrong and causing wrong arguments when calling functions. +// + +package cgotest + +/* +#include + +static int c_bool(bool a, bool b, int c, bool d, bool e) { + return c; +} +*/ +import "C" +import "testing" + +func testBoolAlign(t *testing.T) { + b := C.c_bool(true, true, 10, true, false) + if b != 10 { + t.Fatalf("found %d expected 10\n", b) + } + b = C.c_bool(true, true, 5, true, true) + if b != 5 { + t.Fatalf("found %d expected 5\n", b) + } + b = C.c_bool(true, true, 3, true, false) + if b != 3 { + t.Fatalf("found %d expected 3\n", b) + } + b = C.c_bool(false, false, 1, true, false) + if b != 1 { + t.Fatalf("found %d expected 1\n", b) + } + b = C.c_bool(false, true, 200, true, false) + if b != 200 { + t.Fatalf("found %d expected 200\n", b) + } +} diff --git a/libgo/misc/cgo/test/issue4857.go b/libgo/misc/cgo/test/issue4857.go new file mode 100644 index 00000000000..b18979b5f7a --- /dev/null +++ b/libgo/misc/cgo/test/issue4857.go @@ -0,0 +1,15 @@ +// 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 cgotest + +/* +#cgo CFLAGS: -Werror +const struct { int a; } *issue4857() { return (void *)0; } +*/ +import "C" + +func test4857() { + _ = C.issue4857() +} diff --git a/libgo/misc/cgo/test/issue5227.go b/libgo/misc/cgo/test/issue5227.go new file mode 100644 index 00000000000..53c3bf12d74 --- /dev/null +++ b/libgo/misc/cgo/test/issue5227.go @@ -0,0 +1,38 @@ +// 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. + +// Issue 5227: linker incorrectly treats common symbols and +// leaves them undefined. + +package cgotest + +/* +typedef struct { + int Count; +} Fontinfo; + +Fontinfo SansTypeface; + +extern void init(); + +Fontinfo loadfont() { + Fontinfo f = {0}; + return f; +} + +void init() { + SansTypeface = loadfont(); +} +*/ +import "C" + +import "testing" + +func test5227(t *testing.T) { + C.init() +} + +func selectfont() C.Fontinfo { + return C.SansTypeface +} diff --git a/libgo/misc/cgo/test/issue5242.go b/libgo/misc/cgo/test/issue5242.go new file mode 100644 index 00000000000..c81cd409199 --- /dev/null +++ b/libgo/misc/cgo/test/issue5242.go @@ -0,0 +1,31 @@ +// 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. + +// Issue 5242. Cgo incorrectly computed the alignment of structs +// with no Go accessible fields as 0, and then panicked on +// modulo-by-zero computations. + +package cgotest + +/* +typedef struct { +} foo; + +typedef struct { + int x : 1; +} bar; + +int issue5242(foo f, bar b) { + return 5242; +} +*/ +import "C" + +import "testing" + +func test5242(t *testing.T) { + if got := C.issue5242(C.foo{}, C.bar{}); got != 5242 { + t.Errorf("got %v", got) + } +} diff --git a/libgo/misc/cgo/test/issue5337.go b/libgo/misc/cgo/test/issue5337.go new file mode 100644 index 00000000000..9041d95168d --- /dev/null +++ b/libgo/misc/cgo/test/issue5337.go @@ -0,0 +1,31 @@ +// 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. + +// +build !windows + +package cgotest + +/* +#include +#include + +static void *thread1(void *p) { + (void)p; + pthread_kill(pthread_self(), SIGPROF); + return NULL; +} +void test5337() { + pthread_t tid; + pthread_create(&tid, 0, thread1, NULL); + pthread_join(tid, 0); +} +*/ +import "C" + +import "testing" + +// Verify that we can withstand SIGPROF received on foreign threads +func test5337(t *testing.T) { + C.test5337() +} diff --git a/libgo/misc/cgo/test/issue5337w.go b/libgo/misc/cgo/test/issue5337w.go new file mode 100644 index 00000000000..7b467577007 --- /dev/null +++ b/libgo/misc/cgo/test/issue5337w.go @@ -0,0 +1,11 @@ +// 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. + +// +build windows + +package cgotest + +import "testing" + +func test5337(t *testing.T) {} diff --git a/libgo/misc/cgo/test/issue5548.go b/libgo/misc/cgo/test/issue5548.go new file mode 100644 index 00000000000..0710da79507 --- /dev/null +++ b/libgo/misc/cgo/test/issue5548.go @@ -0,0 +1,27 @@ +// 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 cgotest + +import "testing" + +/* +extern int issue5548_in_c(void); +*/ +import "C" + +//export issue5548FromC +func issue5548FromC(s string, i int) int { + if len(s) == 4 && s == "test" && i == 42 { + return 12345 + } + println("got", len(s), i) + return 9876 +} + +func test5548(t *testing.T) { + if x := C.issue5548_in_c(); x != 12345 { + t.Errorf("issue5548_in_c = %d, want %d", x, 12345) + } +} diff --git a/libgo/misc/cgo/test/issue5548_c.c b/libgo/misc/cgo/test/issue5548_c.c new file mode 100644 index 00000000000..84115266ffd --- /dev/null +++ b/libgo/misc/cgo/test/issue5548_c.c @@ -0,0 +1,24 @@ +// 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. + +#include "_cgo_export.h" + +static void clobber_stack() { + volatile char a[1024]; + int i; + for(i = 0; i < sizeof a; i++) + a[i] = 0xff; +} + +static int call_go() { + GoString s; + s.p = "test"; + s.n = 4; + return issue5548FromC(s, 42); +} + +int issue5548_in_c() { + clobber_stack(); + return call_go(); +} diff --git a/libgo/misc/cgo/test/issue5603.go b/libgo/misc/cgo/test/issue5603.go new file mode 100644 index 00000000000..ab84339e101 --- /dev/null +++ b/libgo/misc/cgo/test/issue5603.go @@ -0,0 +1,32 @@ +// 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 cgotest + +/* +const long long issue5603exp = 0x12345678; +long long issue5603foo0() { return issue5603exp; } +long long issue5603foo1(void *p) { return issue5603exp; } +long long issue5603foo2(void *p, void *q) { return issue5603exp; } +long long issue5603foo3(void *p, void *q, void *r) { return issue5603exp; } +long long issue5603foo4(void *p, void *q, void *r, void *s) { return issue5603exp; } +*/ +import "C" + +import "testing" + +func test5603(t *testing.T) { + var x [5]int64 + exp := int64(C.issue5603exp) + x[0] = int64(C.issue5603foo0()) + x[1] = int64(C.issue5603foo1(nil)) + x[2] = int64(C.issue5603foo2(nil, nil)) + x[3] = int64(C.issue5603foo3(nil, nil, nil)) + x[4] = int64(C.issue5603foo4(nil, nil, nil, nil)) + for i, v := range x { + if v != exp { + t.Errorf("issue5603foo%d() returns %v, expected %v", i, v, exp) + } + } +} diff --git a/libgo/misc/cgo/test/issue5740.go b/libgo/misc/cgo/test/issue5740.go new file mode 100644 index 00000000000..059e316119d --- /dev/null +++ b/libgo/misc/cgo/test/issue5740.go @@ -0,0 +1,15 @@ +// 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 cgotest + +// int test5740a(void), test5740b(void); +import "C" +import "testing" + +func test5740(t *testing.T) { + if v := C.test5740a() + C.test5740b(); v != 5 { + t.Errorf("expected 5, got %v", v) + } +} diff --git a/libgo/misc/cgo/test/issue5740a.c b/libgo/misc/cgo/test/issue5740a.c new file mode 100644 index 00000000000..a6a7d0c9601 --- /dev/null +++ b/libgo/misc/cgo/test/issue5740a.c @@ -0,0 +1,9 @@ +// 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. + +static int volatile val = 2; + +int test5740a() { + return val; +} diff --git a/libgo/misc/cgo/test/issue5740b.c b/libgo/misc/cgo/test/issue5740b.c new file mode 100644 index 00000000000..c2ff5fbc4a5 --- /dev/null +++ b/libgo/misc/cgo/test/issue5740b.c @@ -0,0 +1,9 @@ +// 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. + +static int volatile val = 3; + +int test5740b() { + return val; +} diff --git a/libgo/misc/cgo/test/issue5986.go b/libgo/misc/cgo/test/issue5986.go new file mode 100644 index 00000000000..9be1614233e --- /dev/null +++ b/libgo/misc/cgo/test/issue5986.go @@ -0,0 +1,33 @@ +// 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 cgotest + +/* +#cgo LDFLAGS: -lm +#include +#include + +static void output5986() +{ + int current_row = 0, row_count = 0; + double sum_squares = 0; + double d; + do { + if (current_row == 10) { + current_row = 0; + } + ++row_count; + } + while (current_row++ != 1); + d = sqrt(sum_squares / row_count); + printf("sqrt is: %g\n", d); +} +*/ +import "C" +import "testing" + +func test5986(t *testing.T) { + C.output5986() +} diff --git a/libgo/misc/cgo/test/issue6128.go b/libgo/misc/cgo/test/issue6128.go new file mode 100644 index 00000000000..9832d799b94 --- /dev/null +++ b/libgo/misc/cgo/test/issue6128.go @@ -0,0 +1,20 @@ +// 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 cgotest + +// Test handling of #defined names in clang. +// golang.org/issue/6128. + +/* +// NOTE: Must use hex, or else a shortcut for decimals +// in cgo avoids trying to pass this to clang. +#define X 0x1 +*/ +import "C" + +func test6128() { + // nothing to run, just make sure this compiles. + _ = C.X +} diff --git a/libgo/misc/cgo/test/issue6390.go b/libgo/misc/cgo/test/issue6390.go new file mode 100644 index 00000000000..5642899c587 --- /dev/null +++ b/libgo/misc/cgo/test/issue6390.go @@ -0,0 +1,23 @@ +// 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 cgotest + +// #include +import "C" + +import "testing" + +func test6390(t *testing.T) { + p1 := C.malloc(1024) + if p1 == nil { + t.Fatalf("C.malloc(1024) returned nil") + } + p2 := C.malloc(0) + if p2 == nil { + t.Fatalf("C.malloc(0) returned nil") + } + C.free(p1) + C.free(p2) +} diff --git a/libgo/misc/cgo/test/issue6472.go b/libgo/misc/cgo/test/issue6472.go new file mode 100644 index 00000000000..d416a05e29d --- /dev/null +++ b/libgo/misc/cgo/test/issue6472.go @@ -0,0 +1,22 @@ +// 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 cgotest + +/* +typedef struct +{ + struct + { + int x; + } y[16]; +} z; +*/ +import "C" + +func test6472() { + // nothing to run, just make sure this compiles + s := new(C.z) + println(s.y[0].x) +} diff --git a/libgo/misc/cgo/test/issue6506.go b/libgo/misc/cgo/test/issue6506.go new file mode 100644 index 00000000000..c54b54b64fc --- /dev/null +++ b/libgo/misc/cgo/test/issue6506.go @@ -0,0 +1,36 @@ +// 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 cgotest + +// Test handling of size_t in the face of incorrect clang debug information. +// golang.org/issue/6506. + +/* +#include +#include +*/ +import "C" + +func test6506() { + // nothing to run, just make sure this compiles + var x C.size_t + + C.calloc(x, x) + C.malloc(x) + C.realloc(nil, x) + C.memcpy(nil, nil, x) + C.memcmp(nil, nil, x) + C.memmove(nil, nil, x) + C.strncpy(nil, nil, x) + C.strncmp(nil, nil, x) + C.strncat(nil, nil, x) + x = C.strxfrm(nil, nil, x) + C.memchr(nil, 0, x) + x = C.strcspn(nil, nil) + x = C.strspn(nil, nil) + C.memset(nil, 0, x) + x = C.strlen(nil) + _ = x +} diff --git a/libgo/misc/cgo/test/issue6612.go b/libgo/misc/cgo/test/issue6612.go new file mode 100644 index 00000000000..c337f911d90 --- /dev/null +++ b/libgo/misc/cgo/test/issue6612.go @@ -0,0 +1,93 @@ +// 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. + +// golang.org/issue/6612 +// Test new scheme for deciding whether C.name is an expression, type, constant. +// Clang silences some warnings when the name is a #defined macro, so test those too +// (even though we now use errors exclusively, not warnings). + +package cgotest + +/* +void myfunc(void) {} +int myvar = 5; +const char *mytext = "abcdef"; +typedef int mytype; +enum { + myenum = 1234, +}; + +#define myfunc_def myfunc +#define myvar_def myvar +#define mytext_def mytext +#define mytype_def mytype +#define myenum_def myenum +#define myint_def 12345 +#define myfloat_def 1.5 +#define mystring_def "hello" +*/ +import "C" + +import "testing" + +func testNaming(t *testing.T) { + C.myfunc() + C.myfunc_def() + if v := C.myvar; v != 5 { + t.Errorf("C.myvar = %d, want 5", v) + } + if v := C.myvar_def; v != 5 { + t.Errorf("C.myvar_def = %d, want 5", v) + } + if s := C.GoString(C.mytext); s != "abcdef" { + t.Errorf("C.mytext = %q, want %q", s, "abcdef") + } + if s := C.GoString(C.mytext_def); s != "abcdef" { + t.Errorf("C.mytext_def = %q, want %q", s, "abcdef") + } + if c := C.myenum; c != 1234 { + t.Errorf("C.myenum = %v, want 1234", c) + } + if c := C.myenum_def; c != 1234 { + t.Errorf("C.myenum_def = %v, want 1234", c) + } + { + const c = C.myenum + if c != 1234 { + t.Errorf("C.myenum as const = %v, want 1234", c) + } + } + { + const c = C.myenum_def + if c != 1234 { + t.Errorf("C.myenum as const = %v, want 1234", c) + } + } + if c := C.myint_def; c != 12345 { + t.Errorf("C.myint_def = %v, want 12345", c) + } + { + const c = C.myint_def + if c != 12345 { + t.Errorf("C.myint as const = %v, want 12345", c) + } + } + + // This would be nice, but it has never worked. + /* + if c := C.myfloat_def; c != 1.5 { + t.Errorf("C.myint_def = %v, want 1.5", c) + } + { + const c = C.myfloat_def + if c != 1.5 { + t.Errorf("C.myint as const = %v, want 1.5", c) + } + } + */ + + if s := C.mystring_def; s != "hello" { + t.Errorf("C.mystring_def = %q, want %q", s, "hello") + } +} diff --git a/libgo/misc/cgo/test/issue6833.go b/libgo/misc/cgo/test/issue6833.go new file mode 100644 index 00000000000..de60dbfcf20 --- /dev/null +++ b/libgo/misc/cgo/test/issue6833.go @@ -0,0 +1,27 @@ +// 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 cgotest + +/* +extern unsigned long long issue6833Func(unsigned int, unsigned long long); +*/ +import "C" + +import "testing" + +//export GoIssue6833Func +func GoIssue6833Func(aui uint, aui64 uint64) uint64 { + return aui64 + uint64(aui) +} + +func test6833(t *testing.T) { + ui := 7 + ull := uint64(0x4000300020001000) + v := uint64(C.issue6833Func(C.uint(ui), C.ulonglong(ull))) + exp := uint64(ui) + ull + if v != exp { + t.Errorf("issue6833Func() returns %x, expected %x", v, exp) + } +} diff --git a/libgo/misc/cgo/test/issue6833_c.c b/libgo/misc/cgo/test/issue6833_c.c new file mode 100644 index 00000000000..c94c2c6d457 --- /dev/null +++ b/libgo/misc/cgo/test/issue6833_c.c @@ -0,0 +1,10 @@ +// 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. + +#include "_cgo_export.h" + +unsigned long long +issue6833Func(unsigned int aui, unsigned long long aull) { + return GoIssue6833Func(aui, aull); +} diff --git a/libgo/misc/cgo/test/issue6997_linux.c b/libgo/misc/cgo/test/issue6997_linux.c new file mode 100644 index 00000000000..de803d296e9 --- /dev/null +++ b/libgo/misc/cgo/test/issue6997_linux.c @@ -0,0 +1,28 @@ +// 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. + +// +build !android + +#include +#include +#include + +static pthread_t thread; + +static void* threadfunc(void* dummy) { + while(1) { + sleep(1); + } +} + +int StartThread() { + return pthread_create(&thread, NULL, &threadfunc, NULL); +} + +int CancelThread() { + void *r; + pthread_cancel(thread); + pthread_join(thread, &r); + return (r == PTHREAD_CANCELED); +} diff --git a/libgo/misc/cgo/test/issue6997_linux.go b/libgo/misc/cgo/test/issue6997_linux.go new file mode 100644 index 00000000000..0c98ea0794e --- /dev/null +++ b/libgo/misc/cgo/test/issue6997_linux.go @@ -0,0 +1,42 @@ +// 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. + +// +build !android + +// Test that pthread_cancel works as expected +// (NPTL uses SIGRTMIN to implement thread cancelation) +// See https://golang.org/issue/6997 +package cgotest + +/* +#cgo CFLAGS: -pthread +#cgo LDFLAGS: -pthread +extern int StartThread(); +extern int CancelThread(); +*/ +import "C" + +import "testing" +import "time" + +func test6997(t *testing.T) { + r := C.StartThread() + if r != 0 { + t.Error("pthread_create failed") + } + c := make(chan C.int) + go func() { + time.Sleep(500 * time.Millisecond) + c <- C.CancelThread() + }() + + select { + case r = <-c: + if r == 0 { + t.Error("pthread finished but wasn't canceled??") + } + case <-time.After(30 * time.Second): + t.Error("hung in pthread_cancel/pthread_join") + } +} diff --git a/libgo/misc/cgo/test/issue7234_test.go b/libgo/misc/cgo/test/issue7234_test.go new file mode 100644 index 00000000000..c191a1a66fe --- /dev/null +++ b/libgo/misc/cgo/test/issue7234_test.go @@ -0,0 +1,21 @@ +// 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 cgotest + +import "testing" + +// This test actually doesn't have anything to do with cgo. It is a +// test of https://golang.org/issue/7234, a compiler/linker bug in +// handling string constants when using -linkmode=external. The test +// is in this directory because we routinely test -linkmode=external +// here. + +var v7234 = [...]string{"runtime/cgo"} + +func Test7234(t *testing.T) { + if v7234[0] != "runtime/cgo" { + t.Errorf("bad string constant %q", v7234[0]) + } +} diff --git a/libgo/misc/cgo/test/issue7560.go b/libgo/misc/cgo/test/issue7560.go new file mode 100644 index 00000000000..f36d8a10234 --- /dev/null +++ b/libgo/misc/cgo/test/issue7560.go @@ -0,0 +1,44 @@ +// 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 cgotest + +/* +#include + +typedef struct { + char x; + long y; +} __attribute__((__packed__)) misaligned; + +int +offset7560(void) +{ + return (uintptr_t)&((misaligned*)0)->y; +} +*/ +import "C" + +import ( + "reflect" + "testing" +) + +func test7560(t *testing.T) { + // some mingw don't implement __packed__ correctly. + if C.offset7560() != 1 { + t.Skip("C compiler did not pack struct") + } + + // C.misaligned should have x but then a padding field to get to the end of the struct. + // There should not be a field named 'y'. + var v C.misaligned + rt := reflect.TypeOf(&v).Elem() + if rt.NumField() != 2 || rt.Field(0).Name != "x" || rt.Field(1).Name != "_" { + t.Errorf("unexpected fields in C.misaligned:\n") + for i := 0; i < rt.NumField(); i++ { + t.Logf("%+v\n", rt.Field(i)) + } + } +} diff --git a/libgo/misc/cgo/test/issue7665.go b/libgo/misc/cgo/test/issue7665.go new file mode 100644 index 00000000000..ce0345845f9 --- /dev/null +++ b/libgo/misc/cgo/test/issue7665.go @@ -0,0 +1,25 @@ +// 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 cgotest + +import ( + "testing" + "unsafe" +) + +// extern void f7665(void); +import "C" + +//export f7665 +func f7665() {} + +var bad7665 unsafe.Pointer = C.f7665 +var good7665 uintptr = uintptr(C.f7665) + +func test7665(t *testing.T) { + if bad7665 == nil || uintptr(bad7665) != good7665 { + t.Errorf("ptrs = %p, %#x, want same non-nil pointer", bad7665, good7665) + } +} diff --git a/libgo/misc/cgo/test/issue7786.go b/libgo/misc/cgo/test/issue7786.go new file mode 100644 index 00000000000..1344e9eda62 --- /dev/null +++ b/libgo/misc/cgo/test/issue7786.go @@ -0,0 +1,51 @@ +// 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. + +// Issue 7786. No runtime test, just make sure that typedef and struct/union/class are interchangeable at compile time. + +package cgotest + +// struct test7786; +// typedef struct test7786 typedef_test7786; +// void f7786(struct test7786 *ctx) {} +// void g7786(typedef_test7786 *ctx) {} +// +// typedef struct body7786 typedef_body7786; +// struct body7786 { int x; }; +// void b7786(struct body7786 *ctx) {} +// void c7786(typedef_body7786 *ctx) {} +// +// typedef union union7786 typedef_union7786; +// void u7786(union union7786 *ctx) {} +// void v7786(typedef_union7786 *ctx) {} +import "C" + +func f() { + var x1 *C.typedef_test7786 + var x2 *C.struct_test7786 + x1 = x2 + x2 = x1 + C.f7786(x1) + C.f7786(x2) + C.g7786(x1) + C.g7786(x2) + + var b1 *C.typedef_body7786 + var b2 *C.struct_body7786 + b1 = b2 + b2 = b1 + C.b7786(b1) + C.b7786(b2) + C.c7786(b1) + C.c7786(b2) + + var u1 *C.typedef_union7786 + var u2 *C.union_union7786 + u1 = u2 + u2 = u1 + C.u7786(u1) + C.u7786(u2) + C.v7786(u1) + C.v7786(u2) +} diff --git a/libgo/misc/cgo/test/issue7978.go b/libgo/misc/cgo/test/issue7978.go new file mode 100644 index 00000000000..7fb62e807ba --- /dev/null +++ b/libgo/misc/cgo/test/issue7978.go @@ -0,0 +1,138 @@ +// 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. + +// Issue 7978. Stack tracing didn't work during cgo code after calling a Go +// callback. Make sure GC works and the stack trace is correct. + +package cgotest + +/* +#include + +void issue7978cb(void); + +#if defined(__APPLE__) && defined(__arm__) +// on Darwin/ARM, libSystem doesn't provide implementation of the __sync_fetch_and_add +// primitive, and although gcc supports it, it doesn't inline its definition. +// Clang could inline its definition, so we require clang on Darwin/ARM. +#if defined(__clang__) +#define HAS_SYNC_FETCH_AND_ADD 1 +#else +#define HAS_SYNC_FETCH_AND_ADD 0 +#endif +#else +#define HAS_SYNC_FETCH_AND_ADD 1 +#endif + +// use ugly atomic variable sync since that doesn't require calling back into +// Go code or OS dependencies +static void issue7978c(uint32_t *sync) { +#if HAS_SYNC_FETCH_AND_ADD + while(__sync_fetch_and_add(sync, 0) != 0) + ; + __sync_fetch_and_add(sync, 1); + while(__sync_fetch_and_add(sync, 0) != 2) + ; + issue7978cb(); + __sync_fetch_and_add(sync, 1); + while(__sync_fetch_and_add(sync, 0) != 6) + ; +#endif +} +*/ +import "C" + +import ( + "os" + "runtime" + "strings" + "sync/atomic" + "testing" +) + +var issue7978sync uint32 + +func issue7978check(t *testing.T, wantFunc string, badFunc string, depth int) { + runtime.GC() + buf := make([]byte, 65536) + trace := string(buf[:runtime.Stack(buf, true)]) + for _, goroutine := range strings.Split(trace, "\n\n") { + if strings.Contains(goroutine, "test.issue7978go") { + trace := strings.Split(goroutine, "\n") + // look for the expected function in the stack + for i := 0; i < depth; i++ { + if badFunc != "" && strings.Contains(trace[1+2*i], badFunc) { + t.Errorf("bad stack: found %s in the stack:\n%s", badFunc, goroutine) + return + } + if strings.Contains(trace[1+2*i], wantFunc) { + return + } + } + t.Errorf("bad stack: didn't find %s in the stack:\n%s", wantFunc, goroutine) + return + } + } + t.Errorf("bad stack: goroutine not found. Full stack dump:\n%s", trace) +} + +func issue7978wait(store uint32, wait uint32) { + if store != 0 { + atomic.StoreUint32(&issue7978sync, store) + } + for atomic.LoadUint32(&issue7978sync) != wait { + runtime.Gosched() + } +} + +//export issue7978cb +func issue7978cb() { + // Force a stack growth from the callback to put extra + // pressure on the runtime. See issue #17785. + growStack(64) + issue7978wait(3, 4) +} + +func growStack(n int) int { + var buf [128]int + if n == 0 { + return 0 + } + return buf[growStack(n-1)] +} + +func issue7978go() { + C.issue7978c((*C.uint32_t)(&issue7978sync)) + issue7978wait(7, 8) +} + +func test7978(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("gccgo can not do stack traces of C code") + } + if C.HAS_SYNC_FETCH_AND_ADD == 0 { + t.Skip("clang required for __sync_fetch_and_add support on darwin/arm") + } + if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("GOTRACEBACK is not passed on to the exec wrapper") + } + if os.Getenv("GOTRACEBACK") != "2" { + t.Fatalf("GOTRACEBACK must be 2") + } + issue7978sync = 0 + go issue7978go() + // test in c code, before callback + issue7978wait(0, 1) + issue7978check(t, "_Cfunc_issue7978c(", "", 1) + // test in go code, during callback + issue7978wait(2, 3) + issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3) + // test in c code, after callback + issue7978wait(4, 5) + issue7978check(t, "_Cfunc_issue7978c(", "_cgoexpwrap", 1) + // test in go code, after return from cgo + issue7978wait(6, 7) + issue7978check(t, "test.issue7978go(", "", 3) + atomic.StoreUint32(&issue7978sync, 8) +} diff --git a/libgo/misc/cgo/test/issue8092.go b/libgo/misc/cgo/test/issue8092.go new file mode 100644 index 00000000000..19123e79cfa --- /dev/null +++ b/libgo/misc/cgo/test/issue8092.go @@ -0,0 +1,36 @@ +// 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. + +// Issue 8092. Test that linker defined symbols (e.g., text, data) don't +// conflict with C symbols. + +package cgotest + +/* +char text[] = "text"; +char data[] = "data"; +char *ctext(void) { return text; } +char *cdata(void) { return data; } +*/ +import "C" + +import "testing" + +func test8092(t *testing.T) { + tests := []struct { + s string + a, b *C.char + }{ + {"text", &C.text[0], C.ctext()}, + {"data", &C.data[0], C.cdata()}, + } + for _, test := range tests { + if test.a != test.b { + t.Errorf("%s: pointer mismatch: %v != %v", test.s, test.a, test.b) + } + if got := C.GoString(test.a); got != test.s { + t.Errorf("%s: points at %#v, want %#v", test.s, got, test.s) + } + } +} diff --git a/libgo/misc/cgo/test/issue8148.go b/libgo/misc/cgo/test/issue8148.go new file mode 100644 index 00000000000..f704788aef8 --- /dev/null +++ b/libgo/misc/cgo/test/issue8148.go @@ -0,0 +1,31 @@ +// 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. + +// Issue 8148. A typedef of an unnamed struct didn't work when used +// with an exported Go function. No runtime test; just make sure it +// compiles. + +package cgotest + +/* +typedef struct { int i; } T; + +int issue8148Callback(T*); + +static int get() { + T t; + t.i = 42; + return issue8148Callback(&t); +} +*/ +import "C" + +//export issue8148Callback +func issue8148Callback(t *C.T) C.int { + return t.i +} + +func Issue8148() int { + return int(C.get()) +} diff --git a/libgo/misc/cgo/test/issue8331.h b/libgo/misc/cgo/test/issue8331.h new file mode 100644 index 00000000000..8065be08904 --- /dev/null +++ b/libgo/misc/cgo/test/issue8331.h @@ -0,0 +1,7 @@ +// 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. + +typedef struct { + int i; +} issue8331; diff --git a/libgo/misc/cgo/test/issue8331a.go b/libgo/misc/cgo/test/issue8331a.go new file mode 100644 index 00000000000..92e2579e7ae --- /dev/null +++ b/libgo/misc/cgo/test/issue8331a.go @@ -0,0 +1,15 @@ +// 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. + +// Issue 8331. A typedef of an unnamed struct is the same struct when +// #include'd twice. No runtime test; just make sure it compiles. + +package cgotest + +// #include "issue8331.h" +import "C" + +func issue8331a() C.issue8331 { + return issue8331Var +} diff --git a/libgo/misc/cgo/test/issue8331b.go b/libgo/misc/cgo/test/issue8331b.go new file mode 100644 index 00000000000..5324aa2a175 --- /dev/null +++ b/libgo/misc/cgo/test/issue8331b.go @@ -0,0 +1,13 @@ +// 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. + +// Issue 8331. A typedef of an unnamed struct is the same struct when +// #include'd twice. No runtime test; just make sure it compiles. + +package cgotest + +// #include "issue8331.h" +import "C" + +var issue8331Var C.issue8331 diff --git a/libgo/misc/cgo/test/issue8428.go b/libgo/misc/cgo/test/issue8428.go new file mode 100644 index 00000000000..2e5a555b582 --- /dev/null +++ b/libgo/misc/cgo/test/issue8428.go @@ -0,0 +1,55 @@ +// 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. + +// This test fails on older versions of OS X because they use older buggy +// versions of Clang that emit ambiguous DWARF info. See issue 8611. +// +build !darwin + +package cgotest + +// Issue 8428. Cgo inconsistently translated zero size arrays. + +/* +struct issue8428one { + char b; + char rest[]; +}; + +struct issue8428two { + void *p; + char b; + char rest[0]; + char pad; +}; + +struct issue8428three { + char w[1][2][3][0]; + char x[2][3][0][1]; + char y[3][0][1][2]; + char z[0][1][2][3]; +}; +*/ +import "C" + +import "unsafe" + +var _ = C.struct_issue8428one{ + b: C.char(0), + // The trailing rest field is not available in cgo. + // See issue 11925. + // rest: [0]C.char{}, +} + +var _ = C.struct_issue8428two{ + p: unsafe.Pointer(nil), + b: C.char(0), + rest: [0]C.char{}, +} + +var _ = C.struct_issue8428three{ + w: [1][2][3][0]C.char{}, + x: [2][3][0][1]C.char{}, + y: [3][0][1][2]C.char{}, + z: [0][1][2][3]C.char{}, +} diff --git a/libgo/misc/cgo/test/issue8441.go b/libgo/misc/cgo/test/issue8441.go new file mode 100644 index 00000000000..4489ca9eb67 --- /dev/null +++ b/libgo/misc/cgo/test/issue8441.go @@ -0,0 +1,27 @@ +// 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. + +// Issue 8368 and 8441. Recursive struct definitions didn't work. +// No runtime test; just make sure it compiles. + +package cgotest + +/* +typedef struct one one; +typedef struct two two; +struct one { + two *x; +}; +struct two { + one *x; +}; +*/ +import "C" + +func issue8368(one *C.struct_one, two *C.struct_two) { +} + +func issue8441(one *C.one, two *C.two) { + issue8441(two.x, one.x) +} diff --git a/libgo/misc/cgo/test/issue8517.go b/libgo/misc/cgo/test/issue8517.go new file mode 100644 index 00000000000..4e431df921d --- /dev/null +++ b/libgo/misc/cgo/test/issue8517.go @@ -0,0 +1,13 @@ +// 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. + +// +build !windows + +package cgotest + +import "testing" + +func test8517(t *testing.T) { + t.Skip("skipping windows only test") +} diff --git a/libgo/misc/cgo/test/issue8517_windows.c b/libgo/misc/cgo/test/issue8517_windows.c new file mode 100644 index 00000000000..a0b94c126f6 --- /dev/null +++ b/libgo/misc/cgo/test/issue8517_windows.c @@ -0,0 +1,24 @@ +// 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. + +#include "windows.h" + +extern void testHandleLeaksCallback(); + +DWORD WINAPI testHandleLeaksFunc(LPVOID lpThreadParameter) +{ + int i; + for(i = 0; i < 100; i++) { + testHandleLeaksCallback(); + } + return 0; +} + +void testHandleLeaks() +{ + HANDLE h; + h = CreateThread(NULL, 0, &testHandleLeaksFunc, 0, 0, NULL); + WaitForSingleObject(h, INFINITE); + CloseHandle(h); +} diff --git a/libgo/misc/cgo/test/issue8517_windows.go b/libgo/misc/cgo/test/issue8517_windows.go new file mode 100644 index 00000000000..3782631e91b --- /dev/null +++ b/libgo/misc/cgo/test/issue8517_windows.go @@ -0,0 +1,45 @@ +// 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 cgotest + +//void testHandleLeaks(); +import "C" + +import ( + "syscall" + "testing" + "unsafe" +) + +var issue8517counter int + +var ( + kernel32 = syscall.MustLoadDLL("kernel32.dll") + getProcessHandleCount = kernel32.MustFindProc("GetProcessHandleCount") +) + +func processHandleCount(t *testing.T) int { + const current_process = ^uintptr(0) + var c uint32 + r, _, err := getProcessHandleCount.Call(current_process, uintptr(unsafe.Pointer(&c))) + if r == 0 { + t.Fatal(err) + } + return int(c) +} + +func test8517(t *testing.T) { + c1 := processHandleCount(t) + C.testHandleLeaks() + c2 := processHandleCount(t) + if c1+issue8517counter <= c2 { + t.Fatalf("too many handles leaked: issue8517counter=%v c1=%v c2=%v", issue8517counter, c1, c2) + } +} + +//export testHandleLeaksCallback +func testHandleLeaksCallback() { + issue8517counter++ +} diff --git a/libgo/misc/cgo/test/issue8694.go b/libgo/misc/cgo/test/issue8694.go new file mode 100644 index 00000000000..89be7ea0907 --- /dev/null +++ b/libgo/misc/cgo/test/issue8694.go @@ -0,0 +1,40 @@ +// 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. + +// +build !android + +package cgotest + +/* +#include + +complex float complexFloatSquared(complex float a) { return a*a; } +complex double complexDoubleSquared(complex double a) { return a*a; } +*/ +import "C" + +import ( + "runtime" + "testing" +) + +func test8694(t *testing.T) { + if runtime.GOARCH == "arm" { + t.Skip("test8694 is disabled on ARM because 5l cannot handle thumb library.") + } + // Really just testing that this compiles, but check answer anyway. + x := C.complexfloat(2 + 3i) + x2 := x * x + cx2 := C.complexFloatSquared(x) + if cx2 != x2 { + t.Errorf("C.complexFloatSquared(%v) = %v, want %v", x, cx2, x2) + } + + y := C.complexdouble(2 + 3i) + y2 := y * y + cy2 := C.complexDoubleSquared(y) + if cy2 != y2 { + t.Errorf("C.complexDoubleSquared(%v) = %v, want %v", y, cy2, y2) + } +} diff --git a/libgo/misc/cgo/test/issue8756.go b/libgo/misc/cgo/test/issue8756.go new file mode 100644 index 00000000000..d8ee3b8213d --- /dev/null +++ b/libgo/misc/cgo/test/issue8756.go @@ -0,0 +1,17 @@ +package cgotest + +/* +#cgo LDFLAGS: -lm +#include +*/ +import "C" +import ( + "testing" + + "./issue8756" +) + +func test8756(t *testing.T) { + issue8756.Pow() + C.pow(1, 2) +} diff --git a/libgo/misc/cgo/test/issue8756/issue8756.go b/libgo/misc/cgo/test/issue8756/issue8756.go new file mode 100644 index 00000000000..5f6b7778ff6 --- /dev/null +++ b/libgo/misc/cgo/test/issue8756/issue8756.go @@ -0,0 +1,11 @@ +package issue8756 + +/* +#cgo LDFLAGS: -lm +#include +*/ +import "C" + +func Pow() { + C.pow(1, 2) +} diff --git a/libgo/misc/cgo/test/issue8811.c b/libgo/misc/cgo/test/issue8811.c new file mode 100644 index 00000000000..41b3c7c8ea3 --- /dev/null +++ b/libgo/misc/cgo/test/issue8811.c @@ -0,0 +1,8 @@ +// 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. + +int issue8811Initialized = 0; + +void issue8811Init() { +} diff --git a/libgo/misc/cgo/test/issue8811.go b/libgo/misc/cgo/test/issue8811.go new file mode 100644 index 00000000000..f812732cfd7 --- /dev/null +++ b/libgo/misc/cgo/test/issue8811.go @@ -0,0 +1,22 @@ +// 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 cgotest + +/* +extern int issue8811Initialized; +extern void issue8811Init(); + +void issue8811Execute() { + if(!issue8811Initialized) + issue8811Init(); +} +*/ +import "C" + +import "testing" + +func test8811(t *testing.T) { + C.issue8811Execute() +} diff --git a/libgo/misc/cgo/test/issue8828.go b/libgo/misc/cgo/test/issue8828.go new file mode 100644 index 00000000000..304797c929c --- /dev/null +++ b/libgo/misc/cgo/test/issue8828.go @@ -0,0 +1,16 @@ +// compile + +// 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. + +// Issue 8828: compiling a file with -compiler=gccgo fails if a .c file +// has the same name as compiled directory. + +package cgotest + +import "./issue8828" + +func p() { + issue8828.Bar() +} diff --git a/libgo/misc/cgo/test/issue8828/issue8828.c b/libgo/misc/cgo/test/issue8828/issue8828.c new file mode 100644 index 00000000000..27ec23a2605 --- /dev/null +++ b/libgo/misc/cgo/test/issue8828/issue8828.c @@ -0,0 +1,7 @@ +// 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. + +void foo() +{ +} diff --git a/libgo/misc/cgo/test/issue8828/trivial.go b/libgo/misc/cgo/test/issue8828/trivial.go new file mode 100644 index 00000000000..e7b9a4e573d --- /dev/null +++ b/libgo/misc/cgo/test/issue8828/trivial.go @@ -0,0 +1,8 @@ +package issue8828 + +//void foo(); +import "C" + +func Bar() { + C.foo() +} diff --git a/libgo/misc/cgo/test/issue8945.go b/libgo/misc/cgo/test/issue8945.go new file mode 100644 index 00000000000..57a5b2db44b --- /dev/null +++ b/libgo/misc/cgo/test/issue8945.go @@ -0,0 +1,16 @@ +// 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. + +// +build gccgo + +package cgotest + +//typedef void (*PFunc)(); +//PFunc success_cb; +import "C" + +//export Test +func Test() { + _ = C.success_cb +} diff --git a/libgo/misc/cgo/test/issue9026.go b/libgo/misc/cgo/test/issue9026.go new file mode 100644 index 00000000000..8848d0e8118 --- /dev/null +++ b/libgo/misc/cgo/test/issue9026.go @@ -0,0 +1,9 @@ +package cgotest + +import ( + "testing" + + "./issue9026" +) + +func test9026(t *testing.T) { issue9026.Test(t) } diff --git a/libgo/misc/cgo/test/issue9026/issue9026.go b/libgo/misc/cgo/test/issue9026/issue9026.go new file mode 100644 index 00000000000..0af86e64da4 --- /dev/null +++ b/libgo/misc/cgo/test/issue9026/issue9026.go @@ -0,0 +1,36 @@ +package issue9026 + +// This file appears in its own package since the assertion tests the +// per-package counter used to create fresh identifiers. + +/* +typedef struct {} git_merge_file_input; + +typedef struct {} git_merge_file_options; + +void git_merge_file( + git_merge_file_input *in, + git_merge_file_options *opts) {} +*/ +import "C" +import ( + "fmt" + "testing" +) + +func Test(t *testing.T) { + var in C.git_merge_file_input + var opts *C.git_merge_file_options + C.git_merge_file(&in, opts) + + // Test that the generated type names are deterministic. + // (Previously this would fail about 10% of the time.) + // + // Brittle: the assertion may fail spuriously when the algorithm + // changes, but should remain stable otherwise. + got := fmt.Sprintf("%T %T", in, opts) + want := "issue9026._Ctype_struct___0 *issue9026._Ctype_struct___1" + if got != want { + t.Errorf("Non-deterministic type names: got %s, want %s", got, want) + } +} diff --git a/libgo/misc/cgo/test/issue9400/asm_386.s b/libgo/misc/cgo/test/issue9400/asm_386.s new file mode 100644 index 00000000000..7f158b5c39d --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_386.s @@ -0,0 +1,27 @@ +// 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. + +// +build !gccgo + +#include "textflag.h" + +TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0 + MOVL $·Baton(SB), BX + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADDL $(1024 * 8), SP + + // Ask signaller to setgid + MOVL $1, (BX) + + // Wait for setgid completion +loop: + PAUSE + MOVL (BX), AX + CMPL AX, $0 + JNE loop + + // Restore stack + SUBL $(1024 * 8), SP + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_amd64x.s b/libgo/misc/cgo/test/issue9400/asm_amd64x.s new file mode 100644 index 00000000000..48b86190a59 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_amd64x.s @@ -0,0 +1,27 @@ +// 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. + +// +build amd64 amd64p32 +// +build !gccgo + +#include "textflag.h" + +TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0 + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADDQ $(1024 * 8), SP + + // Ask signaller to setgid + MOVL $1, ·Baton(SB) + + // Wait for setgid completion +loop: + PAUSE + MOVL ·Baton(SB), AX + CMPL AX, $0 + JNE loop + + // Restore stack + SUBQ $(1024 * 8), SP + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_arm.s b/libgo/misc/cgo/test/issue9400/asm_arm.s new file mode 100644 index 00000000000..166d53f304e --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_arm.s @@ -0,0 +1,39 @@ +// 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. + +// +build !gccgo + +#include "textflag.h" + +TEXT cas<>(SB),NOSPLIT,$0 + MOVW $0xffff0fc0, R15 // R15 is PC + +TEXT ·RewindAndSetgid(SB),NOSPLIT,$-4-0 + // Save link register + MOVW R14, R4 + + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADD $(1024 * 8), R13 + + // Ask signaller to setgid + MOVW $·Baton(SB), R2 +storeloop: + MOVW 0(R2), R0 + MOVW $1, R1 + BL cas<>(SB) + BCC storeloop + + // Wait for setgid completion +loop: + MOVW $0, R0 + MOVW $0, R1 + BL cas<>(SB) + BCC loop + + // Restore stack + SUB $(1024 * 8), R13 + + MOVW R4, R14 + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_arm64.s b/libgo/misc/cgo/test/issue9400/asm_arm64.s new file mode 100644 index 00000000000..9bb50816b44 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_arm64.s @@ -0,0 +1,39 @@ +// 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. + +// +build !gccgo + +#include "textflag.h" + +TEXT ·RewindAndSetgid(SB),NOSPLIT,$-8-0 + // Save link register + MOVD R30, R9 + + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADD $(1024 * 8), RSP + + // Ask signaller to setgid + MOVD $·Baton(SB), R0 + MOVD $1, R1 +storeloop: + LDAXRW (R0), R2 + STLXRW R1, (R0), R3 + CBNZ R3, storeloop + + // Wait for setgid completion + MOVW $0, R1 + MOVW $0, R2 +loop: + LDAXRW (R0), R3 + CMPW R1, R3 + BNE loop + STLXRW R2, (R0), R3 + CBNZ R3, loop + + // Restore stack + SUB $(1024 * 8), RSP + + MOVD R9, R30 + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_mips64x.s b/libgo/misc/cgo/test/issue9400/asm_mips64x.s new file mode 100644 index 00000000000..63dc90605e6 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_mips64x.s @@ -0,0 +1,33 @@ +// 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. + +// +build mips64 mips64le +// +build !gccgo + +#include "textflag.h" + +#define SYNC WORD $0xf + +TEXT ·RewindAndSetgid(SB),NOSPLIT|NOFRAME,$0-0 + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADDV $(1024*8), R29 + + // Ask signaller to setgid + MOVW $1, R1 + SYNC + MOVW R1, ·Baton(SB) + SYNC + + // Wait for setgid completion +loop: + SYNC + MOVW ·Baton(SB), R1 + OR R2, R2, R2 // hint that we're in a spin loop + BNE R1, loop + SYNC + + // Restore stack + ADDV $(-1024*8), R29 + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_mipsx.s b/libgo/misc/cgo/test/issue9400/asm_mipsx.s new file mode 100644 index 00000000000..ddf33e9f8e5 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_mipsx.s @@ -0,0 +1,31 @@ +// 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. + +// +build mips mipsle +// +build !gccgo + +#include "textflag.h" + +TEXT ·RewindAndSetgid(SB),NOSPLIT,$-4-0 + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADDU $(1024*8), R29 + + // Ask signaller to setgid + MOVW $1, R1 + SYNC + MOVW R1, ·Baton(SB) + SYNC + + // Wait for setgid completion +loop: + SYNC + MOVW ·Baton(SB), R1 + OR R2, R2, R2 // hint that we're in a spin loop + BNE R1, loop + SYNC + + // Restore stack + ADDU $(-1024*8), R29 + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_ppc64x.s b/libgo/misc/cgo/test/issue9400/asm_ppc64x.s new file mode 100644 index 00000000000..c88ec3b21e7 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_ppc64x.s @@ -0,0 +1,32 @@ +// 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. + +// +build ppc64 ppc64le +// +build !gccgo + +#include "textflag.h" + +TEXT ·RewindAndSetgid(SB),NOSPLIT|NOFRAME,$0-0 + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADD $(1024 * 8), R1 + + // Ask signaller to setgid + MOVW $1, R3 + SYNC + MOVW R3, ·Baton(SB) + + // Wait for setgid completion +loop: + SYNC + MOVW ·Baton(SB), R3 + CMP R3, $0 + // Hint that we're in a spin loop + OR R1, R1, R1 + BNE loop + ISYNC + + // Restore stack + SUB $(1024 * 8), R1 + RET diff --git a/libgo/misc/cgo/test/issue9400/asm_s390x.s b/libgo/misc/cgo/test/issue9400/asm_s390x.s new file mode 100644 index 00000000000..fc9ad724c15 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/asm_s390x.s @@ -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. + +// +build !gccgo + +#include "textflag.h" + +TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0 + // Rewind stack pointer so anything that happens on the stack + // will clobber the test pattern created by the caller + ADD $(1024 * 8), R15 + + // Ask signaller to setgid + MOVD $·Baton(SB), R5 + MOVW $1, 0(R5) + + // Wait for setgid completion +loop: + SYNC + MOVW ·Baton(SB), R3 + CMPBNE R3, $0, loop + + // Restore stack + SUB $(1024 * 8), R15 + RET diff --git a/libgo/misc/cgo/test/issue9400/gccgo.go b/libgo/misc/cgo/test/issue9400/gccgo.go new file mode 100644 index 00000000000..0ef3a8cacf3 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/gccgo.go @@ -0,0 +1,24 @@ +// 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. + +// +build gccgo + +package issue9400 + +import ( + "runtime" + "sync/atomic" +) + +// The test for the gc compiler resets the stack pointer so that the +// stack gets modified. We don't have a way to do that for gccgo +// without writing more assembly code, which we haven't bothered to +// do. So this is not much of a test. + +func RewindAndSetgid() { + atomic.StoreInt32(&Baton, 1) + for atomic.LoadInt32(&Baton) != 0 { + runtime.Gosched() + } +} diff --git a/libgo/misc/cgo/test/issue9400/stubs.go b/libgo/misc/cgo/test/issue9400/stubs.go new file mode 100644 index 00000000000..60193dc4117 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400/stubs.go @@ -0,0 +1,9 @@ +// 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 issue9400 + +var Baton int32 + +func RewindAndSetgid() diff --git a/libgo/misc/cgo/test/issue9400_linux.go b/libgo/misc/cgo/test/issue9400_linux.go new file mode 100644 index 00000000000..34eb4983a41 --- /dev/null +++ b/libgo/misc/cgo/test/issue9400_linux.go @@ -0,0 +1,58 @@ +// 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. + +// Test that SIGSETXID runs on signal stack, since it's likely to +// overflow if it runs on the Go stack. + +package cgotest + +/* +#include +#include +*/ +import "C" + +import ( + "runtime" + "sync/atomic" + "testing" + + "./issue9400" +) + +func test9400(t *testing.T) { + // We synchronize through a shared variable, so we need two procs + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2)) + + // Start signaller + atomic.StoreInt32(&issue9400.Baton, 0) + go func() { + // Wait for RewindAndSetgid + for atomic.LoadInt32(&issue9400.Baton) == 0 { + runtime.Gosched() + } + // Broadcast SIGSETXID + runtime.LockOSThread() + C.setgid(0) + // Indicate that signalling is done + atomic.StoreInt32(&issue9400.Baton, 0) + }() + + // Grow the stack and put down a test pattern + const pattern = 0x123456789abcdef + var big [1024]uint64 // len must match assmebly + for i := range big { + big[i] = pattern + } + + // Temporarily rewind the stack and trigger SIGSETXID + issue9400.RewindAndSetgid() + + // Check test pattern + for i := range big { + if big[i] != pattern { + t.Fatalf("entry %d of test pattern is wrong; %#x != %#x", i, big[i], uint64(pattern)) + } + } +} diff --git a/libgo/misc/cgo/test/issue9510.go b/libgo/misc/cgo/test/issue9510.go new file mode 100644 index 00000000000..efd3f770b6a --- /dev/null +++ b/libgo/misc/cgo/test/issue9510.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. + +// Test that we can link together two different cgo packages that both +// use the same libgcc function. + +package cgotest + +import ( + "runtime" + "testing" + + "./issue9510a" + "./issue9510b" +) + +func test9510(t *testing.T) { + if runtime.GOARCH == "arm" { + t.Skip("skipping because libgcc may be a Thumb library") + } + issue9510a.F(1, 1) + issue9510b.F(1, 1) +} diff --git a/libgo/misc/cgo/test/issue9510a/a.go b/libgo/misc/cgo/test/issue9510a/a.go new file mode 100644 index 00000000000..1a5224b8c68 --- /dev/null +++ b/libgo/misc/cgo/test/issue9510a/a.go @@ -0,0 +1,15 @@ +package issue9510a + +/* +static double csquare(double a, double b) { + __complex__ double d; + __real__ d = a; + __imag__ d = b; + return __real__ (d * d); +} +*/ +import "C" + +func F(a, b float64) float64 { + return float64(C.csquare(C.double(a), C.double(b))) +} diff --git a/libgo/misc/cgo/test/issue9510b/b.go b/libgo/misc/cgo/test/issue9510b/b.go new file mode 100644 index 00000000000..5016b39597e --- /dev/null +++ b/libgo/misc/cgo/test/issue9510b/b.go @@ -0,0 +1,15 @@ +package issue9510b + +/* +static double csquare(double a, double b) { + __complex__ double d; + __real__ d = a; + __imag__ d = b; + return __real__ (d * d); +} +*/ +import "C" + +func F(a, b float64) float64 { + return float64(C.csquare(C.double(a), C.double(b))) +} diff --git a/libgo/misc/cgo/test/issue9557.go b/libgo/misc/cgo/test/issue9557.go new file mode 100644 index 00000000000..4e8922a69c6 --- /dev/null +++ b/libgo/misc/cgo/test/issue9557.go @@ -0,0 +1,36 @@ +// 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. + +// cgo rewrote C.var to *_Cvar_var, but left +// C.var.field as _Cvar.var.field. It now rewrites +// the latter as (*_Cvar_var).field. +// See https://golang.org/issue/9557. + +package cgotest + +// struct issue9557_t { +// int a; +// } test9557bar = { 42 }; +// +// struct issue9557_t *issue9557foo = &test9557bar; +import "C" +import "testing" + +func test9557(t *testing.T) { + // implicitly dereference a Go variable + foo := C.issue9557foo + if v := foo.a; v != 42 { + t.Fatalf("foo.a expected 42, but got %d", v) + } + + // explicitly dereference a C variable + if v := (*C.issue9557foo).a; v != 42 { + t.Fatalf("(*C.issue9557foo).a expected 42, but is %d", v) + } + + // implicitly dereference a C variable + if v := C.issue9557foo.a; v != 42 { + t.Fatalf("C.issue9557foo.a expected 42, but is %d", v) + } +} diff --git a/libgo/misc/cgo/test/setgid_linux.go b/libgo/misc/cgo/test/setgid_linux.go new file mode 100644 index 00000000000..6773f94d3d6 --- /dev/null +++ b/libgo/misc/cgo/test/setgid_linux.go @@ -0,0 +1,49 @@ +// Copyright 2012 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 setgid does not hang on GNU/Linux. +// See https://golang.org/issue/3871 for details. + +package cgotest + +/* +#include +#include +*/ +import "C" + +import ( + "os" + "os/signal" + "syscall" + "testing" + "time" +) + +func runTestSetgid() bool { + c := make(chan bool) + go func() { + C.setgid(0) + c <- true + }() + select { + case <-c: + return true + case <-time.After(5 * time.Second): + return false + } + +} + +func testSetgid(t *testing.T) { + if !runTestSetgid() { + t.Error("setgid hung") + } + + // Now try it again after using signal.Notify. + signal.Notify(make(chan os.Signal, 1), syscall.SIGINT) + if !runTestSetgid() { + t.Error("setgid hung after signal.Notify") + } +} diff --git a/libgo/misc/cgo/test/sigaltstack.go b/libgo/misc/cgo/test/sigaltstack.go new file mode 100644 index 00000000000..2b7a1ec9ad0 --- /dev/null +++ b/libgo/misc/cgo/test/sigaltstack.go @@ -0,0 +1,73 @@ +// 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. + +// +build !windows,!android + +// Test that the Go runtime still works if C code changes the signal stack. + +package cgotest + +/* +#include +#include +#include +#include + +static stack_t oss; +static char signalStack[SIGSTKSZ]; + +static void changeSignalStack(void) { + stack_t ss; + memset(&ss, 0, sizeof ss); + ss.ss_sp = signalStack; + ss.ss_flags = 0; + ss.ss_size = SIGSTKSZ; + if (sigaltstack(&ss, &oss) < 0) { + perror("sigaltstack"); + abort(); + } +} + +static void restoreSignalStack(void) { +#if (defined(__x86_64__) || defined(__i386__)) && defined(__APPLE__) + // The Darwin C library enforces a minimum that the kernel does not. + // This is OK since we allocated this much space in mpreinit, + // it was just removed from the buffer by stackalloc. + oss.ss_size = MINSIGSTKSZ; +#endif + if (sigaltstack(&oss, NULL) < 0) { + perror("sigaltstack restore"); + abort(); + } +} + +static int zero(void) { + return 0; +} +*/ +import "C" + +import ( + "runtime" + "testing" +) + +func testSigaltstack(t *testing.T) { + switch { + case runtime.GOOS == "solaris", runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64"): + t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) + case runtime.GOOS == "darwin" && runtime.GOARCH == "386": + t.Skipf("sigaltstack fails on darwin/386") + } + + C.changeSignalStack() + defer C.restoreSignalStack() + defer func() { + if recover() == nil { + t.Error("did not see expected panic") + } + }() + v := 1 / int(C.zero()) + t.Errorf("unexpected success of division by zero == %d", v) +} diff --git a/libgo/misc/cgo/test/sigprocmask.c b/libgo/misc/cgo/test/sigprocmask.c new file mode 100644 index 00000000000..bd99647d2b3 --- /dev/null +++ b/libgo/misc/cgo/test/sigprocmask.c @@ -0,0 +1,38 @@ +// 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. + +// +build !windows + +#include +#include +#include +#include +#include + +extern void IntoGoAndBack(); + +int CheckBlocked() { + sigset_t mask; + sigprocmask(SIG_BLOCK, NULL, &mask); + return sigismember(&mask, SIGIO); +} + +static void* sigthreadfunc(void* unused) { + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGIO); + sigprocmask(SIG_BLOCK, &mask, NULL); + IntoGoAndBack(); + return NULL; +} + +int RunSigThread() { + pthread_t thread; + int r; + + r = pthread_create(&thread, NULL, &sigthreadfunc, NULL); + if (r != 0) + return r; + return pthread_join(thread, NULL); +} diff --git a/libgo/misc/cgo/test/sigprocmask.go b/libgo/misc/cgo/test/sigprocmask.go new file mode 100644 index 00000000000..39b658e96c3 --- /dev/null +++ b/libgo/misc/cgo/test/sigprocmask.go @@ -0,0 +1,40 @@ +// 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. + +// +build !windows + +package cgotest + +/* +#cgo CFLAGS: -pthread +#cgo LDFLAGS: -pthread +extern int RunSigThread(); +extern int CheckBlocked(); +*/ +import "C" +import ( + "os" + "os/signal" + "syscall" + "testing" +) + +var blocked bool + +//export IntoGoAndBack +func IntoGoAndBack() { + // Verify that SIGIO stays blocked on the C thread + // even when unblocked for signal.Notify(). + signal.Notify(make(chan os.Signal), syscall.SIGIO) + blocked = C.CheckBlocked() != 0 +} + +func testSigprocmask(t *testing.T) { + if r := C.RunSigThread(); r != 0 { + t.Error("pthread_create/pthread_join failed") + } + if !blocked { + t.Error("Go runtime unblocked SIGIO") + } +} diff --git a/libgo/misc/cgo/testasan/main.go b/libgo/misc/cgo/testasan/main.go new file mode 100644 index 00000000000..1837c6cc81d --- /dev/null +++ b/libgo/misc/cgo/testasan/main.go @@ -0,0 +1,49 @@ +// 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 + +/* +#include +#include +#include + +void ctor(void) __attribute__((constructor)); +static void* thread(void*); + +void +ctor(void) +{ + // occupy memory where Go runtime would normally map heap + mmap((void*)0x00c000000000, 64<<10, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); + + // allocate 4K every 10us + pthread_t t; + pthread_create(&t, 0, thread, 0); +} + +static void* +thread(void *p) +{ + for(;;) { + usleep(10000); + mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + } + return 0; +} +*/ +import "C" + +import ( + "time" +) + +func main() { + // ensure that we can function normally + var v [][]byte + for i := 0; i < 1000; i++ { + time.Sleep(10 * time.Microsecond) + v = append(v, make([]byte, 64<<10)) + } +} diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go new file mode 100644 index 00000000000..49999297751 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/carchive_test.go @@ -0,0 +1,540 @@ +// 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 carchive_test + +import ( + "bufio" + "debug/elf" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "syscall" + "testing" + "time" + "unicode" +) + +// Program to run. +var bin []string + +// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)). +var cc []string + +// An environment with GOPATH=$(pwd). +var gopathEnv []string + +// ".exe" on Windows. +var exeSuffix string + +var GOOS, GOARCH string +var libgodir string + +func init() { + GOOS = goEnv("GOOS") + GOARCH = goEnv("GOARCH") + bin = cmdToRun("./testp") + + ccOut := goEnv("CC") + cc = []string{string(ccOut)} + + out := goEnv("GOGCCFLAGS") + quote := '\000' + start := 0 + lastSpace := true + backslash := false + s := string(out) + for i, c := range s { + if quote == '\000' && unicode.IsSpace(c) { + if !lastSpace { + cc = append(cc, s[start:i]) + lastSpace = true + } + } else { + if lastSpace { + start = i + lastSpace = false + } + if quote == '\000' && !backslash && (c == '"' || c == '\'') { + quote = c + backslash = false + } else if !backslash && quote == c { + quote = '\000' + } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' { + backslash = true + } else { + backslash = false + } + } + } + if !lastSpace { + cc = append(cc, s[start:]) + } + + if GOOS == "darwin" { + // For Darwin/ARM. + // TODO(crawshaw): can we do better? + cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) + } + libgodir = GOOS + "_" + GOARCH + switch GOOS { + case "darwin": + if GOARCH == "arm" || GOARCH == "arm64" { + libgodir += "_shared" + } + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + libgodir += "_shared" + } + cc = append(cc, "-I", filepath.Join("pkg", libgodir)) + + // Build an environment with GOPATH=$(pwd) + env := os.Environ() + var n []string + for _, e := range env { + if !strings.HasPrefix(e, "GOPATH=") { + n = append(n, e) + } + } + dir, err := os.Getwd() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + n = append(n, "GOPATH="+dir) + gopathEnv = n + + if GOOS == "windows" { + exeSuffix = ".exe" + } +} + +func goEnv(key string) string { + out, err := exec.Command("go", "env", key).Output() + if err != nil { + fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err) + fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr) + os.Exit(2) + } + return strings.TrimSpace(string(out)) +} + +func cmdToRun(name string) []string { + execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec" + executor, err := exec.LookPath(execScript) + if err != nil { + return []string{name} + } + return []string{executor, name} +} + +func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) { + cmd := exec.Command(buildcmd[0], buildcmd[1:]...) + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + defer func() { + os.Remove(libgoa) + os.Remove(libgoh) + }() + + ccArgs := append(cc, "-o", exe, "main.c") + if GOOS == "windows" { + ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm") + } else { + ccArgs = append(ccArgs, "main_unix.c", libgoa) + } + t.Log(ccArgs) + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + defer os.Remove(exe) + + binArgs := append(cmdToRun(exe), "arg1", "arg2") + if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } +} + +func TestInstall(t *testing.T) { + defer os.RemoveAll("pkg") + + testInstall(t, "./testp1"+exeSuffix, + filepath.Join("pkg", libgodir, "libgo.a"), + filepath.Join("pkg", libgodir, "libgo.h"), + "go", "install", "-buildmode=c-archive", "libgo") + + // Test building libgo other than installing it. + // Header files are now present. + testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h", + "go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go")) + + testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h", + "go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo") +} + +func TestEarlySignalHandler(t *testing.T) { + switch GOOS { + case "darwin": + switch GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH) + } + case "windows": + t.Skip("skipping signal test on Windows") + } + + defer func() { + os.Remove("libgo2.a") + os.Remove("libgo2.h") + os.Remove("testp") + os.RemoveAll("pkg") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a") + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } +} + +func TestSignalForwarding(t *testing.T) { + switch GOOS { + case "darwin": + switch GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH) + } + case "windows": + t.Skip("skipping signal test on Windows") + } + + defer func() { + os.Remove("libgo2.a") + os.Remove("libgo2.h") + os.Remove("testp") + os.RemoveAll("pkg") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a") + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + cmd = exec.Command(bin[0], append(bin[1:], "1")...) + + out, err := cmd.CombinedOutput() + + if err == nil { + t.Logf("%s", out) + t.Error("test program succeeded unexpectedly") + } else if ee, ok := err.(*exec.ExitError); !ok { + t.Logf("%s", out) + t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err) + } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { + t.Logf("%s", out) + t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys()) + } else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV { + t.Logf("%s", out) + t.Errorf("got %v; expected SIGSEGV", ee) + } +} + +func TestSignalForwardingExternal(t *testing.T) { + switch GOOS { + case "darwin": + switch GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH) + } + case "windows": + t.Skip("skipping signal test on Windows") + } + + defer func() { + os.Remove("libgo2.a") + os.Remove("libgo2.h") + os.Remove("testp") + os.RemoveAll("pkg") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a") + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + // We want to send the process a signal and see if it dies. + // Normally the signal goes to the C thread, the Go signal + // handler picks it up, sees that it is running in a C thread, + // and the program dies. Unfortunately, occasionally the + // signal is delivered to a Go thread, which winds up + // discarding it because it was sent by another program and + // there is no Go handler for it. To avoid this, run the + // program several times in the hopes that it will eventually + // fail. + const tries = 20 + for i := 0; i < tries; i++ { + cmd = exec.Command(bin[0], append(bin[1:], "2")...) + + stderr, err := cmd.StderrPipe() + if err != nil { + t.Fatal(err) + } + defer stderr.Close() + + r := bufio.NewReader(stderr) + + err = cmd.Start() + + if err != nil { + t.Fatal(err) + } + + // Wait for trigger to ensure that the process is started. + ok, err := r.ReadString('\n') + + // Verify trigger. + if err != nil || ok != "OK\n" { + t.Fatalf("Did not receive OK signal") + } + + // Give the program a chance to enter the sleep function. + time.Sleep(time.Millisecond) + + cmd.Process.Signal(syscall.SIGSEGV) + + err = cmd.Wait() + + if err == nil { + continue + } + + if ee, ok := err.(*exec.ExitError); !ok { + t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err) + } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { + t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys()) + } else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV { + t.Errorf("got %v; expected SIGSEGV", ee) + } else { + // We got the error we expected. + return + } + } + + t.Errorf("program succeeded unexpectedly %d times", tries) +} + +func TestOsSignal(t *testing.T) { + switch GOOS { + case "windows": + t.Skip("skipping signal test on Windows") + } + + defer func() { + os.Remove("libgo3.a") + os.Remove("libgo3.h") + os.Remove("testp") + os.RemoveAll("pkg") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a") + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } +} + +func TestSigaltstack(t *testing.T) { + switch GOOS { + case "windows": + t.Skip("skipping signal test on Windows") + } + + defer func() { + os.Remove("libgo4.a") + os.Remove("libgo4.h") + os.Remove("testp") + os.RemoveAll("pkg") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a") + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } +} + +const testar = `#!/usr/bin/env bash +while expr $1 : '[-]' >/dev/null; do + shift +done +echo "testar" > $1 +echo "testar" > PWD/testar.ran +` + +func TestExtar(t *testing.T) { + switch GOOS { + case "windows": + t.Skip("skipping signal test on Windows") + } + + defer func() { + os.Remove("libgo4.a") + os.Remove("libgo4.h") + os.Remove("testar") + os.Remove("testar.ran") + os.RemoveAll("pkg") + }() + + os.Remove("testar") + dir, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + s := strings.Replace(testar, "PWD", dir, 1) + if err := ioutil.WriteFile("testar", []byte(s), 0777); err != nil { + t.Fatal(err) + } + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "libgo4") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + if _, err := os.Stat("testar.ran"); err != nil { + if os.IsNotExist(err) { + t.Error("testar does not exist after go build") + } else { + t.Errorf("error checking testar: %v", err) + } + } +} + +func TestPIE(t *testing.T) { + switch GOOS { + case "windows", "darwin", "plan9": + t.Skipf("skipping PIE test on %s", GOOS) + } + + defer func() { + os.Remove("testp" + exeSuffix) + os.RemoveAll("pkg") + }() + + cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, "libgo.a")) + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + binArgs := append(bin, "arg1", "arg2") + if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + f, err := elf.Open("testp" + exeSuffix) + if err != nil { + t.Fatal("elf.Open failed: ", err) + } + defer f.Close() + if hasDynTag(t, f, elf.DT_TEXTREL) { + t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix) + } +} + +func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool { + ds := f.SectionByType(elf.SHT_DYNAMIC) + if ds == nil { + t.Error("no SHT_DYNAMIC section") + return false + } + d, err := ds.Data() + if err != nil { + t.Errorf("can't read SHT_DYNAMIC contents: %v", err) + return false + } + for len(d) > 0 { + var t elf.DynTag + switch f.Class { + case elf.ELFCLASS32: + t = elf.DynTag(f.ByteOrder.Uint32(d[:4])) + d = d[8:] + case elf.ELFCLASS64: + t = elf.DynTag(f.ByteOrder.Uint64(d[:8])) + d = d[16:] + } + if t == tag { + return true + } + } + return false +} diff --git a/libgo/misc/cgo/testcarchive/main.c b/libgo/misc/cgo/testcarchive/main.c new file mode 100644 index 00000000000..163b5398e5e --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main.c @@ -0,0 +1,48 @@ +// 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. + +#include +#include +#include + +#include "p.h" +#include "libgo.h" + +extern int install_handler(); +extern int check_handler(); + +int main(void) { + int32_t res; + + int r1 = install_handler(); + if (r1!=0) { + return r1; + } + + if (!DidInitRun()) { + fprintf(stderr, "ERROR: buildmode=c-archive init should run\n"); + return 2; + } + + if (DidMainRun()) { + fprintf(stderr, "ERROR: buildmode=c-archive should not run main\n"); + return 2; + } + + int r2 = check_handler(); + if (r2!=0) { + return r2; + } + + res = FromPkg(); + if (res != 1024) { + fprintf(stderr, "ERROR: FromPkg()=%d, want 1024\n", res); + return 2; + } + + CheckArgs(); + + fprintf(stderr, "PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/main2.c b/libgo/misc/cgo/testcarchive/main2.c new file mode 100644 index 00000000000..774e014a162 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main2.c @@ -0,0 +1,199 @@ +// 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. + +// Test installing a signal handler before the Go code starts. +// This is a lot like misc/cgo/testcshared/main4.c. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libgo2.h" + +static void die(const char* msg) { + perror(msg); + exit(EXIT_FAILURE); +} + +static volatile sig_atomic_t sigioSeen; + +// Use up some stack space. +static void recur(int i, char *p) { + char a[1024]; + + *p = '\0'; + if (i > 0) { + recur(i - 1, a); + } +} + +// Signal handler that uses up more stack space than a goroutine will have. +static void ioHandler(int signo, siginfo_t* info, void* ctxt) { + char a[1024]; + + recur(4, a); + sigioSeen = 1; +} + +static jmp_buf jmp; +static char* nullPointer; + +// An arbitrary function which requires proper stack alignment; see +// http://golang.org/issue/17641. +static void callWithVarargs(void* dummy, ...) { + va_list args; + va_start(args, dummy); + va_end(args); +} + +// Signal handler for SIGSEGV on a C thread. +static void segvHandler(int signo, siginfo_t* info, void* ctxt) { + sigset_t mask; + int i; + + // Call an arbitrary function that requires the stack to be properly aligned. + callWithVarargs("dummy arg", 3.1415); + + if (sigemptyset(&mask) < 0) { + die("sigemptyset"); + } + if (sigaddset(&mask, SIGSEGV) < 0) { + die("sigaddset"); + } + i = sigprocmask(SIG_UNBLOCK, &mask, NULL); + if (i != 0) { + fprintf(stderr, "sigprocmask: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + // Don't try this at home. + longjmp(jmp, signo); + + // We should never get here. + abort(); +} + +// Set up the signal handlers in a high priority constructor, +// so that they are installed before the Go code starts. + +static void init(void) __attribute__ ((constructor (200))); + +static void init() { + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = ioHandler; + if (sigemptyset(&sa.sa_mask) < 0) { + die("sigemptyset"); + } + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGIO, &sa, NULL) < 0) { + die("sigaction"); + } + + sa.sa_sigaction = segvHandler; + if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) { + die("sigaction"); + } + +} + +int main(int argc, char** argv) { + int verbose; + sigset_t mask; + int i; + struct timespec ts; + + verbose = argc > 1; + setvbuf(stdout, NULL, _IONBF, 0); + + // Call setsid so that we can use kill(0, SIGIO) below. + // Don't check the return value so that this works both from + // a job control shell and from a shell script. + setsid(); + + if (verbose) { + printf("calling RunGoroutines\n"); + } + + RunGoroutines(); + + // Block SIGIO in this thread to make it more likely that it + // will be delivered to a goroutine. + + if (verbose) { + printf("calling pthread_sigmask\n"); + } + + if (sigemptyset(&mask) < 0) { + die("sigemptyset"); + } + if (sigaddset(&mask, SIGIO) < 0) { + die("sigaddset"); + } + i = pthread_sigmask(SIG_BLOCK, &mask, NULL); + if (i != 0) { + fprintf(stderr, "pthread_sigmask: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling kill\n"); + } + + if (kill(0, SIGIO) < 0) { + die("kill"); + } + + if (verbose) { + printf("waiting for sigioSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + if (verbose) { + printf("calling setjmp\n"); + } + + // Test that a SIGSEGV on this thread is delivered to us. + if (setjmp(jmp) == 0) { + if (verbose) { + printf("triggering SIGSEGV\n"); + } + + *nullPointer = '\0'; + + fprintf(stderr, "continued after address error\n"); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling TestSEGV\n"); + } + + TestSEGV(); + + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/main3.c b/libgo/misc/cgo/testcarchive/main3.c new file mode 100644 index 00000000000..0a6c0d3f74e --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main3.c @@ -0,0 +1,155 @@ +// 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. + +// Test os/signal.Notify and os/signal.Reset. +// This is a lot like misc/cgo/testcshared/main5.c. + +#include +#include +#include +#include +#include +#include + +#include "libgo3.h" + +static void die(const char* msg) { + perror(msg); + exit(EXIT_FAILURE); +} + +static volatile sig_atomic_t sigioSeen; + +static void ioHandler(int signo, siginfo_t* info, void* ctxt) { + sigioSeen = 1; +} + +int main(int argc, char** argv) { + int verbose; + struct sigaction sa; + int i; + struct timespec ts; + + verbose = argc > 2; + setvbuf(stdout, NULL, _IONBF, 0); + + if (verbose) { + printf("calling sigaction\n"); + } + + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = ioHandler; + if (sigemptyset(&sa.sa_mask) < 0) { + die("sigemptyset"); + } + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGIO, &sa, NULL) < 0) { + die("sigaction"); + } + + // At this point there should not be a Go signal handler + // installed for SIGIO. + + if (verbose) { + printf("raising SIGIO\n"); + } + + if (raise(SIGIO) < 0) { + die("raise"); + } + + if (verbose) { + printf("waiting for sigioSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + sigioSeen = 0; + + // Tell the Go code to catch SIGIO. + + if (verbose) { + printf("calling CatchSIGIO\n"); + } + + CatchSIGIO(); + + if (verbose) { + printf("raising SIGIO\n"); + } + + if (raise(SIGIO) < 0) { + die("raise"); + } + + if (verbose) { + printf("calling SawSIGIO\n"); + } + + if (!SawSIGIO()) { + fprintf(stderr, "Go handler did not see SIGIO\n"); + exit(EXIT_FAILURE); + } + + if (sigioSeen != 0) { + fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n"); + exit(EXIT_FAILURE); + } + + // Tell the Go code to stop catching SIGIO. + + if (verbose) { + printf("calling ResetSIGIO\n"); + } + + ResetSIGIO(); + + if (verbose) { + printf("raising SIGIO\n"); + } + + if (raise(SIGIO) < 0) { + die("raise"); + } + + if (verbose) { + printf("calling SawSIGIO\n"); + } + + if (SawSIGIO()) { + fprintf(stderr, "Go handler saw SIGIO after Reset\n"); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("waiting for sigioSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/main4.c b/libgo/misc/cgo/testcarchive/main4.c new file mode 100644 index 00000000000..4fd55e753d5 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main4.c @@ -0,0 +1,197 @@ +// 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. + +// Test a C thread that calls sigaltstack and then calls Go code. + +#include +#include +#include +#include +#include +#include +#include + +#include "libgo4.h" + +static void die(const char* msg) { + perror(msg); + exit(EXIT_FAILURE); +} + +static int ok = 1; + +static void ioHandler(int signo, siginfo_t* info, void* ctxt) { +} + +// Set up the SIGIO signal handler in a high priority constructor, so +// that it is installed before the Go code starts. + +static void init(void) __attribute__ ((constructor (200))); + +static void init() { + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = ioHandler; + if (sigemptyset(&sa.sa_mask) < 0) { + die("sigemptyset"); + } + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + if (sigaction(SIGIO, &sa, NULL) < 0) { + die("sigaction"); + } +} + +// Test raising SIGIO on a C thread with an alternate signal stack +// when there is a Go signal handler for SIGIO. +static void* thread1(void* arg __attribute__ ((unused))) { + stack_t ss; + int i; + stack_t nss; + struct timespec ts; + + // Set up an alternate signal stack for this thread. + memset(&ss, 0, sizeof ss); + ss.ss_sp = malloc(SIGSTKSZ); + if (ss.ss_sp == NULL) { + die("malloc"); + } + ss.ss_flags = 0; + ss.ss_size = SIGSTKSZ; + if (sigaltstack(&ss, NULL) < 0) { + die("sigaltstack"); + } + + // Send ourselves a SIGIO. This will be caught by the Go + // signal handler which should forward to the C signal + // handler. + i = pthread_kill(pthread_self(), SIGIO); + if (i != 0) { + fprintf(stderr, "pthread_kill: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + // Wait until the signal has been delivered. + i = 0; + while (SIGIOCount() == 0) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + // We should still be on the same signal stack. + if (sigaltstack(NULL, &nss) < 0) { + die("sigaltstack check"); + } + if ((nss.ss_flags & SS_DISABLE) != 0) { + fprintf(stderr, "sigaltstack disabled on return from Go\n"); + ok = 0; + } else if (nss.ss_sp != ss.ss_sp) { + fprintf(stderr, "sigalstack changed on return from Go\n"); + ok = 0; + } + + return NULL; +} + +// Test calling a Go function to raise SIGIO on a C thread with an +// alternate signal stack when there is a Go signal handler for SIGIO. +static void* thread2(void* arg __attribute__ ((unused))) { + stack_t ss; + int i; + int oldcount; + pthread_t tid; + struct timespec ts; + stack_t nss; + + // Set up an alternate signal stack for this thread. + memset(&ss, 0, sizeof ss); + ss.ss_sp = malloc(SIGSTKSZ); + if (ss.ss_sp == NULL) { + die("malloc"); + } + ss.ss_flags = 0; + ss.ss_size = SIGSTKSZ; + if (sigaltstack(&ss, NULL) < 0) { + die("sigaltstack"); + } + + oldcount = SIGIOCount(); + + // Call a Go function that will call a C function to send us a + // SIGIO. + tid = pthread_self(); + GoRaiseSIGIO(&tid); + + // Wait until the signal has been delivered. + i = 0; + while (SIGIOCount() == oldcount) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + // We should still be on the same signal stack. + if (sigaltstack(NULL, &nss) < 0) { + die("sigaltstack check"); + } + if ((nss.ss_flags & SS_DISABLE) != 0) { + fprintf(stderr, "sigaltstack disabled on return from Go\n"); + ok = 0; + } else if (nss.ss_sp != ss.ss_sp) { + fprintf(stderr, "sigalstack changed on return from Go\n"); + ok = 0; + } + + return NULL; +} + +int main(int argc, char **argv) { + pthread_t tid; + int i; + + // Tell the Go library to start looking for SIGIO. + GoCatchSIGIO(); + + i = pthread_create(&tid, NULL, thread1, NULL); + if (i != 0) { + fprintf(stderr, "pthread_create: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + i = pthread_join(tid, NULL); + if (i != 0) { + fprintf(stderr, "pthread_join: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + i = pthread_create(&tid, NULL, thread2, NULL); + if (i != 0) { + fprintf(stderr, "pthread_create: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + i = pthread_join(tid, NULL); + if (i != 0) { + fprintf(stderr, "pthread_join: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + if (!ok) { + exit(EXIT_FAILURE); + } + + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/main5.c b/libgo/misc/cgo/testcarchive/main5.c new file mode 100644 index 00000000000..9fadf0801e1 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main5.c @@ -0,0 +1,78 @@ +// 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. + +// Test for verifying that the Go runtime properly forwards +// signals when non-Go signals are raised. + +#include +#include +#include +#include +#include +#include + +#include "libgo2.h" + +int main(int argc, char** argv) { + int verbose; + int test; + + if (argc < 2) { + printf("Missing argument\n"); + return 1; + } + + test = atoi(argv[1]); + + verbose = (argc > 2); + + if (verbose) { + printf("calling RunGoroutines\n"); + } + + Noop(); + + switch (test) { + case 1: { + if (verbose) { + printf("attempting segfault\n"); + } + + volatile int crash = *(int *) 0; + break; + } + + case 2: { + struct timeval tv; + + if (verbose) { + printf("attempting external signal test\n"); + } + + fprintf(stderr, "OK\n"); + fflush(stderr); + + // The program should be interrupted before + // this sleep finishes. We use select rather + // than sleep because in older versions of + // glibc the sleep function does some signal + // fiddling to handle SIGCHLD. If this + // program is fiddling signals just when the + // test program sends the signal, the signal + // may be delivered to a Go thread which will + // break this test. + tv.tv_sec = 60; + tv.tv_usec = 0; + select(0, NULL, NULL, NULL, &tv); + + break; + } + default: + printf("Unknown test: %d\n", test); + return 0; + } + + printf("FAIL\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/main_unix.c b/libgo/misc/cgo/testcarchive/main_unix.c new file mode 100644 index 00000000000..4d9d16f03b0 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main_unix.c @@ -0,0 +1,53 @@ +// 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. + +#include +#include +#include +#include + +struct sigaction sa; +struct sigaction osa; + +static void (*oldHandler)(int, siginfo_t*, void*); + +static void handler(int signo, siginfo_t* info, void* ctxt) { + if (oldHandler) { + oldHandler(signo, info, ctxt); + } +} + +int install_handler() { + // Install our own signal handler. + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; + memset(&osa, 0, sizeof osa); + sigemptyset(&osa.sa_mask); + if (sigaction(SIGSEGV, &sa, &osa) < 0) { + perror("sigaction"); + return 2; + } + if (osa.sa_handler == SIG_DFL || (osa.sa_flags&SA_ONSTACK) == 0) { + fprintf(stderr, "Go runtime did not install signal handler\n"); + return 2; + } + oldHandler = osa.sa_sigaction; + + return 0; +} + +int check_handler() { + if (sigaction(SIGSEGV, NULL, &sa) < 0) { + perror("sigaction check"); + return 2; + } + if (sa.sa_sigaction != handler) { + fprintf(stderr, "ERROR: wrong signal handler: %p != %p\n", sa.sa_sigaction, handler); + return 2; + } + return 0; +} + diff --git a/libgo/misc/cgo/testcarchive/main_windows.c b/libgo/misc/cgo/testcarchive/main_windows.c new file mode 100644 index 00000000000..eded8af1a2c --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main_windows.c @@ -0,0 +1,17 @@ +// 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. + +/* + * Dummy implementations for Windows, because Windows doesn't + * support Unix-style signal handling. + */ + +int install_handler() { + return 0; +} + + +int check_handler() { + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/src/libgo/libgo.go b/libgo/misc/cgo/testcarchive/src/libgo/libgo.go new file mode 100644 index 00000000000..45958a546cb --- /dev/null +++ b/libgo/misc/cgo/testcarchive/src/libgo/libgo.go @@ -0,0 +1,53 @@ +// 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 + +import ( + "fmt" + "os" + "syscall" + "time" + + _ "p" +) + +import "C" + +var initCh = make(chan int, 1) +var ranMain bool + +func init() { + // emulate an exceedingly slow package initialization function + time.Sleep(100 * time.Millisecond) + initCh <- 42 +} + +func main() { ranMain = true } + +//export DidInitRun +func DidInitRun() bool { + select { + case x := <-initCh: + if x != 42 { + // Just in case initCh was not correctly made. + println("want init value of 42, got: ", x) + syscall.Exit(2) + } + return true + default: + return false + } +} + +//export DidMainRun +func DidMainRun() bool { return ranMain } + +//export CheckArgs +func CheckArgs() { + if len(os.Args) != 3 || os.Args[1] != "arg1" || os.Args[2] != "arg2" { + fmt.Printf("CheckArgs: want [_, arg1, arg2], got: %v\n", os.Args) + os.Exit(2) + } +} diff --git a/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go b/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go new file mode 100644 index 00000000000..fbed493b93f --- /dev/null +++ b/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go @@ -0,0 +1,50 @@ +// 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 + +import "C" + +import ( + "fmt" + "os" + "runtime" +) + +// RunGoroutines starts some goroutines that don't do anything. +// The idea is to get some threads going, so that a signal will be delivered +// to a thread started by Go. +//export RunGoroutines +func RunGoroutines() { + for i := 0; i < 4; i++ { + go func() { + runtime.LockOSThread() + select {} + }() + } +} + +var P *byte + +// TestSEGV makes sure that an invalid address turns into a run-time Go panic. +//export TestSEGV +func TestSEGV() { + defer func() { + if recover() == nil { + fmt.Fprintln(os.Stderr, "no panic from segv") + os.Exit(1) + } + }() + *P = 0 + fmt.Fprintln(os.Stderr, "continued after segv") + os.Exit(1) +} + +// Noop ensures that the Go runtime is initialized. +//export Noop +func Noop() { +} + +func main() { +} diff --git a/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go b/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go new file mode 100644 index 00000000000..94e5d21c14a --- /dev/null +++ b/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go @@ -0,0 +1,44 @@ +// 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 + +import "C" + +import ( + "os" + "os/signal" + "syscall" + "time" +) + +// The channel used to read SIGIO signals. +var sigioChan chan os.Signal + +// CatchSIGIO starts catching SIGIO signals. +//export CatchSIGIO +func CatchSIGIO() { + sigioChan = make(chan os.Signal, 1) + signal.Notify(sigioChan, syscall.SIGIO) +} + +// ResetSIGIO stops catching SIGIO signals. +//export ResetSIGIO +func ResetSIGIO() { + signal.Reset(syscall.SIGIO) +} + +// SawSIGIO returns whether we saw a SIGIO within a brief pause. +//export SawSIGIO +func SawSIGIO() C.int { + select { + case <-sigioChan: + return 1 + case <-time.After(100 * time.Millisecond): + return 0 + } +} + +func main() { +} diff --git a/libgo/misc/cgo/testcarchive/src/libgo4/libgo4.go b/libgo/misc/cgo/testcarchive/src/libgo4/libgo4.go new file mode 100644 index 00000000000..8cc1895f99f --- /dev/null +++ b/libgo/misc/cgo/testcarchive/src/libgo4/libgo4.go @@ -0,0 +1,52 @@ +// 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 +#include + +// Raise SIGIO. +static void CRaiseSIGIO(pthread_t* p) { + pthread_kill(*p, SIGIO); +} +*/ +import "C" + +import ( + "os" + "os/signal" + "sync/atomic" + "syscall" +) + +var sigioCount int32 + +// Catch SIGIO. +//export GoCatchSIGIO +func GoCatchSIGIO() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGIO) + go func() { + for range c { + atomic.AddInt32(&sigioCount, 1) + } + }() +} + +// Raise SIGIO. +//export GoRaiseSIGIO +func GoRaiseSIGIO(p *C.pthread_t) { + C.CRaiseSIGIO(p) +} + +// Return the number of SIGIO signals seen. +//export SIGIOCount +func SIGIOCount() C.int { + return C.int(atomic.LoadInt32(&sigioCount)) +} + +func main() { +} diff --git a/libgo/misc/cgo/testcarchive/src/p/p.go b/libgo/misc/cgo/testcarchive/src/p/p.go new file mode 100644 index 00000000000..82b445c1210 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/src/p/p.go @@ -0,0 +1,10 @@ +// 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 p + +import "C" + +//export FromPkg +func FromPkg() int32 { return 1024 } diff --git a/libgo/misc/cgo/testcshared/main0.c b/libgo/misc/cgo/testcshared/main0.c new file mode 100644 index 00000000000..1274b8950eb --- /dev/null +++ b/libgo/misc/cgo/testcshared/main0.c @@ -0,0 +1,36 @@ +// 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. + +#include +#include + +#include "p.h" +#include "libgo.h" + +// Tests libgo.so to export the following functions. +// int8_t DidInitRun(); +// int8_t DidMainRun(); +// int32_t FromPkg(); +int main(void) { + int8_t ran_init = DidInitRun(); + if (!ran_init) { + fprintf(stderr, "ERROR: DidInitRun returned unexpected results: %d\n", + ran_init); + return 1; + } + int8_t ran_main = DidMainRun(); + if (ran_main) { + fprintf(stderr, "ERROR: DidMainRun returned unexpected results: %d\n", + ran_main); + return 1; + } + int32_t from_pkg = FromPkg(); + if (from_pkg != 1024) { + fprintf(stderr, "ERROR: FromPkg=%d, want %d\n", from_pkg, 1024); + return 1; + } + // test.bash looks for "PASS" to ensure this program has reached the end. + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcshared/main1.c b/libgo/misc/cgo/testcshared/main1.c new file mode 100644 index 00000000000..420dd1ea974 --- /dev/null +++ b/libgo/misc/cgo/testcshared/main1.c @@ -0,0 +1,69 @@ +// 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. + +#include +#include +#include + +int check_int8(void* handle, const char* fname, int8_t want) { + int8_t (*fn)(); + fn = (int8_t (*)())dlsym(handle, fname); + if (!fn) { + fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror()); + return 1; + } + signed char ret = fn(); + if (ret != want) { + fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want); + return 1; + } + return 0; +} + +int check_int32(void* handle, const char* fname, int32_t want) { + int32_t (*fn)(); + fn = (int32_t (*)())dlsym(handle, fname); + if (!fn) { + fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror()); + return 1; + } + int32_t ret = fn(); + if (ret != want) { + fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want); + return 1; + } + return 0; +} + +// Tests libgo.so to export the following functions. +// int8_t DidInitRun() // returns true +// int8_t DidMainRun() // returns true +// int32_t FromPkg() // returns 1024 +int main(int argc, char** argv) { + void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + fprintf(stderr, "ERROR: failed to open the shared library: %s\n", + dlerror()); + return 2; + } + + int ret = 0; + ret = check_int8(handle, "DidInitRun", 1); + if (ret != 0) { + return ret; + } + + ret = check_int8(handle, "DidMainRun", 0); + if (ret != 0) { + return ret; + } + + ret = check_int32(handle, "FromPkg", 1024); + if (ret != 0) { + return ret; + } + // test.bash looks for "PASS" to ensure this program has reached the end. + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcshared/main2.c b/libgo/misc/cgo/testcshared/main2.c new file mode 100644 index 00000000000..6e8bf141caf --- /dev/null +++ b/libgo/misc/cgo/testcshared/main2.c @@ -0,0 +1,56 @@ +// 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. + +#include +#include +#include +#include +#include +#include + +#define fd (100) + +// Tests libgo2.so, which does not export any functions. +// Read a string from the file descriptor and print it. +int main(void) { + int i; + ssize_t n; + char buf[20]; + struct timespec ts; + + // The descriptor will be initialized in a thread, so we have to + // give a chance to get opened. + for (i = 0; i < 1000; i++) { + n = read(fd, buf, sizeof buf); + if (n >= 0) + break; + if (errno != EBADF && errno != EINVAL) { + fprintf(stderr, "BUG: read: %s\n", strerror(errno)); + return 2; + } + + // An EBADF error means that the shared library has not opened the + // descriptor yet. + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + } + + if (n < 0) { + fprintf(stderr, "BUG: failed to read any data from pipe\n"); + return 2; + } + + if (n == 0) { + fprintf(stderr, "BUG: unexpected EOF\n"); + return 2; + } + + if (n == sizeof buf) { + n--; + } + buf[n] = '\0'; + printf("%s\n", buf); + return 0; +} diff --git a/libgo/misc/cgo/testcshared/main3.c b/libgo/misc/cgo/testcshared/main3.c new file mode 100644 index 00000000000..49cc0558a01 --- /dev/null +++ b/libgo/misc/cgo/testcshared/main3.c @@ -0,0 +1,29 @@ +// 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. + +#include +#include +#include + +// Tests "main.main" is exported on android/arm, +// which golang.org/x/mobile/app depends on. +int main(int argc, char** argv) { + void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + fprintf(stderr, "ERROR: failed to open the shared library: %s\n", + dlerror()); + return 2; + } + + uintptr_t main_fn = (uintptr_t)dlsym(handle, "main.main"); + if (!main_fn) { + fprintf(stderr, "ERROR: missing main.main: %s\n", dlerror()); + return 2; + } + + // TODO(hyangah): check that main.main can run. + + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcshared/main4.c b/libgo/misc/cgo/testcshared/main4.c new file mode 100644 index 00000000000..355cdefb017 --- /dev/null +++ b/libgo/misc/cgo/testcshared/main4.c @@ -0,0 +1,215 @@ +// 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. + +// Test that a signal handler that uses up stack space does not crash +// if the signal is delivered to a thread running a goroutine. +// This is a lot like misc/cgo/testcarchive/main2.c. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void die(const char* msg) { + perror(msg); + exit(EXIT_FAILURE); +} + +static volatile sig_atomic_t sigioSeen; + +// Use up some stack space. +static void recur(int i, char *p) { + char a[1024]; + + *p = '\0'; + if (i > 0) { + recur(i - 1, a); + } +} + +// Signal handler that uses up more stack space than a goroutine will have. +static void ioHandler(int signo, siginfo_t* info, void* ctxt) { + char a[1024]; + + recur(4, a); + sigioSeen = 1; +} + +static jmp_buf jmp; +static char* nullPointer; + +// Signal handler for SIGSEGV on a C thread. +static void segvHandler(int signo, siginfo_t* info, void* ctxt) { + sigset_t mask; + int i; + + if (sigemptyset(&mask) < 0) { + die("sigemptyset"); + } + if (sigaddset(&mask, SIGSEGV) < 0) { + die("sigaddset"); + } + i = sigprocmask(SIG_UNBLOCK, &mask, NULL); + if (i != 0) { + fprintf(stderr, "sigprocmask: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + // Don't try this at home. + longjmp(jmp, signo); + + // We should never get here. + abort(); +} + +int main(int argc, char** argv) { + int verbose; + struct sigaction sa; + void* handle; + void (*fn)(void); + sigset_t mask; + int i; + struct timespec ts; + + verbose = argc > 2; + setvbuf(stdout, NULL, _IONBF, 0); + + // Call setsid so that we can use kill(0, SIGIO) below. + // Don't check the return value so that this works both from + // a job control shell and from a shell script. + setsid(); + + if (verbose) { + printf("calling sigaction\n"); + } + + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = ioHandler; + if (sigemptyset(&sa.sa_mask) < 0) { + die("sigemptyset"); + } + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGIO, &sa, NULL) < 0) { + die("sigaction"); + } + + sa.sa_sigaction = segvHandler; + if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) { + die("sigaction"); + } + + if (verbose) { + printf("calling dlopen\n"); + } + + handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL); + if (handle == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling dlsym\n"); + } + + // Start some goroutines. + fn = (void(*)(void))dlsym(handle, "RunGoroutines"); + if (fn == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling RunGoroutines\n"); + } + + fn(); + + // Block SIGIO in this thread to make it more likely that it + // will be delivered to a goroutine. + + if (verbose) { + printf("calling pthread_sigmask\n"); + } + + if (sigemptyset(&mask) < 0) { + die("sigemptyset"); + } + if (sigaddset(&mask, SIGIO) < 0) { + die("sigaddset"); + } + i = pthread_sigmask(SIG_BLOCK, &mask, NULL); + if (i != 0) { + fprintf(stderr, "pthread_sigmask: %s\n", strerror(i)); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling kill\n"); + } + + if (kill(0, SIGIO) < 0) { + die("kill"); + } + + if (verbose) { + printf("waiting for sigioSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + if (verbose) { + printf("calling setjmp\n"); + } + + // Test that a SIGSEGV on this thread is delivered to us. + if (setjmp(jmp) == 0) { + if (verbose) { + printf("triggering SIGSEGV\n"); + } + + *nullPointer = '\0'; + + fprintf(stderr, "continued after address error\n"); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling dlsym\n"); + } + + // Make sure that a SIGSEGV in Go causes a run-time panic. + fn = (void (*)(void))dlsym(handle, "TestSEGV"); + if (fn == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling TestSEGV\n"); + } + + fn(); + + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcshared/main5.c b/libgo/misc/cgo/testcshared/main5.c new file mode 100644 index 00000000000..1bc99101d7a --- /dev/null +++ b/libgo/misc/cgo/testcshared/main5.c @@ -0,0 +1,199 @@ +// 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. + +// Test that a signal handler works in non-Go code when using +// os/signal.Notify. +// This is a lot like misc/cgo/testcarchive/main3.c. + +#include +#include +#include +#include +#include +#include +#include + +static void die(const char* msg) { + perror(msg); + exit(EXIT_FAILURE); +} + +static volatile sig_atomic_t sigioSeen; + +static void ioHandler(int signo, siginfo_t* info, void* ctxt) { + sigioSeen = 1; +} + +int main(int argc, char** argv) { + int verbose; + struct sigaction sa; + void* handle; + void (*fn1)(void); + int (*sawSIGIO)(void); + int i; + struct timespec ts; + + verbose = argc > 2; + setvbuf(stdout, NULL, _IONBF, 0); + + if (verbose) { + printf("calling sigaction\n"); + } + + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = ioHandler; + if (sigemptyset(&sa.sa_mask) < 0) { + die("sigemptyset"); + } + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGIO, &sa, NULL) < 0) { + die("sigaction"); + } + + if (verbose) { + printf("calling dlopen\n"); + } + + handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL); + if (handle == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + // At this point there should not be a Go signal handler + // installed for SIGIO. + + if (verbose) { + printf("raising SIGIO\n"); + } + + if (raise(SIGIO) < 0) { + die("raise"); + } + + if (verbose) { + printf("waiting for sigioSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + sigioSeen = 0; + + // Tell the Go code to catch SIGIO. + + if (verbose) { + printf("calling dlsym\n"); + } + + fn1 = (void(*)(void))dlsym(handle, "CatchSIGIO"); + if (fn1 == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling CatchSIGIO\n"); + } + + fn1(); + + if (verbose) { + printf("raising SIGIO\n"); + } + + if (raise(SIGIO) < 0) { + die("raise"); + } + + if (verbose) { + printf("calling dlsym\n"); + } + + // Check that the Go code saw SIGIO. + sawSIGIO = (int (*)(void))dlsym(handle, "SawSIGIO"); + if (sawSIGIO == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling SawSIGIO\n"); + } + + if (!sawSIGIO()) { + fprintf(stderr, "Go handler did not see SIGIO\n"); + exit(EXIT_FAILURE); + } + + if (sigioSeen != 0) { + fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n"); + exit(EXIT_FAILURE); + } + + // Tell the Go code to stop catching SIGIO. + + if (verbose) { + printf("calling dlsym\n"); + } + + fn1 = (void(*)(void))dlsym(handle, "ResetSIGIO"); + if (fn1 == NULL) { + fprintf(stderr, "%s\n", dlerror()); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("calling ResetSIGIO\n"); + } + + fn1(); + + if (verbose) { + printf("raising SIGIO\n"); + } + + if (raise(SIGIO) < 0) { + die("raise"); + } + + if (verbose) { + printf("calling SawSIGIO\n"); + } + + if (sawSIGIO()) { + fprintf(stderr, "Go handler saw SIGIO after Reset\n"); + exit(EXIT_FAILURE); + } + + if (verbose) { + printf("waiting for sigioSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } + + printf("PASS\n"); + return 0; +} diff --git a/libgo/misc/cgo/testcshared/src/libgo/libgo.go b/libgo/misc/cgo/testcshared/src/libgo/libgo.go new file mode 100644 index 00000000000..8a4bf795e91 --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/libgo/libgo.go @@ -0,0 +1,46 @@ +// 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 + +import ( + _ "p" + "syscall" + "time" +) + +import "C" + +var initCh = make(chan int, 1) +var ranMain bool + +func init() { + // emulate an exceedingly slow package initialization function + time.Sleep(100 * time.Millisecond) + initCh <- 42 +} + +func main() { + ranMain = true +} + +//export DidInitRun +func DidInitRun() bool { + select { + case x := <-initCh: + if x != 42 { + // Just in case initCh was not correctly made. + println("want init value of 42, got: ", x) + syscall.Exit(2) + } + return true + default: + return false + } +} + +//export DidMainRun +func DidMainRun() bool { + return ranMain +} diff --git a/libgo/misc/cgo/testcshared/src/libgo2/dup2.go b/libgo/misc/cgo/testcshared/src/libgo2/dup2.go new file mode 100644 index 00000000000..d18f0b130d3 --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/libgo2/dup2.go @@ -0,0 +1,13 @@ +// 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. + +// +build darwin dragonfly freebsd linux,!arm64 netbsd openbsd + +package main + +import "syscall" + +func dup2(oldfd, newfd int) error { + return syscall.Dup2(oldfd, newfd) +} diff --git a/libgo/misc/cgo/testcshared/src/libgo2/dup3.go b/libgo/misc/cgo/testcshared/src/libgo2/dup3.go new file mode 100644 index 00000000000..c9c65a6e3c1 --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/libgo2/dup3.go @@ -0,0 +1,13 @@ +// 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. + +// +build linux,arm64 + +package main + +import "syscall" + +func dup2(oldfd, newfd int) error { + return syscall.Dup3(oldfd, newfd, 0) +} diff --git a/libgo/misc/cgo/testcshared/src/libgo2/libgo2.go b/libgo/misc/cgo/testcshared/src/libgo2/libgo2.go new file mode 100644 index 00000000000..1b69d8f09fa --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/libgo2/libgo2.go @@ -0,0 +1,52 @@ +// 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. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package main + +// Test a shared library created by -buildmode=c-shared that does not +// export anything. + +import ( + "fmt" + "os" + "syscall" +) + +// To test this we want to communicate between the main program and +// the shared library without using any exported symbols. The init +// function creates a pipe and Dups the read end to a known number +// that the C code can also use. + +const ( + fd = 100 +) + +func init() { + var p [2]int + if e := syscall.Pipe(p[0:]); e != nil { + fmt.Fprintf(os.Stderr, "pipe: %v\n", e) + os.Exit(2) + } + + if e := dup2(p[0], fd); e != nil { + fmt.Fprintf(os.Stderr, "dup2: %v\n", e) + os.Exit(2) + } + + const str = "PASS" + if n, e := syscall.Write(p[1], []byte(str)); e != nil || n != len(str) { + fmt.Fprintf(os.Stderr, "write: %d %v\n", n, e) + os.Exit(2) + } + + if e := syscall.Close(p[1]); e != nil { + fmt.Fprintf(os.Stderr, "close: %v\n", e) + os.Exit(2) + } +} + +func main() { +} diff --git a/libgo/misc/cgo/testcshared/src/libgo4/libgo4.go b/libgo/misc/cgo/testcshared/src/libgo4/libgo4.go new file mode 100644 index 00000000000..ab40b75e78a --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/libgo4/libgo4.go @@ -0,0 +1,45 @@ +// 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 + +import "C" + +import ( + "fmt" + "os" + "runtime" +) + +// RunGoroutines starts some goroutines that don't do anything. +// The idea is to get some threads going, so that a signal will be delivered +// to a thread started by Go. +//export RunGoroutines +func RunGoroutines() { + for i := 0; i < 4; i++ { + go func() { + runtime.LockOSThread() + select {} + }() + } +} + +var P *byte + +// TestSEGV makes sure that an invalid address turns into a run-time Go panic. +//export TestSEGV +func TestSEGV() { + defer func() { + if recover() == nil { + fmt.Fprintln(os.Stderr, "no panic from segv") + os.Exit(1) + } + }() + *P = 0 + fmt.Fprintln(os.Stderr, "continued after segv") + os.Exit(1) +} + +func main() { +} diff --git a/libgo/misc/cgo/testcshared/src/libgo5/libgo5.go b/libgo/misc/cgo/testcshared/src/libgo5/libgo5.go new file mode 100644 index 00000000000..94e5d21c14a --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/libgo5/libgo5.go @@ -0,0 +1,44 @@ +// 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 + +import "C" + +import ( + "os" + "os/signal" + "syscall" + "time" +) + +// The channel used to read SIGIO signals. +var sigioChan chan os.Signal + +// CatchSIGIO starts catching SIGIO signals. +//export CatchSIGIO +func CatchSIGIO() { + sigioChan = make(chan os.Signal, 1) + signal.Notify(sigioChan, syscall.SIGIO) +} + +// ResetSIGIO stops catching SIGIO signals. +//export ResetSIGIO +func ResetSIGIO() { + signal.Reset(syscall.SIGIO) +} + +// SawSIGIO returns whether we saw a SIGIO within a brief pause. +//export SawSIGIO +func SawSIGIO() C.int { + select { + case <-sigioChan: + return 1 + case <-time.After(100 * time.Millisecond): + return 0 + } +} + +func main() { +} diff --git a/libgo/misc/cgo/testcshared/src/p/p.go b/libgo/misc/cgo/testcshared/src/p/p.go new file mode 100644 index 00000000000..82b445c1210 --- /dev/null +++ b/libgo/misc/cgo/testcshared/src/p/p.go @@ -0,0 +1,10 @@ +// 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 p + +import "C" + +//export FromPkg +func FromPkg() int32 { return 1024 } diff --git a/libgo/misc/cgo/testcshared/test.bash b/libgo/misc/cgo/testcshared/test.bash new file mode 100644 index 00000000000..0315fb07f57 --- /dev/null +++ b/libgo/misc/cgo/testcshared/test.bash @@ -0,0 +1,193 @@ +#!/usr/bin/env bash +# 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. + +# For testing Android, this script requires adb to push and run compiled +# binaries on a target device. + +set -e + +if [ ! -f src/libgo/libgo.go ]; then + cwd=$(pwd) + echo "misc/cgo/testcshared/test.bash is running in $cwd" 1>&2 + exit 1 +fi + +goos=$(go env GOOS) +goarch=$(go env GOARCH) +goroot=$(go env GOROOT) +if [ ! -d "$goroot" ]; then + echo 'misc/cgo/testcshared/test.bash cannot find GOROOT' 1>&2 + echo '$GOROOT:' "$GOROOT" 1>&2 + echo 'go env GOROOT:' "$goroot" 1>&2 + exit 1 +fi + +# Directory where cgo headers and outputs will be installed. +# The installation directory format varies depending on the platform. +installdir=pkg/${goos}_${goarch}_testcshared_shared +if [ "${goos}" == "darwin" ]; then + installdir=pkg/${goos}_${goarch}_testcshared +fi + +# Temporary directory on the android device. +androidpath=/data/local/tmp/testcshared-$$ + +function cleanup() { + rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext + rm -f libgo.h libgo4.h libgo5.h + rm -f testp testp2 testp3 testp4 testp5 + rm -rf pkg "${goroot}/${installdir}" + + if [ "$goos" == "android" ]; then + adb shell rm -rf "$androidpath" + fi +} +trap cleanup EXIT + +if [ "$goos" == "android" ]; then + adb shell mkdir -p "$androidpath" +fi + +function run() { + case "$goos" in + "android") + local args=$@ + output=$(adb shell "cd ${androidpath}; $@") + output=$(echo $output|tr -d '\r') + case $output in + *PASS) echo "PASS";; + *) echo "$output";; + esac + ;; + *) + echo $(env $@) + ;; + esac +} + +function binpush() { + bin=${1} + if [ "$goos" == "android" ]; then + adb push "$bin" "${androidpath}/${bin}" 2>/dev/null + fi +} + +rm -rf pkg + +suffix="-installsuffix testcshared" + +libext="so" +if [ "$goos" == "darwin" ]; then + libext="dylib" +fi + +# Create the header files. +GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo + +GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go +binpush libgo.$libext + +if [ "$goos" == "linux" ] || [ "$goos" == "android" ] ; then + if readelf -d libgo.$libext | grep TEXTREL >/dev/null; then + echo "libgo.$libext has TEXTREL set" + exit 1 + fi +fi + +GOGCCFLAGS=$(go env GOGCCFLAGS) +if [ "$goos" == "android" ]; then + GOGCCFLAGS="${GOGCCFLAGS} -pie" +fi + +status=0 + +# test0: exported symbols in shared lib are accessible. +# TODO(iant): using _shared here shouldn't really be necessary. +$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c ./libgo.$libext +binpush testp + +output=$(run LD_LIBRARY_PATH=. ./testp) +if [ "$output" != "PASS" ]; then + echo "FAIL test0 got ${output}" + status=1 +fi + +# test1: shared library can be dynamically loaded and exported symbols are accessible. +$(go env CC) ${GOGCCFLAGS} -o testp main1.c -ldl +binpush testp +output=$(run ./testp ./libgo.$libext) +if [ "$output" != "PASS" ]; then + echo "FAIL test1 got ${output}" + status=1 +fi + +# test2: tests libgo2 which does not export any functions. +GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext libgo2 +binpush libgo2.$libext +linkflags="-Wl,--no-as-needed" +if [ "$goos" == "darwin" ]; then + linkflags="" +fi +$(go env CC) ${GOGCCFLAGS} -o testp2 main2.c $linkflags libgo2.$libext +binpush testp2 +output=$(run LD_LIBRARY_PATH=. ./testp2) +if [ "$output" != "PASS" ]; then + echo "FAIL test2 got ${output}" + status=1 +fi + +# test3: tests main.main is exported on android. +if [ "$goos" == "android" ]; then + $(go env CC) ${GOGCCFLAGS} -o testp3 main3.c -ldl + binpush testp3 + output=$(run ./testp ./libgo.so) + if [ "$output" != "PASS" ]; then + echo "FAIL test3 got ${output}" + status=1 + fi +fi + +# test4: tests signal handlers +GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo4.$libext libgo4 +binpush libgo4.$libext +$(go env CC) ${GOGCCFLAGS} -pthread -o testp4 main4.c -ldl +binpush testp4 +output=$(run ./testp4 ./libgo4.$libext 2>&1) +if test "$output" != "PASS"; then + echo "FAIL test4 got ${output}" + if test "$goos" != "android"; then + echo "re-running test4 in verbose mode" + ./testp4 ./libgo4.$libext verbose + fi + status=1 +fi + +# test5: tests signal handlers with os/signal.Notify +GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5 +binpush libgo5.$libext +$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl +binpush testp5 +output=$(run ./testp5 ./libgo5.$libext 2>&1) +if test "$output" != "PASS"; then + echo "FAIL test5 got ${output}" + if test "$goos" != "android"; then + echo "re-running test5 in verbose mode" + ./testp5 ./libgo5.$libext verbose + fi + status=1 +fi + +if test "$libext" = "dylib"; then + # make sure dylibs are well-formed + if ! otool -l libgo*.dylib >/dev/null; then + status=1 + fi +fi + +if test $status = 0; then + echo "ok" +fi + +exit $status diff --git a/libgo/misc/cgo/testgodefs/anonunion.go b/libgo/misc/cgo/testgodefs/anonunion.go new file mode 100644 index 00000000000..18840f2577c --- /dev/null +++ b/libgo/misc/cgo/testgodefs/anonunion.go @@ -0,0 +1,26 @@ +// 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. +// +// +build ignore + +package main + +// This file tests that when cgo -godefs sees a struct with a field +// that is an anonymous union, the first field in the union is +// promoted to become a field of the struct. See issue 6677 for +// background. + +/* +typedef struct { + union { + long l; + int c; + }; +} t; +*/ +import "C" + +// Input for cgo -godefs. + +type T C.t diff --git a/libgo/misc/cgo/testgodefs/issue8478.go b/libgo/misc/cgo/testgodefs/issue8478.go new file mode 100644 index 00000000000..23214461711 --- /dev/null +++ b/libgo/misc/cgo/testgodefs/issue8478.go @@ -0,0 +1,20 @@ +// 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. +// +// +build ignore + +package main + +// Issue 8478. Test that void* is consistently mapped to *byte. + +/* +typedef struct { + void *p; + void **q; + void ***r; +} s; +*/ +import "C" + +type Issue8478 C.s diff --git a/libgo/misc/cgo/testgodefs/main.go b/libgo/misc/cgo/testgodefs/main.go new file mode 100644 index 00000000000..1ce0fd0d1e1 --- /dev/null +++ b/libgo/misc/cgo/testgodefs/main.go @@ -0,0 +1,15 @@ +// 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 + +// Test that the struct field in anonunion.go was promoted. +var v1 T +var v2 = v1.L + +// Test that P, Q, and R all point to byte. +var v3 = Issue8478{P: (*byte)(nil), Q: (**byte)(nil), R: (***byte)(nil)} + +func main() { +} diff --git a/libgo/misc/cgo/testgodefs/test.bash b/libgo/misc/cgo/testgodefs/test.bash new file mode 100644 index 00000000000..a82ff9328fe --- /dev/null +++ b/libgo/misc/cgo/testgodefs/test.bash @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# 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. + +# We are testing cgo -godefs, which translates Go files that use +# import "C" into Go files with Go definitions of types defined in the +# import "C" block. Add more tests here. +FILE_PREFIXES="anonunion issue8478" + +RM= +for FP in $FILE_PREFIXES +do + go tool cgo -godefs -srcdir . ${FP}.go > ${FP}_defs.go + RM="${RM} ${FP}_defs.go" +done + +go build . && ./testgodefs +EXIT=$? +rm -rf _obj testgodefs ${RM} +exit $EXIT diff --git a/libgo/misc/cgo/testplugin/altpath/src/common/common.go b/libgo/misc/cgo/testplugin/altpath/src/common/common.go new file mode 100644 index 00000000000..505ba02b1f1 --- /dev/null +++ b/libgo/misc/cgo/testplugin/altpath/src/common/common.go @@ -0,0 +1,11 @@ +// 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 common + +var X int + +func init() { + X = 4 +} diff --git a/libgo/misc/cgo/testplugin/altpath/src/plugin-mismatch/main.go b/libgo/misc/cgo/testplugin/altpath/src/plugin-mismatch/main.go new file mode 100644 index 00000000000..8aacafc4530 --- /dev/null +++ b/libgo/misc/cgo/testplugin/altpath/src/plugin-mismatch/main.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. + +package main + +// // No C code required. +import "C" + +// The common package imported here does not match the common package +// imported by plugin1. A program that attempts to load plugin1 and +// plugin-mismatch should produce an error. +import "common" + +func ReadCommonX() int { + return common.X +} diff --git a/libgo/misc/cgo/testplugin/src/common/common.go b/libgo/misc/cgo/testplugin/src/common/common.go new file mode 100644 index 00000000000..b064e6bccfe --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/common/common.go @@ -0,0 +1,11 @@ +// 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 common + +var X int + +func init() { + X = 3 +} diff --git a/libgo/misc/cgo/testplugin/src/host/host.go b/libgo/misc/cgo/testplugin/src/host/host.go new file mode 100644 index 00000000000..898f44efa15 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/host/host.go @@ -0,0 +1,148 @@ +// 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 + +import ( + "fmt" + "log" + "path/filepath" + "plugin" + "strings" + + "common" +) + +func init() { + common.X *= 5 +} + +// testUnnamed tests that two plugins built with .go files passed on +// the command line do not have overlapping symbols. That is, +// unnamed1.so/FuncInt and unnamed2.so/FuncInt should be distinct functions. +func testUnnamed() { + p, err := plugin.Open("unnamed1.so") + if err != nil { + log.Fatalf(`plugin.Open("unnamed1.so"): %v`, err) + } + fn, err := p.Lookup("FuncInt") + if err != nil { + log.Fatalf(`unnamed1.so: Lookup("FuncInt") failed: %v`, err) + } + if got, want := fn.(func() int)(), 1; got != want { + log.Fatalf("unnamed1.so: FuncInt()=%d, want %d", got, want) + } + + p, err = plugin.Open("unnamed2.so") + if err != nil { + log.Fatalf(`plugin.Open("unnamed2.so"): %v`, err) + } + fn, err = p.Lookup("FuncInt") + if err != nil { + log.Fatalf(`unnamed2.so: Lookup("FuncInt") failed: %v`, err) + } + if got, want := fn.(func() int)(), 2; got != want { + log.Fatalf("unnamed2.so: FuncInt()=%d, want %d", got, want) + } +} + +func main() { + if got, want := common.X, 3*5; got != want { + log.Fatalf("before plugin load common.X=%d, want %d", got, want) + } + + p, err := plugin.Open("plugin1.so") + if err != nil { + log.Fatalf("plugin.Open failed: %v", err) + } + + const wantX = 3 * 5 * 7 + if got := common.X; got != wantX { + log.Fatalf("after plugin load common.X=%d, want %d", got, wantX) + } + + seven, err := p.Lookup("Seven") + if err != nil { + log.Fatalf(`Lookup("Seven") failed: %v`, err) + } + if got, want := *seven.(*int), 7; got != want { + log.Fatalf("plugin1.Seven=%d, want %d", got, want) + } + + readFunc, err := p.Lookup("ReadCommonX") + if err != nil { + log.Fatalf(`plugin1.Lookup("ReadCommonX") failed: %v`, err) + } + if got := readFunc.(func() int)(); got != wantX { + log.Fatalf("plugin1.ReadCommonX()=%d, want %d", got, wantX) + } + + // sub/plugin1.so is a different plugin with the same name as + // the already loaded plugin. It also depends on common. Test + // that we can load the different plugin, it is actually + // different, and that it sees the same common package. + subpPath, err := filepath.Abs("sub/plugin1.so") + if err != nil { + log.Fatalf("filepath.Abs(%q) failed: %v", subpPath, err) + } + subp, err := plugin.Open(subpPath) + if err != nil { + log.Fatalf("plugin.Open(%q) failed: %v", subpPath, err) + } + + funcVar, err := subp.Lookup("FuncVar") + if err != nil { + log.Fatalf(`sub/plugin1.Lookup("FuncVar") failed: %v`, err) + } + called := false + *funcVar.(*func()) = func() { + called = true + } + + readFunc, err = subp.Lookup("ReadCommonX") + if err != nil { + log.Fatalf(`sub/plugin1.Lookup("ReadCommonX") failed: %v`, err) + } + if got := readFunc.(func() int)(); got != wantX { + log.Fatalf("sub/plugin1.ReadCommonX()=%d, want %d", got, wantX) + } + if !called { + log.Fatal("calling ReadCommonX did not call FuncVar") + } + + subf, err := subp.Lookup("F") + if err != nil { + log.Fatalf(`sub/plugin1.Lookup("F") failed: %v`, err) + } + if gotf := subf.(func() int)(); gotf != 17 { + log.Fatalf(`sub/plugin1.F()=%d, want 17`, gotf) + } + f, err := p.Lookup("F") + if err != nil { + log.Fatalf(`plugin1.Lookup("F") failed: %v`, err) + } + if gotf := f.(func() int)(); gotf != 3 { + log.Fatalf(`plugin1.F()=%d, want 17`, gotf) + } + + // plugin2 has no exported symbols, only an init function. + if _, err := plugin.Open("plugin2.so"); err != nil { + log.Fatalf("plugin.Open failed: %v", err) + } + if got, want := common.X, 2; got != want { + log.Fatalf("after loading plugin2, common.X=%d, want %d", got, want) + } + + _, err = plugin.Open("plugin-mismatch.so") + if err == nil { + log.Fatal(`plugin.Open("plugin-mismatch.so"): should have failed`) + } + if s := err.Error(); !strings.Contains(s, "different version") { + log.Fatalf(`plugin.Open("plugin-mismatch.so"): error does not mention "different version": %v`, s) + } + + testUnnamed() + + fmt.Println("PASS") +} diff --git a/libgo/misc/cgo/testplugin/src/iface/main.go b/libgo/misc/cgo/testplugin/src/iface/main.go new file mode 100644 index 00000000000..5e7e4d8b480 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/iface/main.go @@ -0,0 +1,46 @@ +// Copyright 2017 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 ( + "iface_i" + "log" + "plugin" +) + +func main() { + a, err := plugin.Open("iface_a.so") + if err != nil { + log.Fatalf(`plugin.Open("iface_a.so"): %v`, err) + } + b, err := plugin.Open("iface_b.so") + if err != nil { + log.Fatalf(`plugin.Open("iface_b.so"): %v`, err) + } + + af, err := a.Lookup("F") + if err != nil { + log.Fatalf(`a.Lookup("F") failed: %v`, err) + } + bf, err := b.Lookup("F") + if err != nil { + log.Fatalf(`b.Lookup("F") failed: %v`, err) + } + if af.(func() interface{})() != bf.(func() interface{})() { + panic("empty interfaces not equal") + } + + ag, err := a.Lookup("G") + if err != nil { + log.Fatalf(`a.Lookup("G") failed: %v`, err) + } + bg, err := b.Lookup("G") + if err != nil { + log.Fatalf(`b.Lookup("G") failed: %v`, err) + } + if ag.(func() iface_i.I)() != bg.(func() iface_i.I)() { + panic("nonempty interfaces not equal") + } +} diff --git a/libgo/misc/cgo/testplugin/src/iface_a/a.go b/libgo/misc/cgo/testplugin/src/iface_a/a.go new file mode 100644 index 00000000000..29d2e277640 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/iface_a/a.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 "iface_i" + +//go:noinline +func F() interface{} { + return (*iface_i.T)(nil) +} + +//go:noinline +func G() iface_i.I { + return (*iface_i.T)(nil) +} diff --git a/libgo/misc/cgo/testplugin/src/iface_b/b.go b/libgo/misc/cgo/testplugin/src/iface_b/b.go new file mode 100644 index 00000000000..29d2e277640 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/iface_b/b.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 "iface_i" + +//go:noinline +func F() interface{} { + return (*iface_i.T)(nil) +} + +//go:noinline +func G() iface_i.I { + return (*iface_i.T)(nil) +} diff --git a/libgo/misc/cgo/testplugin/src/iface_i/i.go b/libgo/misc/cgo/testplugin/src/iface_i/i.go new file mode 100644 index 00000000000..31c80387c7e --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/iface_i/i.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 iface_i + +type I interface { + M() +} + +type T struct { +} + +func (t *T) M() { +} + +// *T implements I diff --git a/libgo/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go b/libgo/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go new file mode 100644 index 00000000000..70fd054d089 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue18676/dynamodbstreamsevt/definition.go @@ -0,0 +1,13 @@ +// Copyright 2017 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 dynamodbstreamsevt + +import "encoding/json" + +var foo json.RawMessage + +type Event struct{} + +func (e *Event) Dummy() {} diff --git a/libgo/misc/cgo/testplugin/src/issue18676/main.go b/libgo/misc/cgo/testplugin/src/issue18676/main.go new file mode 100644 index 00000000000..c75409dafe7 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue18676/main.go @@ -0,0 +1,31 @@ +// Copyright 2017 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. + +// The bug happened like this: +// 1) The main binary adds an itab for *json.UnsupportedValueError / error +// (concrete type / interface type). This itab goes in hash bucket 0x111. +// 2) The plugin adds that same itab again. That makes a cycle in the itab +// chain rooted at hash bucket 0x111. +// 3) The main binary then asks for the itab for *dynamodbstreamsevt.Event / +// json.Unmarshaler. This itab happens to also live in bucket 0x111. +// The lookup code goes into an infinite loop searching for this itab. +// The code is carefully crafted so that the two itabs are both from the +// same bucket, and so that the second itab doesn't exist in +// the itab hashmap yet (so the entire linked list must be searched). +package main + +import ( + "encoding/json" + "issue18676/dynamodbstreamsevt" + "plugin" +) + +func main() { + plugin.Open("plugin.so") + + var x interface{} = (*dynamodbstreamsevt.Event)(nil) + if _, ok := x.(json.Unmarshaler); !ok { + println("something") + } +} diff --git a/libgo/misc/cgo/testplugin/src/issue18676/plugin.go b/libgo/misc/cgo/testplugin/src/issue18676/plugin.go new file mode 100644 index 00000000000..8a3b85a75cd --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue18676/plugin.go @@ -0,0 +1,11 @@ +// Copyright 2017 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" + +import "issue18676/dynamodbstreamsevt" + +func F(evt *dynamodbstreamsevt.Event) {} diff --git a/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go b/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go new file mode 100644 index 00000000000..edcef2c77e9 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/plugin1/plugin1.go @@ -0,0 +1,38 @@ +// 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 + +// // No C code required. +import "C" + +import "common" + +func F() int { + _ = make([]byte, 1<<21) // trigger stack unwind, Issue #18190. + return 3 +} + +func ReadCommonX() int { + return common.X +} + +var Seven int + +func call(fn func()) { + fn() +} + +func g() { + common.X *= Seven +} + +func init() { + Seven = 7 + call(g) +} + +func main() { + panic("plugin1.main called") +} diff --git a/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go b/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go new file mode 100644 index 00000000000..9c507fc3658 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/plugin2/plugin2.go @@ -0,0 +1,27 @@ +// 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 + +//#include +//#include +import "C" + +// #include +// void cfunc() {} // uses cgo_topofstack + +import ( + "common" + "strings" +) + +func init() { + _ = strings.NewReplacer() // trigger stack unwind, Issue #18190. + C.strerror(C.EIO) // uses cgo_topofstack + common.X = 2 +} + +func main() { + panic("plugin1.main called") +} diff --git a/libgo/misc/cgo/testplugin/src/sub/plugin1/plugin1.go b/libgo/misc/cgo/testplugin/src/sub/plugin1/plugin1.go new file mode 100644 index 00000000000..cf9000c4a4e --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/sub/plugin1/plugin1.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. + +package main + +// // No C code required. +import "C" + +import "common" + +func F() int { return 17 } + +var FuncVar = func() {} + +func ReadCommonX() int { + FuncVar() + return common.X +} + +func main() { + panic("plugin1.main called") +} diff --git a/libgo/misc/cgo/testplugin/test.bash b/libgo/misc/cgo/testplugin/test.bash new file mode 100644 index 00000000000..ab7430acc37 --- /dev/null +++ b/libgo/misc/cgo/testplugin/test.bash @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# 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. + +set -e + +if [ ! -f src/host/host.go ]; then + cwd=$(pwd) + echo "misc/cgo/testplugin/test.bash is running in $cwd" 1>&2 + exit 1 +fi + +goos=$(go env GOOS) +goarch=$(go env GOARCH) + +function cleanup() { + rm -f plugin*.so unnamed*.so iface*.so + rm -rf host pkg sub iface issue18676 +} +trap cleanup EXIT + +rm -rf pkg sub +mkdir sub + +GOPATH=$(pwd) go build -buildmode=plugin plugin1 +GOPATH=$(pwd) go build -buildmode=plugin plugin2 +GOPATH=$(pwd)/altpath go build -buildmode=plugin plugin-mismatch +GOPATH=$(pwd) go build -buildmode=plugin -o=sub/plugin1.so sub/plugin1 +GOPATH=$(pwd) go build -buildmode=plugin unnamed1.go +GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go +GOPATH=$(pwd) go build host + +LD_LIBRARY_PATH=$(pwd) ./host + +# Test that types and itabs get properly uniqified. +GOPATH=$(pwd) go build -buildmode=plugin iface_a +GOPATH=$(pwd) go build -buildmode=plugin iface_b +GOPATH=$(pwd) go build iface +LD_LIBRARY_PATH=$(pwd) ./iface + +# Test for issue 18676 - make sure we don't add the same itab twice. +# The buggy code hangs forever, so use a timeout to check for that. +GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go +GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go +timeout 10s ./issue18676 diff --git a/libgo/misc/cgo/testplugin/unnamed1.go b/libgo/misc/cgo/testplugin/unnamed1.go new file mode 100644 index 00000000000..102edaf3e29 --- /dev/null +++ b/libgo/misc/cgo/testplugin/unnamed1.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 + +// // No C code required. +import "C" + +func FuncInt() int { return 1 } + +func main() {} diff --git a/libgo/misc/cgo/testplugin/unnamed2.go b/libgo/misc/cgo/testplugin/unnamed2.go new file mode 100644 index 00000000000..55070d5e9f7 --- /dev/null +++ b/libgo/misc/cgo/testplugin/unnamed2.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 + +// // No C code required. +import "C" + +func FuncInt() int { return 2 } + +func main() {} diff --git a/libgo/misc/cgo/testsanitizers/msan.go b/libgo/misc/cgo/testsanitizers/msan.go new file mode 100644 index 00000000000..7915fa84f60 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan.go @@ -0,0 +1,35 @@ +// 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 + +void f(int32_t *p, int n) { + int i; + + for (i = 0; i < n; i++) { + p[i] = (int32_t)i; + } +} +*/ +import "C" + +import ( + "fmt" + "os" + "unsafe" +) + +func main() { + a := make([]int32, 10) + C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) + for i, v := range a { + if i != int(v) { + fmt.Println("bad %d: %v\n", i, a) + os.Exit(1) + } + } +} diff --git a/libgo/misc/cgo/testsanitizers/msan2.go b/libgo/misc/cgo/testsanitizers/msan2.go new file mode 100644 index 00000000000..6690cb034fc --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan2.go @@ -0,0 +1,35 @@ +// 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 +#include +#include + +void f(int32_t *p, int n) { + int32_t * volatile q = (int32_t *)malloc(sizeof(int32_t) * n); + memcpy(p, q, n * sizeof(*p)); + free(q); +} + +void g(int32_t *p, int n) { + if (p[4] != 1) { + abort(); + } +} +*/ +import "C" + +import ( + "unsafe" +) + +func main() { + a := make([]int32, 10) + C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) + a[4] = 1 + C.g((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) +} diff --git a/libgo/misc/cgo/testsanitizers/msan3.go b/libgo/misc/cgo/testsanitizers/msan3.go new file mode 100644 index 00000000000..61a9c29e1a9 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan3.go @@ -0,0 +1,33 @@ +// 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 + +/* +extern int *GoFn(int *); + +// Yes, you can have definitions if you use //export, as long as they are weak. +int f(void) __attribute__ ((weak)); + +int f() { + int i; + int *p = GoFn(&i); + if (*p != 12345) + return 0; + return 1; +} +*/ +import "C" + +//export GoFn +func GoFn(p *C.int) *C.int { + *p = C.int(12345) + return p +} + +func main() { + if r := C.f(); r != 1 { + panic(r) + } +} diff --git a/libgo/misc/cgo/testsanitizers/msan4.go b/libgo/misc/cgo/testsanitizers/msan4.go new file mode 100644 index 00000000000..6c91ff5f091 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan4.go @@ -0,0 +1,50 @@ +// 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 + +// The memory profiler can call copy from a slice on the system stack, +// which msan used to think meant a reference to uninitialized memory. + +/* +#include +#include + +extern void Nop(char*); + +// Use weak as a hack to permit defining a function even though we use export. +void poison() __attribute__ ((weak)); + +// Poison the stack. +void poison() { + char a[1024]; + Nop(&a[0]); +} + +*/ +import "C" + +import ( + "runtime" +) + +func main() { + runtime.MemProfileRate = 1 + start(100) +} + +func start(i int) { + if i == 0 { + return + } + C.poison() + // Tie up a thread. + // We won't actually wait for this sleep to complete. + go func() { C.sleep(1) }() + start(i - 1) +} + +//export Nop +func Nop(*C.char) { +} diff --git a/libgo/misc/cgo/testsanitizers/msan5.go b/libgo/misc/cgo/testsanitizers/msan5.go new file mode 100644 index 00000000000..f1479eb8a00 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan5.go @@ -0,0 +1,57 @@ +// 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 + +// Using reflect to set a value was not seen by msan. + +/* +#include + +extern void Go1(int*); +extern void Go2(char*); + +// Use weak as a hack to permit defining a function even though we use export. +void C1() __attribute__ ((weak)); +void C2() __attribute__ ((weak)); + +void C1() { + int i; + Go1(&i); + if (i != 42) { + abort(); + } +} + +void C2() { + char a[2]; + a[1] = 42; + Go2(a); + if (a[0] != 42) { + abort(); + } +} +*/ +import "C" + +import ( + "reflect" + "unsafe" +) + +//export Go1 +func Go1(p *C.int) { + reflect.ValueOf(p).Elem().Set(reflect.ValueOf(C.int(42))) +} + +//export Go2 +func Go2(p *C.char) { + a := (*[2]byte)(unsafe.Pointer(p)) + reflect.Copy(reflect.ValueOf(a[:1]), reflect.ValueOf(a[1:])) +} + +func main() { + C.C1() + C.C2() +} diff --git a/libgo/misc/cgo/testsanitizers/msan_fail.go b/libgo/misc/cgo/testsanitizers/msan_fail.go new file mode 100644 index 00000000000..4c8dab34f6e --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan_fail.go @@ -0,0 +1,36 @@ +// 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 +#include +#include + +void f(int32_t *p, int n) { + int32_t * volatile q = (int32_t *)malloc(sizeof(int32_t) * n); + memcpy(p, q, n * sizeof(*p)); + free(q); +} + +void g(int32_t *p, int n) { + if (p[4] != 1) { + // We shouldn't get here; msan should stop us first. + exit(0); + } +} +*/ +import "C" + +import ( + "unsafe" +) + +func main() { + a := make([]int32, 10) + C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) + a[3] = 1 + C.g((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a))) +} diff --git a/libgo/misc/cgo/testsanitizers/msan_shared.go b/libgo/misc/cgo/testsanitizers/msan_shared.go new file mode 100644 index 00000000000..966947cac35 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/msan_shared.go @@ -0,0 +1,12 @@ +// Copyright 2017 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. + +// This program segfaulted during libpreinit when built with -msan: +// http://golang.org/issue/18707 + +package main + +import "C" + +func main() {} diff --git a/libgo/misc/cgo/testsanitizers/test.bash b/libgo/misc/cgo/testsanitizers/test.bash new file mode 100644 index 00000000000..4da85020d89 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/test.bash @@ -0,0 +1,204 @@ +#!/usr/bin/env bash +# 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. + +# This directory is intended to test the use of Go with sanitizers +# like msan, asan, etc. See https://github.com/google/sanitizers . + +set -e + +# The sanitizers were originally developed with clang, so prefer it. +CC=cc +if test -x "$(type -p clang)"; then + CC=clang +fi +export CC + +if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then + echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2 + exit 0 +fi + +msan=yes + +TMPDIR=${TMPDIR:-/tmp} +echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c +if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then + echo "skipping msan tests: $CC -fsanitize=memory not supported" + msan=no +elif ! test -x ${TMPDIR}/testsanitizers$$; then + echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable" + msan=no +elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then + echo "skipping msan tests: $CC -fsanitize-memory generates broken executable" + msan=no +fi +rm -f ${TMPDIR}/testsanitizers$$.* + +tsan=yes + +# The memory and thread sanitizers in versions of clang before 3.6 +# don't work with Go. +if test "$msan" = "yes" && $CC --version | grep clang >& /dev/null; then + ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/') + major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') + minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/') + if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then + echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.6)" + msan=no + tsan=no + fi + + # Clang before 3.8 does not work with Linux at or after 4.1. + # golang.org/issue/12898. + if test "$msan" = "yes" -a "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then + if test "$(uname)" = Linux; then + linuxver=$(uname -r) + linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/') + linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/') + if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then + echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)" + msan=no + tsan=no + fi + fi + fi +fi + +status=0 + +testmsanshared() { + goos=$(go env GOOS) + suffix="-installsuffix testsanitizers" + libext="so" + if [ "$goos" == "darwin" ]; then + libext="dylib" + fi + go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go + + echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c + $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext + + if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then + echo "FAIL: msan_shared" + status=1 + fi + rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext} +} + +if test "$msan" = "yes"; then + if ! go build -msan std; then + echo "FAIL: build -msan std" + status=1 + fi + + if ! go run -msan msan.go; then + echo "FAIL: msan" + status=1 + fi + + if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then + echo "FAIL: msan2 with -fsanitize=memory" + status=1 + fi + + if ! go run -msan -a msan2.go; then + echo "FAIL: msan2" + status=1 + fi + + if ! go run -msan msan3.go; then + echo "FAIL: msan3" + status=1 + fi + + if ! go run -msan msan4.go; then + echo "FAIL: msan4" + status=1 + fi + + if ! go run -msan msan5.go; then + echo "FAIL: msan5" + status=1 + fi + + if go run -msan msan_fail.go 2>/dev/null; then + echo "FAIL: msan_fail" + status=1 + fi + + testmsanshared +fi + +if test "$tsan" = "yes"; then + echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c + ok=yes + if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then + ok=no + fi + if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then + echo "skipping tsan tests: -fsanitize=thread not supported" + tsan=no + elif test "$ok" != "yes"; then + cat ${TMPDIR}/testsanitizers$$.err + echo "skipping tsan tests: -fsanitizer=thread build failed" + tsan=no + fi + rm -f ${TMPDIR}/testsanitizers$$* +fi + +# Run a TSAN test. +# $1 test name +# $2 environment variables +# $3 go run args +testtsan() { + err=${TMPDIR}/tsanerr$$.out + if ! env $2 go run $3 $1 2>$err; then + cat $err + echo "FAIL: $1" + status=1 + elif grep -i warning $err >/dev/null 2>&1; then + cat $err + echo "FAIL: $1" + status=1 + fi + rm -f $err +} + +if test "$tsan" = "yes"; then + testtsan tsan.go + testtsan tsan2.go + testtsan tsan3.go + testtsan tsan4.go + testtsan tsan8.go + testtsan tsan9.go + + # These tests are only reliable using clang or GCC version 7 or later. + # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use. + ok=false + if ${CC} --version | grep clang >/dev/null 2>&1; then + ok=true + else + ver=$($CC -dumpversion) + major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') + if test "$major" -lt 7; then + echo "skipping remaining TSAN tests: GCC version $major (older than 7)" + else + ok=true + fi + fi + + if test "$ok" = "true"; then + # This test requires rebuilding os/user with -fsanitize=thread. + testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + + # This test requires rebuilding runtime/cgo with -fsanitize=thread. + testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + + # This test requires rebuilding runtime/cgo with -fsanitize=thread. + testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + fi +fi + +exit $status diff --git a/libgo/misc/cgo/testsanitizers/tsan.go b/libgo/misc/cgo/testsanitizers/tsan.go new file mode 100644 index 00000000000..6c377a701fb --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan.go @@ -0,0 +1,44 @@ +// 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 + +// This program produced false race reports when run under the C/C++ +// ThreadSanitizer, as it did not understand the synchronization in +// the Go code. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +int val; + +int getVal() { + return val; +} + +void setVal(int i) { + val = i; +} +*/ +import "C" + +import ( + "runtime" +) + +func main() { + runtime.LockOSThread() + C.setVal(1) + c := make(chan bool) + go func() { + runtime.LockOSThread() + C.setVal(2) + c <- true + }() + <-c + if v := C.getVal(); v != 2 { + panic(v) + } +} diff --git a/libgo/misc/cgo/testsanitizers/tsan2.go b/libgo/misc/cgo/testsanitizers/tsan2.go new file mode 100644 index 00000000000..5018a1987ca --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan2.go @@ -0,0 +1,55 @@ +// 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 + +// This program produced false race reports when run under the C/C++ +// ThreadSanitizer, as it did not understand the synchronization in +// the Go code. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +extern void GoRun(void); + +// Yes, you can have definitions if you use //export, as long as they are weak. + +int val __attribute__ ((weak)); + +int run(void) __attribute__ ((weak)); + +int run() { + val = 1; + GoRun(); + return val; +} + +void setVal(int) __attribute__ ((weak)); + +void setVal(int i) { + val = i; +} +*/ +import "C" + +import "runtime" + +//export GoRun +func GoRun() { + runtime.LockOSThread() + c := make(chan bool) + go func() { + runtime.LockOSThread() + C.setVal(2) + c <- true + }() + <-c +} + +func main() { + if v := C.run(); v != 2 { + panic(v) + } +} diff --git a/libgo/misc/cgo/testsanitizers/tsan3.go b/libgo/misc/cgo/testsanitizers/tsan3.go new file mode 100644 index 00000000000..87f6c80f1b1 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan3.go @@ -0,0 +1,40 @@ +// 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 + +// The stubs for the C functions read and write the same slot on the +// g0 stack when copying arguments in and out. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +int Func1() { + return 0; +} + +void Func2(int x) { + (void)x; +} +*/ +import "C" + +func main() { + const N = 10000 + done := make(chan bool, N) + for i := 0; i < N; i++ { + go func() { + C.Func1() + done <- true + }() + go func() { + C.Func2(0) + done <- true + }() + } + for i := 0; i < 2*N; i++ { + <-done + } +} diff --git a/libgo/misc/cgo/testsanitizers/tsan4.go b/libgo/misc/cgo/testsanitizers/tsan4.go new file mode 100644 index 00000000000..f0c76d84116 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan4.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. + +package main + +// Check that calls to C.malloc/C.free do not trigger TSAN false +// positive reports. + +// #cgo CFLAGS: -fsanitize=thread +// #cgo LDFLAGS: -fsanitize=thread +// #include +import "C" + +import ( + "runtime" + "sync" +) + +func main() { + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + p := C.malloc(C.size_t(i * 10)) + runtime.Gosched() + C.free(p) + } + }() + } + wg.Wait() +} diff --git a/libgo/misc/cgo/testsanitizers/tsan5.go b/libgo/misc/cgo/testsanitizers/tsan5.go new file mode 100644 index 00000000000..1214a7743b6 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan5.go @@ -0,0 +1,51 @@ +// 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 + +// Check that calls to C.malloc/C.free do not collide with the calls +// made by the os/user package. + +// #cgo CFLAGS: -fsanitize=thread +// #cgo LDFLAGS: -fsanitize=thread +// #include +import "C" + +import ( + "fmt" + "os" + "os/user" + "runtime" + "sync" +) + +func main() { + u, err := user.Current() + if err != nil { + fmt.Fprintln(os.Stderr, err) + // Let the test pass. + os.Exit(0) + } + + var wg sync.WaitGroup + for i := 0; i < 20; i++ { + wg.Add(2) + go func() { + defer wg.Done() + for i := 0; i < 1000; i++ { + user.Lookup(u.Username) + runtime.Gosched() + } + }() + go func() { + defer wg.Done() + for i := 0; i < 1000; i++ { + p := C.malloc(C.size_t(len(u.Username) + 1)) + runtime.Gosched() + C.free(p) + } + }() + } + wg.Wait() +} diff --git a/libgo/misc/cgo/testsanitizers/tsan6.go b/libgo/misc/cgo/testsanitizers/tsan6.go new file mode 100644 index 00000000000..c96f08d2f37 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan6.go @@ -0,0 +1,49 @@ +// 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 + +// Check that writes to Go allocated memory, with Go synchronization, +// do not look like a race. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +void f(char *p) { + *p = 1; +} +*/ +import "C" + +import ( + "runtime" + "sync" +) + +func main() { + var wg sync.WaitGroup + var mu sync.Mutex + c := make(chan []C.char, 100) + for i := 0; i < 10; i++ { + wg.Add(2) + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + c <- make([]C.char, 4096) + runtime.Gosched() + } + }() + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + p := &(<-c)[0] + mu.Lock() + C.f(p) + mu.Unlock() + } + }() + } + wg.Wait() +} diff --git a/libgo/misc/cgo/testsanitizers/tsan7.go b/libgo/misc/cgo/testsanitizers/tsan7.go new file mode 100644 index 00000000000..2fb9e45ee2d --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan7.go @@ -0,0 +1,40 @@ +// 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 + +// Setting an environment variable in a cgo program changes the C +// environment. Test that this does not confuse the race detector. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread +*/ +import "C" + +import ( + "fmt" + "os" + "sync" + "time" +) + +func main() { + var wg sync.WaitGroup + var mu sync.Mutex + f := func() { + defer wg.Done() + for i := 0; i < 100; i++ { + time.Sleep(time.Microsecond) + mu.Lock() + s := fmt.Sprint(i) + os.Setenv("TSAN_TEST"+s, s) + mu.Unlock() + } + } + wg.Add(2) + go f() + go f() + wg.Wait() +} diff --git a/libgo/misc/cgo/testsanitizers/tsan8.go b/libgo/misc/cgo/testsanitizers/tsan8.go new file mode 100644 index 00000000000..88d82a60789 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan8.go @@ -0,0 +1,60 @@ +// 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 + +// This program failed when run under the C/C++ ThreadSanitizer. The TSAN +// sigaction function interceptor returned SIG_DFL instead of the Go runtime's +// handler in registerSegvForwarder. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +#include +#include +#include +#include + +struct sigaction prev_sa; + +void forwardSignal(int signo, siginfo_t *info, void *context) { + // One of sa_sigaction and/or sa_handler + if ((prev_sa.sa_flags&SA_SIGINFO) != 0) { + prev_sa.sa_sigaction(signo, info, context); + return; + } + if (prev_sa.sa_handler != SIG_IGN && prev_sa.sa_handler != SIG_DFL) { + prev_sa.sa_handler(signo); + return; + } + + fprintf(stderr, "No Go handler to forward to!\n"); + abort(); +} + +void registerSegvFowarder() { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + sa.sa_sigaction = forwardSignal; + + if (sigaction(SIGSEGV, &sa, &prev_sa) != 0) { + perror("failed to register SEGV forwarder"); + exit(EXIT_FAILURE); + } +} +*/ +import "C" + +func main() { + C.registerSegvFowarder() + + defer func() { + recover() + }() + var nilp *int + *nilp = 42 +} diff --git a/libgo/misc/cgo/testsanitizers/tsan9.go b/libgo/misc/cgo/testsanitizers/tsan9.go new file mode 100644 index 00000000000..f166d8b495a --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan9.go @@ -0,0 +1,67 @@ +// 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 + +// This program failed when run under the C/C++ ThreadSanitizer. The +// TSAN library was not keeping track of whether signals should be +// delivered on the alternate signal stack, and the Go signal handler +// was not preserving callee-saved registers from C callers. + +/* +#cgo CFLAGS: -g -fsanitize=thread +#cgo LDFLAGS: -g -fsanitize=thread + +#include +#include + +void spin() { + size_t n; + struct timeval tvstart, tvnow; + int diff; + void *prev = NULL, *cur; + + gettimeofday(&tvstart, NULL); + for (n = 0; n < 1<<20; n++) { + cur = malloc(n); + free(prev); + prev = cur; + + gettimeofday(&tvnow, NULL); + diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec); + + // Profile frequency is 100Hz so we should definitely + // get a signal in 50 milliseconds. + if (diff > 50 * 1000) { + break; + } + } + + free(prev); +} +*/ +import "C" + +import ( + "io/ioutil" + "runtime/pprof" + "time" +) + +func goSpin() { + start := time.Now() + for n := 0; n < 1<<20; n++ { + _ = make([]byte, n) + if time.Since(start) > 50*time.Millisecond { + break + } + } +} + +func main() { + pprof.StartCPUProfile(ioutil.Discard) + go C.spin() + goSpin() + pprof.StopCPUProfile() +} diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go new file mode 100644 index 00000000000..f0766e511ec --- /dev/null +++ b/libgo/misc/cgo/testshared/shared_test.go @@ -0,0 +1,828 @@ +// 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 shared_test + +import ( + "bufio" + "bytes" + "debug/elf" + "encoding/binary" + "errors" + "flag" + "fmt" + "go/build" + "io" + "io/ioutil" + "log" + "math/rand" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strings" + "testing" + "time" +) + +var gopathInstallDir, gorootInstallDir, suffix string + +// This is the smallest set of packages we can link into a shared +// library (runtime/cgo is built implicitly). +var minpkgs = []string{"runtime", "sync/atomic"} +var soname = "libruntime,sync-atomic.so" + +// run runs a command and calls t.Errorf if it fails. +func run(t *testing.T, msg string, args ...string) { + c := exec.Command(args[0], args[1:]...) + if output, err := c.CombinedOutput(); err != nil { + t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output) + } +} + +// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls +// t.Fatalf if the command fails. +func goCmd(t *testing.T, args ...string) { + newargs := []string{args[0], "-installsuffix=" + suffix} + if testing.Verbose() { + newargs = append(newargs, "-v") + } + newargs = append(newargs, args[1:]...) + c := exec.Command("go", newargs...) + var output []byte + var err error + if testing.Verbose() { + fmt.Printf("+ go %s\n", strings.Join(newargs, " ")) + c.Stdout = os.Stdout + c.Stderr = os.Stderr + err = c.Run() + } else { + output, err = c.CombinedOutput() + } + if err != nil { + if t != nil { + t.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output) + } else { + log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output) + } + } +} + +// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit). +func testMain(m *testing.M) (int, error) { + // Because go install -buildmode=shared $standard_library_package always + // installs into $GOROOT, here are some gymnastics to come up with a unique + // installsuffix to use in this test that we can clean up afterwards. + myContext := build.Default + runtimeP, err := myContext.Import("runtime", ".", build.ImportComment) + if err != nil { + return 0, fmt.Errorf("import failed: %v", err) + } + for i := 0; i < 10000; i++ { + try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63()) + err = os.Mkdir(try, 0700) + if os.IsExist(err) { + continue + } + if err == nil { + gorootInstallDir = try + } + break + } + if err != nil { + return 0, fmt.Errorf("can't create temporary directory: %v", err) + } + if gorootInstallDir == "" { + return 0, errors.New("could not create temporary directory after 10000 tries") + } + if testing.Verbose() { + fmt.Printf("+ mkdir -p %s\n", gorootInstallDir) + } + defer os.RemoveAll(gorootInstallDir) + + // Some tests need to edit the source in GOPATH, so copy this directory to a + // temporary directory and chdir to that. + scratchDir, err := ioutil.TempDir("", "testshared") + if err != nil { + return 0, fmt.Errorf("TempDir failed: %v", err) + } + if testing.Verbose() { + fmt.Printf("+ mkdir -p %s\n", scratchDir) + } + defer os.RemoveAll(scratchDir) + err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + scratchPath := filepath.Join(scratchDir, path) + if info.IsDir() { + if path == "." { + return nil + } + if testing.Verbose() { + fmt.Printf("+ mkdir -p %s\n", scratchPath) + } + return os.Mkdir(scratchPath, info.Mode()) + } else { + fromBytes, err := ioutil.ReadFile(path) + if err != nil { + return err + } + if testing.Verbose() { + fmt.Printf("+ cp %s %s\n", path, scratchPath) + } + return ioutil.WriteFile(scratchPath, fromBytes, info.Mode()) + } + }) + if err != nil { + return 0, fmt.Errorf("walk failed: %v", err) + } + os.Setenv("GOPATH", scratchDir) + if testing.Verbose() { + fmt.Printf("+ export GOPATH=%s\n", scratchDir) + } + myContext.GOPATH = scratchDir + if testing.Verbose() { + fmt.Printf("+ cd %s\n", scratchDir) + } + os.Chdir(scratchDir) + + // All tests depend on runtime being built into a shared library. Because + // that takes a few seconds, do it here and have all tests use the version + // built here. + suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2] + goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...) + + myContext.InstallSuffix = suffix + "_dynlink" + depP, err := myContext.Import("depBase", ".", build.ImportComment) + if err != nil { + return 0, fmt.Errorf("import failed: %v", err) + } + gopathInstallDir = depP.PkgTargetRoot + return m.Run(), nil +} + +func TestMain(m *testing.M) { + // Some of the tests install binaries into a custom GOPATH. + // That won't work if GOBIN is set. + os.Unsetenv("GOBIN") + + flag.Parse() + exitCode, err := testMain(m) + if err != nil { + log.Fatal(err) + } + os.Exit(exitCode) +} + +// The shared library was built at the expected location. +func TestSOBuilt(t *testing.T) { + _, err := os.Stat(filepath.Join(gorootInstallDir, soname)) + if err != nil { + t.Error(err) + } +} + +func hasDynTag(f *elf.File, tag elf.DynTag) bool { + ds := f.SectionByType(elf.SHT_DYNAMIC) + if ds == nil { + return false + } + d, err := ds.Data() + if err != nil { + return false + } + for len(d) > 0 { + var t elf.DynTag + switch f.Class { + case elf.ELFCLASS32: + t = elf.DynTag(f.ByteOrder.Uint32(d[0:4])) + d = d[8:] + case elf.ELFCLASS64: + t = elf.DynTag(f.ByteOrder.Uint64(d[0:8])) + d = d[16:] + } + if t == tag { + return true + } + } + return false +} + +// The shared library does not have relocations against the text segment. +func TestNoTextrel(t *testing.T) { + sopath := filepath.Join(gorootInstallDir, soname) + f, err := elf.Open(sopath) + if err != nil { + t.Fatal("elf.Open failed: ", err) + } + defer f.Close() + if hasDynTag(f, elf.DT_TEXTREL) { + t.Errorf("%s has DT_TEXTREL set", soname) + } +} + +// The shared library does not contain symbols called ".dup" +func TestNoDupSymbols(t *testing.T) { + sopath := filepath.Join(gorootInstallDir, soname) + f, err := elf.Open(sopath) + if err != nil { + t.Fatal("elf.Open failed: ", err) + } + defer f.Close() + syms, err := f.Symbols() + if err != nil { + t.Errorf("error reading symbols %v", err) + return + } + for _, s := range syms { + if s.Name == ".dup" { + t.Fatalf("%s contains symbol called .dup", sopath) + } + } +} + +// The install command should have created a "shlibname" file for the +// listed packages (and runtime/cgo, and math on arm) indicating the +// name of the shared library containing it. +func TestShlibnameFiles(t *testing.T) { + pkgs := append([]string{}, minpkgs...) + pkgs = append(pkgs, "runtime/cgo") + if runtime.GOARCH == "arm" { + pkgs = append(pkgs, "math") + } + for _, pkg := range pkgs { + shlibnamefile := filepath.Join(gorootInstallDir, pkg+".shlibname") + contentsb, err := ioutil.ReadFile(shlibnamefile) + if err != nil { + t.Errorf("error reading shlibnamefile for %s: %v", pkg, err) + continue + } + contents := strings.TrimSpace(string(contentsb)) + if contents != soname { + t.Errorf("shlibnamefile for %s has wrong contents: %q", pkg, contents) + } + } +} + +// Is a given offset into the file contained in a loaded segment? +func isOffsetLoaded(f *elf.File, offset uint64) bool { + for _, prog := range f.Progs { + if prog.Type == elf.PT_LOAD { + if prog.Off <= offset && offset < prog.Off+prog.Filesz { + return true + } + } + } + return false +} + +func rnd(v int32, r int32) int32 { + if r <= 0 { + return v + } + v += r - 1 + c := v % r + if c < 0 { + c += r + } + v -= c + return v +} + +func readwithpad(r io.Reader, sz int32) ([]byte, error) { + data := make([]byte, rnd(sz, 4)) + _, err := io.ReadFull(r, data) + if err != nil { + return nil, err + } + data = data[:sz] + return data, nil +} + +type note struct { + name string + tag int32 + desc string + section *elf.Section +} + +// Read all notes from f. As ELF section names are not supposed to be special, one +// looks for a particular note by scanning all SHT_NOTE sections looking for a note +// with a particular "name" and "tag". +func readNotes(f *elf.File) ([]*note, error) { + var notes []*note + for _, sect := range f.Sections { + if sect.Type != elf.SHT_NOTE { + continue + } + r := sect.Open() + for { + var namesize, descsize, tag int32 + err := binary.Read(r, f.ByteOrder, &namesize) + if err != nil { + if err == io.EOF { + break + } + return nil, fmt.Errorf("read namesize failed: %v", err) + } + err = binary.Read(r, f.ByteOrder, &descsize) + if err != nil { + return nil, fmt.Errorf("read descsize failed: %v", err) + } + err = binary.Read(r, f.ByteOrder, &tag) + if err != nil { + return nil, fmt.Errorf("read type failed: %v", err) + } + name, err := readwithpad(r, namesize) + if err != nil { + return nil, fmt.Errorf("read name failed: %v", err) + } + desc, err := readwithpad(r, descsize) + if err != nil { + return nil, fmt.Errorf("read desc failed: %v", err) + } + notes = append(notes, ¬e{name: string(name), tag: tag, desc: string(desc), section: sect}) + } + } + return notes, nil +} + +func dynStrings(t *testing.T, path string, flag elf.DynTag) []string { + f, err := elf.Open(path) + defer f.Close() + if err != nil { + t.Fatalf("elf.Open(%q) failed: %v", path, err) + } + dynstrings, err := f.DynString(flag) + if err != nil { + t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err) + } + return dynstrings +} + +func AssertIsLinkedToRegexp(t *testing.T, path string, re *regexp.Regexp) { + for _, dynstring := range dynStrings(t, path, elf.DT_NEEDED) { + if re.MatchString(dynstring) { + return + } + } + t.Errorf("%s is not linked to anything matching %v", path, re) +} + +func AssertIsLinkedTo(t *testing.T, path, lib string) { + AssertIsLinkedToRegexp(t, path, regexp.MustCompile(regexp.QuoteMeta(lib))) +} + +func AssertHasRPath(t *testing.T, path, dir string) { + for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} { + for _, dynstring := range dynStrings(t, path, tag) { + for _, rpath := range strings.Split(dynstring, ":") { + if filepath.Clean(rpath) == filepath.Clean(dir) { + return + } + } + } + } + t.Errorf("%s does not have rpath %s", path, dir) +} + +// Build a trivial program that links against the shared runtime and check it runs. +func TestTrivialExecutable(t *testing.T) { + goCmd(t, "install", "-linkshared", "trivial") + run(t, "trivial executable", "./bin/trivial") + AssertIsLinkedTo(t, "./bin/trivial", soname) + AssertHasRPath(t, "./bin/trivial", gorootInstallDir) +} + +// Build a trivial program in PIE mode that links against the shared runtime and check it runs. +func TestTrivialExecutablePIE(t *testing.T) { + goCmd(t, "build", "-buildmode=pie", "-o", "trivial.pie", "-linkshared", "trivial") + run(t, "trivial executable", "./trivial.pie") + AssertIsLinkedTo(t, "./trivial.pie", soname) + AssertHasRPath(t, "./trivial.pie", gorootInstallDir) +} + +// Build an executable that uses cgo linked against the shared runtime and check it +// runs. +func TestCgoExecutable(t *testing.T) { + goCmd(t, "install", "-linkshared", "execgo") + run(t, "cgo executable", "./bin/execgo") +} + +func checkPIE(t *testing.T, name string) { + f, err := elf.Open(name) + if err != nil { + t.Fatal("elf.Open failed: ", err) + } + defer f.Close() + if f.Type != elf.ET_DYN { + t.Errorf("%s has type %v, want ET_DYN", name, f.Type) + } + if hasDynTag(f, elf.DT_TEXTREL) { + t.Errorf("%s has DT_TEXTREL set", name) + } +} + +func TestTrivialPIE(t *testing.T) { + name := "trivial_pie" + goCmd(t, "build", "-buildmode=pie", "-o="+name, "trivial") + defer os.Remove(name) + run(t, name, "./"+name) + checkPIE(t, name) +} + +func TestCgoPIE(t *testing.T) { + name := "cgo_pie" + goCmd(t, "build", "-buildmode=pie", "-o="+name, "execgo") + defer os.Remove(name) + run(t, name, "./"+name) + checkPIE(t, name) +} + +// Build a GOPATH package into a shared library that links against the goroot runtime +// and an executable that links against both. +func TestGopathShlib(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdepBase.so"), soname) + goCmd(t, "install", "-linkshared", "exe") + AssertIsLinkedTo(t, "./bin/exe", soname) + AssertIsLinkedTo(t, "./bin/exe", "libdepBase.so") + AssertHasRPath(t, "./bin/exe", gorootInstallDir) + AssertHasRPath(t, "./bin/exe", gopathInstallDir) + // And check it runs. + run(t, "executable linked to GOPATH library", "./bin/exe") +} + +// The shared library contains a note listing the packages it contains in a section +// that is not mapped into memory. +func testPkgListNote(t *testing.T, f *elf.File, note *note) { + if note.section.Flags != 0 { + t.Errorf("package list section has flags %v", note.section.Flags) + } + if isOffsetLoaded(f, note.section.Offset) { + t.Errorf("package list section contained in PT_LOAD segment") + } + if note.desc != "depBase\n" { + t.Errorf("incorrect package list %q", note.desc) + } +} + +// The shared library contains a note containing the ABI hash that is mapped into +// memory and there is a local symbol called go.link.abihashbytes that points 16 +// bytes into it. +func testABIHashNote(t *testing.T, f *elf.File, note *note) { + if note.section.Flags != elf.SHF_ALLOC { + t.Errorf("abi hash section has flags %v", note.section.Flags) + } + if !isOffsetLoaded(f, note.section.Offset) { + t.Errorf("abihash section not contained in PT_LOAD segment") + } + var hashbytes elf.Symbol + symbols, err := f.Symbols() + if err != nil { + t.Errorf("error reading symbols %v", err) + return + } + for _, sym := range symbols { + if sym.Name == "go.link.abihashbytes" { + hashbytes = sym + } + } + if hashbytes.Name == "" { + t.Errorf("no symbol called go.link.abihashbytes") + return + } + if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL { + t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info)) + } + if f.Sections[hashbytes.Section] != note.section { + t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name) + } + if hashbytes.Value-note.section.Addr != 16 { + t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr) + } +} + +// A Go shared library contains a note indicating which other Go shared libraries it +// was linked against in an unmapped section. +func testDepsNote(t *testing.T, f *elf.File, note *note) { + if note.section.Flags != 0 { + t.Errorf("package list section has flags %v", note.section.Flags) + } + if isOffsetLoaded(f, note.section.Offset) { + t.Errorf("package list section contained in PT_LOAD segment") + } + // libdepBase.so just links against the lib containing the runtime. + if note.desc != soname { + t.Errorf("incorrect dependency list %q", note.desc) + } +} + +// The shared library contains notes with defined contents; see above. +func TestNotes(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + f, err := elf.Open(filepath.Join(gopathInstallDir, "libdepBase.so")) + if err != nil { + t.Fatal(err) + } + defer f.Close() + notes, err := readNotes(f) + if err != nil { + t.Fatal(err) + } + pkgListNoteFound := false + abiHashNoteFound := false + depsNoteFound := false + for _, note := range notes { + if note.name != "Go\x00\x00" { + continue + } + switch note.tag { + case 1: // ELF_NOTE_GOPKGLIST_TAG + if pkgListNoteFound { + t.Error("multiple package list notes") + } + testPkgListNote(t, f, note) + pkgListNoteFound = true + case 2: // ELF_NOTE_GOABIHASH_TAG + if abiHashNoteFound { + t.Error("multiple abi hash notes") + } + testABIHashNote(t, f, note) + abiHashNoteFound = true + case 3: // ELF_NOTE_GODEPS_TAG + if depsNoteFound { + t.Error("multiple abi hash notes") + } + testDepsNote(t, f, note) + depsNoteFound = true + } + } + if !pkgListNoteFound { + t.Error("package list note not found") + } + if !abiHashNoteFound { + t.Error("abi hash note not found") + } + if !depsNoteFound { + t.Error("deps note not found") + } +} + +// Build a GOPATH package (depBase) into a shared library that links against the goroot +// runtime, another package (dep2) that links against the first, and and an +// executable that links against dep2. +func TestTwoGopathShlibs(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2") + goCmd(t, "install", "-linkshared", "exe2") + run(t, "executable linked to GOPATH library", "./bin/exe2") +} + +func TestThreeGopathShlibs(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep3") + goCmd(t, "install", "-linkshared", "exe3") + run(t, "executable linked to GOPATH library", "./bin/exe3") +} + +// If gccgo is not available or not new enough call t.Skip. Otherwise, +// return a build.Context that is set up for gccgo. +func prepGccgo(t *testing.T) build.Context { + gccgoName := os.Getenv("GCCGO") + if gccgoName == "" { + gccgoName = "gccgo" + } + gccgoPath, err := exec.LookPath(gccgoName) + if err != nil { + t.Skip("gccgo not found") + } + cmd := exec.Command(gccgoPath, "-dumpversion") + output, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%s -dumpversion failed: %v\n%s", gccgoPath, err, output) + } + if string(output) < "5" { + t.Skipf("gccgo too old (%s)", strings.TrimSpace(string(output))) + } + gccgoContext := build.Default + gccgoContext.InstallSuffix = suffix + "_fPIC" + gccgoContext.Compiler = "gccgo" + gccgoContext.GOPATH = os.Getenv("GOPATH") + return gccgoContext +} + +// Build a GOPATH package into a shared library with gccgo and an executable that +// links against it. +func TestGoPathShlibGccgo(t *testing.T) { + gccgoContext := prepGccgo(t) + + libgoRE := regexp.MustCompile("libgo.so.[0-9]+") + + depP, err := gccgoContext.Import("depBase", ".", build.ImportComment) + if err != nil { + t.Fatalf("import failed: %v", err) + } + gccgoInstallDir := filepath.Join(depP.PkgTargetRoot, "shlibs") + goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "depBase") + AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdepBase.so"), libgoRE) + goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe") + AssertIsLinkedToRegexp(t, "./bin/exe", libgoRE) + AssertIsLinkedTo(t, "./bin/exe", "libdepBase.so") + AssertHasRPath(t, "./bin/exe", gccgoInstallDir) + // And check it runs. + run(t, "gccgo-built", "./bin/exe") +} + +// The gccgo version of TestTwoGopathShlibs: build a GOPATH package into a shared +// library with gccgo, another GOPATH package that depends on the first and an +// executable that links the second library. +func TestTwoGopathShlibsGccgo(t *testing.T) { + gccgoContext := prepGccgo(t) + + libgoRE := regexp.MustCompile("libgo.so.[0-9]+") + + depP, err := gccgoContext.Import("depBase", ".", build.ImportComment) + if err != nil { + t.Fatalf("import failed: %v", err) + } + gccgoInstallDir := filepath.Join(depP.PkgTargetRoot, "shlibs") + goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "depBase") + goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep2") + goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe2") + + AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdepBase.so"), libgoRE) + AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep2.so"), libgoRE) + AssertIsLinkedTo(t, filepath.Join(gccgoInstallDir, "libdep2.so"), "libdepBase.so") + AssertIsLinkedToRegexp(t, "./bin/exe2", libgoRE) + AssertIsLinkedTo(t, "./bin/exe2", "libdep2") + AssertIsLinkedTo(t, "./bin/exe2", "libdepBase.so") + + // And check it runs. + run(t, "gccgo-built", "./bin/exe2") +} + +// Testing rebuilding of shared libraries when they are stale is a bit more +// complicated that it seems like it should be. First, we make everything "old": but +// only a few seconds old, or it might be older than gc (or the runtime source) and +// everything will get rebuilt. Then define a timestamp slightly newer than this +// time, which is what we set the mtime to of a file to cause it to be seen as new, +// and finally another slightly even newer one that we can compare files against to +// see if they have been rebuilt. +var oldTime = time.Now().Add(-9 * time.Second) +var nearlyNew = time.Now().Add(-6 * time.Second) +var stampTime = time.Now().Add(-3 * time.Second) + +// resetFileStamps makes "everything" (bin, src, pkg from GOPATH and the +// test-specific parts of GOROOT) appear old. +func resetFileStamps() { + chtime := func(path string, info os.FileInfo, err error) error { + return os.Chtimes(path, oldTime, oldTime) + } + reset := func(path string) { + if err := filepath.Walk(path, chtime); err != nil { + log.Fatalf("resetFileStamps failed: %v", err) + } + + } + reset("bin") + reset("pkg") + reset("src") + reset(gorootInstallDir) +} + +// touch makes path newer than the "old" time stamp used by resetFileStamps. +func touch(path string) { + if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil { + log.Fatalf("os.Chtimes failed: %v", err) + } +} + +// isNew returns if the path is newer than the time stamp used by touch. +func isNew(path string) bool { + fi, err := os.Stat(path) + if err != nil { + log.Fatalf("os.Stat failed: %v", err) + } + return fi.ModTime().After(stampTime) +} + +// Fail unless path has been rebuilt (i.e. is newer than the time stamp used by +// isNew) +func AssertRebuilt(t *testing.T, msg, path string) { + if !isNew(path) { + t.Errorf("%s was not rebuilt (%s)", msg, path) + } +} + +// Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew) +func AssertNotRebuilt(t *testing.T, msg, path string) { + if isNew(path) { + t.Errorf("%s was rebuilt (%s)", msg, path) + } +} + +func TestRebuilding(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + goCmd(t, "install", "-linkshared", "exe") + + // If the source is newer than both the .a file and the .so, both are rebuilt. + resetFileStamps() + touch("src/depBase/dep.go") + goCmd(t, "install", "-linkshared", "exe") + AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "depBase.a")) + AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdepBase.so")) + + // If the .a file is newer than the .so, the .so is rebuilt (but not the .a) + resetFileStamps() + touch(filepath.Join(gopathInstallDir, "depBase.a")) + goCmd(t, "install", "-linkshared", "exe") + AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "depBase.a")) + AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdepBase.so")) +} + +func appendFile(path, content string) { + f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660) + if err != nil { + log.Fatalf("os.OpenFile failed: %v", err) + } + defer func() { + err := f.Close() + if err != nil { + log.Fatalf("f.Close failed: %v", err) + } + }() + _, err = f.WriteString(content) + if err != nil { + log.Fatalf("f.WriteString failed: %v", err) + } +} + +func TestABIChecking(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + goCmd(t, "install", "-linkshared", "exe") + + // If we make an ABI-breaking change to depBase and rebuild libp.so but not exe, + // exe will abort with a complaint on startup. + // This assumes adding an exported function breaks ABI, which is not true in + // some senses but suffices for the narrow definition of ABI compatibility the + // toolchain uses today. + resetFileStamps() + appendFile("src/depBase/dep.go", "func ABIBreak() {}\n") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + c := exec.Command("./bin/exe") + output, err := c.CombinedOutput() + if err == nil { + t.Fatal("executing exe did not fail after ABI break") + } + scanner := bufio.NewScanner(bytes.NewReader(output)) + foundMsg := false + const wantLine = "abi mismatch detected between the executable and libdepBase.so" + for scanner.Scan() { + if scanner.Text() == wantLine { + foundMsg = true + break + } + } + if err = scanner.Err(); err != nil { + t.Errorf("scanner encountered error: %v", err) + } + if !foundMsg { + t.Fatalf("exe failed, but without line %q; got output:\n%s", wantLine, output) + } + + // Rebuilding exe makes it work again. + goCmd(t, "install", "-linkshared", "exe") + run(t, "rebuilt exe", "./bin/exe") + + // If we make a change which does not break ABI (such as adding an unexported + // function) and rebuild libdepBase.so, exe still works. + resetFileStamps() + appendFile("src/depBase/dep.go", "func noABIBreak() {}\n") + goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") + run(t, "after non-ABI breaking change", "./bin/exe") +} + +// If a package 'explicit' imports a package 'implicit', building +// 'explicit' into a shared library implicitly includes implicit in +// the shared library. Building an executable that imports both +// explicit and implicit builds the code from implicit into the +// executable rather than fetching it from the shared library. The +// link still succeeds and the executable still runs though. +func TestImplicitInclusion(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "explicit") + goCmd(t, "install", "-linkshared", "implicitcmd") + run(t, "running executable linked against library that contains same package as it", "./bin/implicitcmd") +} + +// Tests to make sure that the type fields of empty interfaces and itab +// fields of nonempty interfaces are unique even across modules, +// so that interface equality works correctly. +func TestInterface(t *testing.T) { + goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_a") + // Note: iface_i gets installed implicitly as a dependency of iface_a. + goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_b") + goCmd(t, "install", "-linkshared", "iface") + run(t, "running type/itab uniqueness tester", "./bin/iface") +} diff --git a/libgo/misc/cgo/testshared/src/dep2/dep2.go b/libgo/misc/cgo/testshared/src/dep2/dep2.go new file mode 100644 index 00000000000..c2c812adb9b --- /dev/null +++ b/libgo/misc/cgo/testshared/src/dep2/dep2.go @@ -0,0 +1,15 @@ +package dep2 + +import "depBase" + +var W int = 1 + +var hasProg depBase.HasProg + +type Dep2 struct { + depBase.Dep +} + +func G() int { + return depBase.F() + 1 +} diff --git a/libgo/misc/cgo/testshared/src/dep3/dep3.go b/libgo/misc/cgo/testshared/src/dep3/dep3.go new file mode 100644 index 00000000000..7b7c9dac1f9 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/dep3/dep3.go @@ -0,0 +1,22 @@ +package dep3 + +// The point of this test file is that it references a type from +// depBase that is also referenced in dep2, but dep2 is loaded by the +// linker before depBase (because it is earlier in the import list). +// There was a bug in the linker where it would not correctly read out +// the type data in this case and later crash. + +import ( + "dep2" + "depBase" +) + +type Dep3 struct { + dep depBase.Dep + dep2 dep2.Dep2 +} + +func D3() int { + var x Dep3 + return x.dep.X + x.dep2.X +} diff --git a/libgo/misc/cgo/testshared/src/depBase/asm.s b/libgo/misc/cgo/testshared/src/depBase/asm.s new file mode 100644 index 00000000000..f203f8b0301 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/depBase/asm.s @@ -0,0 +1,10 @@ +// 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. + +//+build !gccgo + +#include "textflag.h" + +TEXT ·ImplementedInAsm(SB),NOSPLIT,$0-0 + RET diff --git a/libgo/misc/cgo/testshared/src/depBase/dep.go b/libgo/misc/cgo/testshared/src/depBase/dep.go new file mode 100644 index 00000000000..9f86710db01 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/depBase/dep.go @@ -0,0 +1,33 @@ +package depBase + +import ( + "os" + "reflect" +) + +var SlicePtr interface{} = &[]int{} + +var V int = 1 + +var HasMask []string = []string{"hi"} + +type HasProg struct { + array [1024]*byte +} + +type Dep struct { + X int +} + +func (d *Dep) Method() int { + // This code below causes various go.itab.* symbols to be generated in + // the shared library. Similar code in ../exe/exe.go results in + // exercising https://github.com/golang/go/issues/17594 + reflect.TypeOf(os.Stdout).Elem() + return 10 +} + +func F() int { + defer func() {}() + return V +} diff --git a/libgo/misc/cgo/testshared/src/depBase/gccgo.go b/libgo/misc/cgo/testshared/src/depBase/gccgo.go new file mode 100644 index 00000000000..3e2b69b50bc --- /dev/null +++ b/libgo/misc/cgo/testshared/src/depBase/gccgo.go @@ -0,0 +1,5 @@ +//+build gccgo + +package depBase + +func ImplementedInAsm() {} diff --git a/libgo/misc/cgo/testshared/src/depBase/stubs.go b/libgo/misc/cgo/testshared/src/depBase/stubs.go new file mode 100644 index 00000000000..96573c12ece --- /dev/null +++ b/libgo/misc/cgo/testshared/src/depBase/stubs.go @@ -0,0 +1,5 @@ +//+build !gccgo + +package depBase + +func ImplementedInAsm() diff --git a/libgo/misc/cgo/testshared/src/exe/exe.go b/libgo/misc/cgo/testshared/src/exe/exe.go new file mode 100644 index 00000000000..84302a811f0 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/exe/exe.go @@ -0,0 +1,44 @@ +package main + +import ( + "depBase" + "os" + "reflect" + "runtime" +) + +// Having a function declared in the main package triggered +// golang.org/issue/18250 +func DeclaredInMain() { +} + +type C struct { +} + +func F() *C { + return nil +} + +var slicePtr interface{} = &[]int{} + +func main() { + defer depBase.ImplementedInAsm() + // This code below causes various go.itab.* symbols to be generated in + // the executable. Similar code in ../depBase/dep.go results in + // exercising https://github.com/golang/go/issues/17594 + reflect.TypeOf(os.Stdout).Elem() + runtime.GC() + depBase.V = depBase.F() + 1 + + var c *C + if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) { + panic("bad reflection results, see golang.org/issue/18252") + } + + sp := reflect.New(reflect.TypeOf(slicePtr).Elem()) + s := sp.Interface() + + if reflect.TypeOf(s) != reflect.TypeOf(slicePtr) { + panic("bad reflection results, see golang.org/issue/18729") + } +} diff --git a/libgo/misc/cgo/testshared/src/exe2/exe2.go b/libgo/misc/cgo/testshared/src/exe2/exe2.go new file mode 100644 index 00000000000..675fd1f365c --- /dev/null +++ b/libgo/misc/cgo/testshared/src/exe2/exe2.go @@ -0,0 +1,8 @@ +package main + +import "dep2" + +func main() { + d := &dep2.Dep2{} + dep2.W = dep2.G() + 1 + d.Method() +} diff --git a/libgo/misc/cgo/testshared/src/exe3/exe3.go b/libgo/misc/cgo/testshared/src/exe3/exe3.go new file mode 100644 index 00000000000..643f2605f66 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/exe3/exe3.go @@ -0,0 +1,7 @@ +package main + +import "dep3" + +func main() { + dep3.D3() +} diff --git a/libgo/misc/cgo/testshared/src/execgo/exe.go b/libgo/misc/cgo/testshared/src/execgo/exe.go new file mode 100644 index 00000000000..0427be8bdfd --- /dev/null +++ b/libgo/misc/cgo/testshared/src/execgo/exe.go @@ -0,0 +1,8 @@ +package main + +/* + */ +import "C" + +func main() { +} diff --git a/libgo/misc/cgo/testshared/src/explicit/explicit.go b/libgo/misc/cgo/testshared/src/explicit/explicit.go new file mode 100644 index 00000000000..6a4453f7758 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/explicit/explicit.go @@ -0,0 +1,9 @@ +package explicit + +import ( + "implicit" +) + +func E() int { + return implicit.I() +} diff --git a/libgo/misc/cgo/testshared/src/iface/main.go b/libgo/misc/cgo/testshared/src/iface/main.go new file mode 100644 index 00000000000..3d5b54e73b9 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/iface/main.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 "iface_a" +import "iface_b" + +func main() { + if iface_a.F() != iface_b.F() { + panic("empty interfaces not equal") + } + if iface_a.G() != iface_b.G() { + panic("non-empty interfaces not equal") + } +} diff --git a/libgo/misc/cgo/testshared/src/iface_a/a.go b/libgo/misc/cgo/testshared/src/iface_a/a.go new file mode 100644 index 00000000000..e11047c166c --- /dev/null +++ b/libgo/misc/cgo/testshared/src/iface_a/a.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 iface_a + +import "iface_i" + +//go:noinline +func F() interface{} { + return (*iface_i.T)(nil) +} + +//go:noinline +func G() iface_i.I { + return (*iface_i.T)(nil) +} diff --git a/libgo/misc/cgo/testshared/src/iface_b/b.go b/libgo/misc/cgo/testshared/src/iface_b/b.go new file mode 100644 index 00000000000..47aee2e77ee --- /dev/null +++ b/libgo/misc/cgo/testshared/src/iface_b/b.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 iface_b + +import "iface_i" + +//go:noinline +func F() interface{} { + return (*iface_i.T)(nil) +} + +//go:noinline +func G() iface_i.I { + return (*iface_i.T)(nil) +} diff --git a/libgo/misc/cgo/testshared/src/iface_i/i.go b/libgo/misc/cgo/testshared/src/iface_i/i.go new file mode 100644 index 00000000000..31c80387c7e --- /dev/null +++ b/libgo/misc/cgo/testshared/src/iface_i/i.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 iface_i + +type I interface { + M() +} + +type T struct { +} + +func (t *T) M() { +} + +// *T implements I diff --git a/libgo/misc/cgo/testshared/src/implicit/implicit.go b/libgo/misc/cgo/testshared/src/implicit/implicit.go new file mode 100644 index 00000000000..5360188c562 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/implicit/implicit.go @@ -0,0 +1,5 @@ +package implicit + +func I() int { + return 42 +} diff --git a/libgo/misc/cgo/testshared/src/implicitcmd/implicitcmd.go b/libgo/misc/cgo/testshared/src/implicitcmd/implicitcmd.go new file mode 100644 index 00000000000..f6112933e56 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/implicitcmd/implicitcmd.go @@ -0,0 +1,10 @@ +package main + +import ( + "explicit" + "implicit" +) + +func main() { + println(implicit.I() + explicit.E()) +} diff --git a/libgo/misc/cgo/testshared/src/trivial/trivial.go b/libgo/misc/cgo/testshared/src/trivial/trivial.go new file mode 100644 index 00000000000..da29a2cadf1 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/trivial/trivial.go @@ -0,0 +1,4 @@ +package main + +func main() { +} diff --git a/libgo/misc/cgo/testsigfwd/main.go b/libgo/misc/cgo/testsigfwd/main.go new file mode 100644 index 00000000000..61bd0da88a8 --- /dev/null +++ b/libgo/misc/cgo/testsigfwd/main.go @@ -0,0 +1,113 @@ +// 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 + +import "fmt" + +/* +#cgo CFLAGS: -pthread +#cgo LDFLAGS: -pthread + +#include +#include +#include +#include +#include + +int *p; +static void sigsegv() { + *p = 1; + fprintf(stderr, "ERROR: C SIGSEGV not thrown on caught?.\n"); + exit(2); +} + +static void segvhandler(int signum) { + if (signum == SIGSEGV) { + exit(0); // success + } +} + +static volatile sig_atomic_t sigioSeen; + +// Use up some stack space. +static void recur(int i, char *p) { + char a[1024]; + + *p = '\0'; + if (i > 0) { + recur(i - 1, a); + } +} + +static void iohandler(int signum) { + char a[1024]; + + recur(4, a); + sigioSeen = 1; +} + +static void* sigioThread(void* arg __attribute__ ((unused))) { + raise(SIGIO); + return NULL; +} + +static void sigioOnThread() { + pthread_t tid; + int i; + + pthread_create(&tid, NULL, sigioThread, NULL); + pthread_join(tid, NULL); + + // Wait until the signal has been delivered. + i = 0; + while (!sigioSeen) { + if (sched_yield() < 0) { + perror("sched_yield"); + } + i++; + if (i > 10000) { + fprintf(stderr, "looping too long waiting for signal\n"); + exit(EXIT_FAILURE); + } + } +} + +static void __attribute__ ((constructor)) sigsetup(void) { + struct sigaction act; + + memset(&act, 0, sizeof act); + act.sa_handler = segvhandler; + sigaction(SIGSEGV, &act, NULL); + + act.sa_handler = iohandler; + sigaction(SIGIO, &act, NULL); +} +*/ +import "C" + +var p *byte + +func f() (ret bool) { + defer func() { + if recover() == nil { + fmt.Errorf("ERROR: couldn't raise SIGSEGV in Go.") + C.exit(2) + } + ret = true + }() + *p = 1 + return false +} + +func main() { + // Test that the signal originating in Go is handled (and recovered) by Go. + if !f() { + fmt.Errorf("couldn't recover from SIGSEGV in Go.") + C.exit(2) + } + + // Test that the signal originating in C is handled by C. + C.sigsegv() +} diff --git a/libgo/misc/cgo/testso/cgoso.c b/libgo/misc/cgo/testso/cgoso.c new file mode 100644 index 00000000000..917f472d368 --- /dev/null +++ b/libgo/misc/cgo/testso/cgoso.c @@ -0,0 +1,14 @@ +// 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. + +#include "_cgo_export.h" + +#ifdef WIN32 +extern void setCallback(void *); +void init() { + setCallback(goCallback); +} +#else +void init() {} +#endif diff --git a/libgo/misc/cgo/testso/cgoso.go b/libgo/misc/cgo/testso/cgoso.go new file mode 100644 index 00000000000..29814fa43ae --- /dev/null +++ b/libgo/misc/cgo/testso/cgoso.go @@ -0,0 +1,31 @@ +// Copyright 2011 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 cgosotest + +/* +// intentionally write the same LDFLAGS differently +// to test correct handling of LDFLAGS. +#cgo linux LDFLAGS: -L. -lcgosotest +#cgo dragonfly LDFLAGS: -L. -l cgosotest +#cgo freebsd LDFLAGS: -L. -l cgosotest +#cgo openbsd LDFLAGS: -L. -l cgosotest +#cgo solaris LDFLAGS: -L. -lcgosotest +#cgo netbsd LDFLAGS: -L. libcgosotest.so +#cgo darwin LDFLAGS: -L. libcgosotest.dylib +#cgo windows LDFLAGS: -L. libcgosotest.dll + +void init(void); +void sofunc(void); +*/ +import "C" + +func Test() { + C.init() + C.sofunc() +} + +//export goCallback +func goCallback() { +} diff --git a/libgo/misc/cgo/testso/cgoso_c.c b/libgo/misc/cgo/testso/cgoso_c.c new file mode 100644 index 00000000000..7a38022b547 --- /dev/null +++ b/libgo/misc/cgo/testso/cgoso_c.c @@ -0,0 +1,30 @@ +// Copyright 2011 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. + +// +build ignore + +#ifdef WIN32 +// A Windows DLL is unable to call an arbitrary function in +// the main executable. Work around that by making the main +// executable pass the callback function pointer to us. +void (*goCallback)(void); +__declspec(dllexport) void setCallback(void *f) +{ + goCallback = (void (*)())f; +} +__declspec(dllexport) void sofunc(void); +#else +extern void goCallback(void); +void setCallback(void *f) { (void)f; } +#endif + +// OpenBSD and older Darwin lack TLS support +#if !defined(__OpenBSD__) && !defined(__APPLE__) +__thread int tlsvar = 12345; +#endif + +void sofunc(void) +{ + goCallback(); +} diff --git a/libgo/misc/cgo/testso/cgoso_unix.go b/libgo/misc/cgo/testso/cgoso_unix.go new file mode 100644 index 00000000000..49cdeaa2f59 --- /dev/null +++ b/libgo/misc/cgo/testso/cgoso_unix.go @@ -0,0 +1,20 @@ +// 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. + +// +build dragonfly freebsd linux netbsd solaris + +package cgosotest + +/* +extern int __thread tlsvar; +int *getTLS() { return &tlsvar; } +*/ +import "C" + +func init() { + if v := *C.getTLS(); v != 12345 { + println("got", v) + panic("BAD TLS value") + } +} diff --git a/libgo/misc/cgo/testso/main.go b/libgo/misc/cgo/testso/main.go new file mode 100644 index 00000000000..88aa4322d24 --- /dev/null +++ b/libgo/misc/cgo/testso/main.go @@ -0,0 +1,13 @@ +// Copyright 2011 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. + +// +build ignore + +package main + +import "." + +func main() { + cgosotest.Test() +} diff --git a/libgo/misc/cgo/testsovar/cgoso.go b/libgo/misc/cgo/testsovar/cgoso.go new file mode 100644 index 00000000000..88d44c2c6ee --- /dev/null +++ b/libgo/misc/cgo/testsovar/cgoso.go @@ -0,0 +1,43 @@ +// 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 cgosotest + +// This test verifies that Go can access C variables +// in shared object file via cgo. + +/* +// intentionally write the same LDFLAGS differently +// to test correct handling of LDFLAGS. +#cgo windows CFLAGS: -DIMPORT_DLL +#cgo linux LDFLAGS: -L. -lcgosotest +#cgo dragonfly LDFLAGS: -L. -l cgosotest +#cgo freebsd LDFLAGS: -L. -l cgosotest +#cgo openbsd LDFLAGS: -L. -l cgosotest +#cgo solaris LDFLAGS: -L. -lcgosotest +#cgo netbsd LDFLAGS: -L. libcgosotest.so +#cgo darwin LDFLAGS: -L. libcgosotest.dylib +#cgo windows LDFLAGS: -L. libcgosotest.dll + +#include "cgoso_c.h" + +const char* getVar() { + return exported_var; +} +*/ +import "C" + +import "fmt" + +func Test() { + const want = "Hello world" + got := C.GoString(C.getVar()) + if got != want { + panic(fmt.Sprintf("testExportedVar: got %q, but want %q", got, want)) + } + got = C.GoString(C.exported_var) + if got != want { + panic(fmt.Sprintf("testExportedVar: got %q, but want %q", got, want)) + } +} diff --git a/libgo/misc/cgo/testsovar/cgoso_c.c b/libgo/misc/cgo/testsovar/cgoso_c.c new file mode 100644 index 00000000000..a448c013428 --- /dev/null +++ b/libgo/misc/cgo/testsovar/cgoso_c.c @@ -0,0 +1,7 @@ +// 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. + +// +build ignore + +const char *exported_var = "Hello world"; diff --git a/libgo/misc/cgo/testsovar/cgoso_c.h b/libgo/misc/cgo/testsovar/cgoso_c.h new file mode 100644 index 00000000000..640db7b396a --- /dev/null +++ b/libgo/misc/cgo/testsovar/cgoso_c.h @@ -0,0 +1,17 @@ +// 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. + +// +build ignore + +#ifdef WIN32 +#if defined(EXPORT_DLL) +# define VAR __declspec(dllexport) +#elif defined(IMPORT_DLL) +# define VAR __declspec(dllimport) +#endif +#else +# define VAR extern +#endif + +VAR const char *exported_var; diff --git a/libgo/misc/cgo/testsovar/main.go b/libgo/misc/cgo/testsovar/main.go new file mode 100644 index 00000000000..9c8a1c4e66e --- /dev/null +++ b/libgo/misc/cgo/testsovar/main.go @@ -0,0 +1,13 @@ +// 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. + +// +build ignore + +package main + +import "." + +func main() { + cgosotest.Test() +} diff --git a/libgo/misc/cgo/testtls/tls.go b/libgo/misc/cgo/testtls/tls.go new file mode 100644 index 00000000000..e634220be7c --- /dev/null +++ b/libgo/misc/cgo/testtls/tls.go @@ -0,0 +1,30 @@ +// 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 cgotlstest + +// #include +// extern void setTLS(int); +// extern int getTLS(); +import "C" + +import ( + "runtime" + "testing" +) + +func testTLS(t *testing.T) { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if val := C.getTLS(); val != 0 { + t.Fatalf("at start, C.getTLS() = %#x, want 0", val) + } + + const keyVal = 0x1234 + C.setTLS(keyVal) + if val := C.getTLS(); val != keyVal { + t.Fatalf("at end, C.getTLS() = %#x, want %#x", val, keyVal) + } +} diff --git a/libgo/misc/cgo/testtls/tls_test.go b/libgo/misc/cgo/testtls/tls_test.go new file mode 100644 index 00000000000..3076c2d5943 --- /dev/null +++ b/libgo/misc/cgo/testtls/tls_test.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. + +// +build !windows + +package cgotlstest + +import "testing" + +func TestTLS(t *testing.T) { + testTLS(t) +} diff --git a/libgo/misc/cgo/testtls/tls_unix.c b/libgo/misc/cgo/testtls/tls_unix.c new file mode 100644 index 00000000000..957afce90d4 --- /dev/null +++ b/libgo/misc/cgo/testtls/tls_unix.c @@ -0,0 +1,19 @@ +// 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. + +#include + +static __thread int tls; + +void +setTLS(int v) +{ + tls = v; +} + +int +getTLS() +{ + return tls; +}