Commit 93661575 by Ian Lance Taylor

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
parent 9913ef58
bfb18fb16194826bf2bf2d7af873719ddb5e8e42 040dc31406d580e33f82e578a840600fea5004ef
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -182,6 +182,13 @@ done ...@@ -182,6 +182,13 @@ done
done 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 (cd ${OLDDIR}/src && find . -name '*.go' -print) | while read f; do
oldfile=${OLDDIR}/src/$f oldfile=${OLDDIR}/src/$f
newfile=${NEWDIR}/src/$f newfile=${NEWDIR}/src/$f
...@@ -197,5 +204,20 @@ done ...@@ -197,5 +204,20 @@ done
git rm ${libgofile} git rm ${libgofile}
done 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 (echo ${new_rev}; sed -ne '2,$p' MERGE) > MERGE.tmp
mv MERGE.tmp MERGE mv MERGE.tmp MERGE
// 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()
}
// 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
}
// 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
}
// 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
}
// 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
}
// 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
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// #include <stdio.h>
import "C"
func main() {
_ = C.fopen() // ERROR HERE
}
// 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
)
}
// 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)
}
// 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,
}
}
// 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
}
// 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
}
// 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
}
// 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)
}
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that C.malloc does not return nil.
package main
// #include <stdlib.h>
import "C"
import (
"fmt"
"runtime"
)
func main() {
var size C.size_t
size--
// The Dragonfly libc succeeds when asked to allocate
// 0xffffffffffffffff bytes, so pass a different value that
// causes it to fail.
if runtime.GOOS == "dragonfly" {
size = C.size_t(0x7fffffff << (32 * (^uintptr(0) >> 63)))
}
p := C.malloc(size)
if p == nil {
fmt.Println("malloc: C.malloc returned nil")
// Just exit normally--the test script expects this
// program to crash, so exiting normally indicates failure.
}
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Tests that cgo detects invalid pointer passing at runtime.
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
)
// ptrTest is the tests without the boilerplate.
type ptrTest struct {
name string // for reporting
c string // the cgo comment
imports []string // a list of imports
support string // supporting functions
body string // the body of the main function
extra []extra // extra files
fail bool // whether the test should fail
expensive bool // whether the test requires the expensive check
}
type extra struct {
name string
contents string
}
var ptrTests = []ptrTest{
{
// Passing a pointer to a struct that contains a Go pointer.
name: "ptr1",
c: `typedef struct s { int *p; } s; void f(s *ps) {}`,
body: `C.f(&C.s{new(C.int)})`,
fail: true,
},
{
// Passing a pointer to a struct that contains a Go pointer.
name: "ptr2",
c: `typedef struct s { int *p; } s; void f(s *ps) {}`,
body: `p := &C.s{new(C.int)}; C.f(p)`,
fail: true,
},
{
// Passing a pointer to an int field of a Go struct
// that (irrelevantly) contains a Go pointer.
name: "ok1",
c: `struct s { int i; int *p; }; void f(int *p) {}`,
body: `p := &C.struct_s{i: 0, p: new(C.int)}; C.f(&p.i)`,
fail: false,
},
{
// Passing a pointer to a pointer field of a Go struct.
name: "ptr-field",
c: `struct s { int i; int *p; }; void f(int **p) {}`,
body: `p := &C.struct_s{i: 0, p: new(C.int)}; C.f(&p.p)`,
fail: true,
},
{
// Passing a pointer to a pointer field of a Go
// struct, where the field does not contain a Go
// pointer, but another field (irrelevantly) does.
name: "ptr-field-ok",
c: `struct s { int *p1; int *p2; }; void f(int **p) {}`,
body: `p := &C.struct_s{p1: nil, p2: new(C.int)}; C.f(&p.p1)`,
fail: false,
},
{
// Passing the address of a slice with no Go pointers.
name: "slice-ok-1",
c: `void f(void **p) {}`,
imports: []string{"unsafe"},
body: `s := []unsafe.Pointer{nil}; C.f(&s[0])`,
fail: false,
},
{
// Passing the address of a slice with a Go pointer.
name: "slice-ptr-1",
c: `void f(void **p) {}`,
imports: []string{"unsafe"},
body: `i := 0; s := []unsafe.Pointer{unsafe.Pointer(&i)}; C.f(&s[0])`,
fail: true,
},
{
// Passing the address of a slice with a Go pointer,
// where we are passing the address of an element that
// is not a Go pointer.
name: "slice-ptr-2",
c: `void f(void **p) {}`,
imports: []string{"unsafe"},
body: `i := 0; s := []unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f(&s[0])`,
fail: true,
},
{
// Passing the address of a slice that is an element
// in a struct only looks at the slice.
name: "slice-ok-2",
c: `void f(void **p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; s []unsafe.Pointer }`,
body: `i := 0; p := &S{p:&i, s:[]unsafe.Pointer{nil}}; C.f(&p.s[0])`,
fail: false,
},
{
// Passing the address of a slice of an array that is
// an element in a struct, with a type conversion.
name: "slice-ok-3",
c: `void f(void* p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; a [4]byte }`,
body: `i := 0; p := &S{p:&i}; s := p.a[:]; C.f(unsafe.Pointer(&s[0]))`,
fail: false,
},
{
// Passing the address of a slice of an array that is
// an element in a struct, with a type conversion.
name: "slice-ok-4",
c: `typedef void* PV; void f(PV p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; a [4]byte }`,
body: `i := 0; p := &S{p:&i}; C.f(C.PV(unsafe.Pointer(&p.a[0])))`,
fail: false,
},
{
// Passing the address of a static variable with no
// pointers doesn't matter.
name: "varok",
c: `void f(char** parg) {}`,
support: `var hello = [...]C.char{'h', 'e', 'l', 'l', 'o'}`,
body: `parg := [1]*C.char{&hello[0]}; C.f(&parg[0])`,
fail: false,
},
{
// Passing the address of a static variable with
// pointers does matter.
name: "var",
c: `void f(char*** parg) {}`,
support: `var hello = [...]*C.char{new(C.char)}`,
body: `parg := [1]**C.char{&hello[0]}; C.f(&parg[0])`,
fail: true,
},
{
// Storing a Go pointer into C memory should fail.
name: "barrier",
c: `#include <stdlib.h>
char **f1() { return malloc(sizeof(char*)); }
void f2(char **p) {}`,
body: `p := C.f1(); *p = new(C.char); C.f2(p)`,
fail: true,
expensive: true,
},
{
// Storing a Go pointer into C memory by assigning a
// large value should fail.
name: "barrier-struct",
c: `#include <stdlib.h>
struct s { char *a[10]; };
struct s *f1() { return malloc(sizeof(struct s)); }
void f2(struct s *p) {}`,
body: `p := C.f1(); p.a = [10]*C.char{new(C.char)}; C.f2(p)`,
fail: true,
expensive: true,
},
{
// Storing a Go pointer into C memory using a slice
// copy should fail.
name: "barrier-slice",
c: `#include <stdlib.h>
struct s { char *a[10]; };
struct s *f1() { return malloc(sizeof(struct s)); }
void f2(struct s *p) {}`,
body: `p := C.f1(); copy(p.a[:], []*C.char{new(C.char)}); C.f2(p)`,
fail: true,
expensive: true,
},
{
// A very large value uses a GC program, which is a
// different code path.
name: "barrier-gcprog-array",
c: `#include <stdlib.h>
struct s { char *a[32769]; };
struct s *f1() { return malloc(sizeof(struct s)); }
void f2(struct s *p) {}`,
body: `p := C.f1(); p.a = [32769]*C.char{new(C.char)}; C.f2(p)`,
fail: true,
expensive: true,
},
{
// Similar case, with a source on the heap.
name: "barrier-gcprog-array-heap",
c: `#include <stdlib.h>
struct s { char *a[32769]; };
struct s *f1() { return malloc(sizeof(struct s)); }
void f2(struct s *p) {}
void f3(void *p) {}`,
imports: []string{"unsafe"},
body: `p := C.f1(); n := &[32769]*C.char{new(C.char)}; p.a = *n; C.f2(p); n[0] = nil; C.f3(unsafe.Pointer(n))`,
fail: true,
expensive: true,
},
{
// A GC program with a struct.
name: "barrier-gcprog-struct",
c: `#include <stdlib.h>
struct s { char *a[32769]; };
struct s2 { struct s f; };
struct s2 *f1() { return malloc(sizeof(struct s2)); }
void f2(struct s2 *p) {}`,
body: `p := C.f1(); p.f = C.struct_s{[32769]*C.char{new(C.char)}}; C.f2(p)`,
fail: true,
expensive: true,
},
{
// Similar case, with a source on the heap.
name: "barrier-gcprog-struct-heap",
c: `#include <stdlib.h>
struct s { char *a[32769]; };
struct s2 { struct s f; };
struct s2 *f1() { return malloc(sizeof(struct s2)); }
void f2(struct s2 *p) {}
void f3(void *p) {}`,
imports: []string{"unsafe"},
body: `p := C.f1(); n := &C.struct_s{[32769]*C.char{new(C.char)}}; p.f = *n; C.f2(p); n.a[0] = nil; C.f3(unsafe.Pointer(n))`,
fail: true,
expensive: true,
},
{
// Exported functions may not return Go pointers.
name: "export1",
c: `extern unsigned char *GoFn();`,
support: `//export GoFn
func GoFn() *byte { return new(byte) }`,
body: `C.GoFn()`,
fail: true,
},
{
// Returning a C pointer is fine.
name: "exportok",
c: `#include <stdlib.h>
extern unsigned char *GoFn();`,
support: `//export GoFn
func GoFn() *byte { return (*byte)(C.malloc(1)) }`,
body: `C.GoFn()`,
},
{
// Passing a Go string is fine.
name: "pass-string",
c: `#include <stddef.h>
typedef struct { const char *p; ptrdiff_t n; } gostring;
gostring f(gostring s) { return s; }`,
imports: []string{"unsafe"},
body: `s := "a"; r := C.f(*(*C.gostring)(unsafe.Pointer(&s))); if *(*string)(unsafe.Pointer(&r)) != s { panic(r) }`,
},
{
// Passing a slice of Go strings fails.
name: "pass-string-slice",
c: `void f(void *p) {}`,
imports: []string{"strings", "unsafe"},
support: `type S struct { a [1]string }`,
body: `s := S{a:[1]string{strings.Repeat("a", 2)}}; C.f(unsafe.Pointer(&s.a[0]))`,
fail: true,
},
{
// Exported functions may not return strings.
name: "ret-string",
c: `extern void f();`,
imports: []string{"strings"},
support: `//export GoStr
func GoStr() string { return strings.Repeat("a", 2) }`,
body: `C.f()`,
extra: []extra{
{
"call.c",
`#include <stddef.h>
typedef struct { const char *p; ptrdiff_t n; } gostring;
extern gostring GoStr();
void f() { GoStr(); }`,
},
},
fail: true,
},
{
// Don't check non-pointer data.
// Uses unsafe code to get a pointer we shouldn't check.
// Although we use unsafe, the uintptr represents an integer
// that happens to have the same representation as a pointer;
// that is, we are testing something that is not unsafe.
name: "ptrdata1",
c: `#include <stdlib.h>
void f(void* p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; a [8*8]byte; u uintptr }`,
body: `i := 0; p := &S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f(unsafe.Pointer(q))`,
fail: false,
},
{
// Like ptrdata1, but with a type that uses a GC program.
name: "ptrdata2",
c: `#include <stdlib.h>
void f(void* p) {}`,
imports: []string{"unsafe"},
support: `type S struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
body: `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`,
fail: false,
},
{
// Check deferred pointers when they are used, not
// when the defer statement is run.
name: "defer",
c: `typedef struct s { int *p; } s; void f(s *ps) {}`,
body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`,
fail: true,
},
{
// Check a pointer to a union if the union has any
// pointer fields.
name: "union1",
c: `typedef union { char **p; unsigned long i; } u; void f(u *pu) {}`,
imports: []string{"unsafe"},
body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
fail: true,
},
{
// Don't check a pointer to a union if the union does
// not have any pointer fields.
// Like ptrdata1 above, the uintptr represents an
// integer that happens to have the same
// representation as a pointer.
name: "union2",
c: `typedef union { unsigned long i; } u; void f(u *pu) {}`,
imports: []string{"unsafe"},
body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
fail: false,
},
}
func main() {
os.Exit(doTests())
}
func doTests() int {
gopath, err := ioutil.TempDir("", "cgoerrors")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return 2
}
defer os.RemoveAll(gopath)
if err := os.MkdirAll(filepath.Join(gopath, "src"), 0777); err != nil {
fmt.Fprintln(os.Stderr, err)
return 2
}
workers := runtime.NumCPU() + 1
var wg sync.WaitGroup
c := make(chan int)
errs := make(chan int)
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
worker(gopath, c, errs)
wg.Done()
}()
}
for i := range ptrTests {
c <- i
}
close(c)
go func() {
wg.Wait()
close(errs)
}()
tot := 0
for e := range errs {
tot += e
}
return tot
}
func worker(gopath string, c, errs chan int) {
e := 0
for i := range c {
if !doOne(gopath, i) {
e++
}
}
if e > 0 {
errs <- e
}
}
func doOne(gopath string, i int) bool {
t := &ptrTests[i]
dir := filepath.Join(gopath, "src", fmt.Sprintf("dir%d", i))
if err := os.Mkdir(dir, 0777); err != nil {
fmt.Fprintln(os.Stderr, err)
return false
}
name := filepath.Join(dir, fmt.Sprintf("t%d.go", i))
f, err := os.Create(name)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return false
}
b := bufio.NewWriter(f)
fmt.Fprintln(b, `package main`)
fmt.Fprintln(b)
fmt.Fprintln(b, `/*`)
fmt.Fprintln(b, t.c)
fmt.Fprintln(b, `*/`)
fmt.Fprintln(b, `import "C"`)
fmt.Fprintln(b)
for _, imp := range t.imports {
fmt.Fprintln(b, `import "`+imp+`"`)
}
if len(t.imports) > 0 {
fmt.Fprintln(b)
}
if len(t.support) > 0 {
fmt.Fprintln(b, t.support)
fmt.Fprintln(b)
}
fmt.Fprintln(b, `func main() {`)
fmt.Fprintln(b, t.body)
fmt.Fprintln(b, `}`)
if err := b.Flush(); err != nil {
fmt.Fprintf(os.Stderr, "flushing %s: %v\n", name, err)
return false
}
if err := f.Close(); err != nil {
fmt.Fprintf(os.Stderr, "closing %s: %v\n", name, err)
return false
}
for _, e := range t.extra {
if err := ioutil.WriteFile(filepath.Join(dir, e.name), []byte(e.contents), 0644); err != nil {
fmt.Fprintf(os.Stderr, "writing %s: %v\n", e.name, err)
return false
}
}
ok := true
cmd := exec.Command("go", "build")
cmd.Dir = dir
cmd.Env = addEnv("GOPATH", gopath)
buf, err := cmd.CombinedOutput()
if err != nil {
fmt.Fprintf(os.Stderr, "test %s failed to build: %v\n%s", t.name, err, buf)
return false
}
exe := filepath.Join(dir, filepath.Base(dir))
cmd = exec.Command(exe)
cmd.Dir = dir
if t.expensive {
cmd.Env = cgocheckEnv("1")
buf, err := cmd.CombinedOutput()
if err != nil {
var errbuf bytes.Buffer
if t.fail {
fmt.Fprintf(&errbuf, "test %s marked expensive but failed when not expensive: %v\n", t.name, err)
} else {
fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=1: %v\n", t.name, err)
}
reportTestOutput(&errbuf, t.name, buf)
os.Stderr.Write(errbuf.Bytes())
ok = false
}
cmd = exec.Command(exe)
cmd.Dir = dir
}
if t.expensive {
cmd.Env = cgocheckEnv("2")
}
buf, err = cmd.CombinedOutput()
if t.fail {
if err == nil {
var errbuf bytes.Buffer
fmt.Fprintf(&errbuf, "test %s did not fail as expected\n", t.name)
reportTestOutput(&errbuf, t.name, buf)
os.Stderr.Write(errbuf.Bytes())
ok = false
} else if !bytes.Contains(buf, []byte("Go pointer")) {
var errbuf bytes.Buffer
fmt.Fprintf(&errbuf, "test %s output does not contain expected error (failed with %v)\n", t.name, err)
reportTestOutput(&errbuf, t.name, buf)
os.Stderr.Write(errbuf.Bytes())
ok = false
}
} else {
if err != nil {
var errbuf bytes.Buffer
fmt.Fprintf(&errbuf, "test %s failed unexpectedly: %v\n", t.name, err)
reportTestOutput(&errbuf, t.name, buf)
os.Stderr.Write(errbuf.Bytes())
ok = false
}
if !t.expensive && ok {
// Make sure it passes with the expensive checks.
cmd := exec.Command(exe)
cmd.Dir = dir
cmd.Env = cgocheckEnv("2")
buf, err := cmd.CombinedOutput()
if err != nil {
var errbuf bytes.Buffer
fmt.Fprintf(&errbuf, "test %s failed unexpectedly with expensive checks: %v\n", t.name, err)
reportTestOutput(&errbuf, t.name, buf)
os.Stderr.Write(errbuf.Bytes())
ok = false
}
}
}
if t.fail && ok {
cmd = exec.Command(exe)
cmd.Dir = dir
cmd.Env = cgocheckEnv("0")
buf, err := cmd.CombinedOutput()
if err != nil {
var errbuf bytes.Buffer
fmt.Fprintf(&errbuf, "test %s failed unexpectedly with GODEBUG=cgocheck=0: %v\n", t.name, err)
reportTestOutput(&errbuf, t.name, buf)
os.Stderr.Write(errbuf.Bytes())
ok = false
}
}
return ok
}
func reportTestOutput(w io.Writer, name string, buf []byte) {
fmt.Fprintf(w, "=== test %s output ===\n", name)
fmt.Fprintf(w, "%s", buf)
fmt.Fprintf(w, "=== end of test %s output ===\n", name)
}
func cgocheckEnv(val string) []string {
return addEnv("GODEBUG", "cgocheck="+val)
}
func addEnv(key, val string) []string {
env := []string{key + "=" + val}
look := key + "="
for _, e := range os.Environ() {
if !strings.HasPrefix(e, look) {
env = append(env, e)
}
}
return env
}
#!/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
! 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
// 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())
}
// 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)
}
}
program HelloWorldF90
write(*,*) "Hello World!"
end program HelloWorldF90
#!/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
// 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)
}
}
// 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 <gmp.h>
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 <gmp.h> 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 <gmp.h>
#include <stdlib.h>
// 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
}
// 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())
}
// 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 <assert.h>
#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;
}
}
}
// 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
}
// 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;
// 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")
}
}
// 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
}
// 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)
}
}
// 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")
}
}
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
// 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
}
}
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
// 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 <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
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)))
// 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")
}
* 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
// 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 <stdio.h>
// 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())
// 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 <stdio.h>
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; i<sizeof *event; i++) {
p[i] = i;
}
}
int same(SDL_KeyboardEvent* e, Uint8 typ, Uint8 which, Uint8 state, Uint8 scan, SDLKey sym, SDLMod mod, Uint16 uni) {
return e->typ == 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)
}
}
// 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 <stdlib.h>
//
// // 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)
}
// 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
// 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 <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#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) {}
// 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)
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
// 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 <string.h>
#include <sys/types.h>
#include <unistd.h>
#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 <windows.h>
long long
mysleep(int seconds) {
long long st = GetTickCount();
Sleep(1000 * seconds);
return st;
}
#else
#include <sys/time.h>
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)});
}
// 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* 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;
}
// 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* 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");
}
// 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)
}
}
// 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) }
// 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) {}
// 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) }
// 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 <unistd.h>
#include <sys/syscall.h>
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")
}
}
}
// 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) }
// 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 <stdlib.h>
#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)
}
// 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)
}
}
// 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)
}
}
// 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 <pthread.h>
#include "_cgo_export.h"
static void*
addThread(void *p)
{
int i, max;
max = *(int*)p;
for(i=0; i<max; i++)
Add(i);
return 0;
}
void
doAdd(int max, int nthread)
{
enum { MaxThread = 20 };
int i;
pthread_t thread_id[MaxThread];
if(nthread > MaxThread)
nthread = MaxThread;
for(i=0; i<nthread; i++)
pthread_create(&thread_id[i], 0, addThread, &max);
for(i=0; i<nthread; i++)
pthread_join(thread_id[i], 0);
}
// 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.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <process.h>
#include "_cgo_export.h"
__stdcall
static unsigned int
addThread(void *p)
{
int i, max;
max = *(int*)p;
for(i=0; i<max; i++)
Add(i);
return 0;
}
void
doAdd(int max, int nthread)
{
enum { MaxThread = 20 };
int i;
uintptr_t thread_id[MaxThread];
if(nthread > MaxThread)
nthread = MaxThread;
for(i=0; i<nthread; i++)
thread_id[i] = _beginthreadex(0, 0, addThread, &max, 0, 0);
for(i=0; i<nthread; i++) {
WaitForSingleObject((HANDLE)thread_id[i], INFINITE);
CloseHandle((HANDLE)thread_id[i]);
}
}
// 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
/*
int base_symbol = 0;
#define alias_one base_symbol
#define alias_two base_symbol
*/
import "C"
import "fmt"
func duplicateSymbols() {
fmt.Printf("%v %v %v\n", C.base_symbol, C.alias_one, C.alias_two)
}
// 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
/*
#include <stdlib.h>
*/
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)
}
}
// 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()
}
// 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)
}
}
// 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")
}
}
// 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
}
// 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;
// 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);
// 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)
}
}
}
// 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")
}
}
// 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{}))
}
}
// 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 <stdio.h>
#include <stdlib.h>
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)
}
}
}
// 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
}
// 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()
}
// 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
// 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 <stdlib.h>
import "C"
var _, _ = C.abs(0)
// 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 <stdlib.h>
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)))[:])
}
}
// 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())
}
}
// 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 <stdio.h>
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)
}
}
// 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]
}
}
// 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 <stdlib.h>
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))
}
// 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 <stdlib.h>
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
}
// 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))
}
}
// 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
}
// 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 <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
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)
}
}
// 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) {}
// 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 <stdio.h>
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 <stdio.h>
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
}
}
}
// 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 <errno.h>
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)
}
}
// 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")
}
// 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
}
// +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()
}
// 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 <stdio.h>
//
// void say() {
// printf("%s from C\n", "hello");
// }
//
import "C"
import "testing"
func testPrintf(t *testing.T) {
C.say()
}
// 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();
}
// 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 <dlfcn.h>
#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)
}
// 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) {
}
// 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}
// 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}
// 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
// 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
#include <stdio.h>
#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");
}
// 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)
}
typedef struct Issue4339 Issue4339;
struct Issue4339 {
char *name;
void (*bar)(void);
};
extern Issue4339 exported4339;
void handle4339(Issue4339*);
// 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 <stdbool.h>
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)
}
}
// 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()
}
// 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
}
// 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)
}
}
// 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 <signal.h>
#include <pthread.h>
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()
}
// 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) {}
// 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)
}
}
// 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();
}
// 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)
}
}
}
// 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)
}
}
// 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;
}
// 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;
}
// 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 <stdio.h>
#include <math.h>
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()
}
// 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
}
// 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 <stdlib.h>
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)
}
// 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)
}
// 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 <stdlib.h>
#include <string.h>
*/
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
}
// 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")
}
}
// 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)
}
}
// 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);
}
// 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 <pthread.h>
#include <stdio.h>
#include <unistd.h>
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);
}
// 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")
}
}
// 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])
}
}
// 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 <stdint.h>
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))
}
}
}
// 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)
}
}
// 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)
}
// 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 <stdint.h>
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)
}
// 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)
}
}
}
// 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())
}
// 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;
// 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
}
// 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
// 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{},
}
// 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)
}
// 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")
}
// 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);
}
// 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++
}
// 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.h>
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)
}
}
package cgotest
/*
#cgo LDFLAGS: -lm
#include <math.h>
*/
import "C"
import (
"testing"
"./issue8756"
)
func test8756(t *testing.T) {
issue8756.Pow()
C.pow(1, 2)
}
package issue8756
/*
#cgo LDFLAGS: -lm
#include <math.h>
*/
import "C"
func Pow() {
C.pow(1, 2)
}
// 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() {
}
// 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()
}
// 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()
}
// 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()
{
}
package issue8828
//void foo();
import "C"
func Bar() {
C.foo()
}
// 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
}
package cgotest
import (
"testing"
"./issue9026"
)
func test9026(t *testing.T) { issue9026.Test(t) }
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)
}
}
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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()
}
}
// 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()
// 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 <sys/types.h>
#include <unistd.h>
*/
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))
}
}
}
// 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)
}
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)))
}
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)))
}
// 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)
}
}
// 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 <sys/types.h>
#include <unistd.h>
*/
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")
}
}
// 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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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)
}
// 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 <signal.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
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);
}
// 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")
}
}
// 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 <sys/mman.h>
#include <pthread.h>
#include <unistd.h>
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))
}
}
// 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
}
// 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 <stdint.h>
#include <stdio.h>
#include <string.h>
#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;
}
// 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 <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#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;
}
// 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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sched.h>
#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;
}
// 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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sched.h>
#include <pthread.h>
#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;
}
// 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#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;
}
// 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 <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
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;
}
// 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;
}
// 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)
}
}
// 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() {
}
// 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() {
}
// 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 <signal.h>
#include <pthread.h>
// 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() {
}
// 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 }
// 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 <stdint.h>
#include <stdio.h>
#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;
}
// 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 <stdint.h>
#include <stdio.h>
#include <dlfcn.h>
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;
}
// 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#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;
}
// 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 <stdint.h>
#include <stdio.h>
#include <dlfcn.h>
// 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;
}
// 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 <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#include <dlfcn.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;
// 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;
}
// 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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sched.h>
#include <dlfcn.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;
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;
}
// 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
}
// 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)
}
// 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)
}
// 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() {
}
// 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() {
}
// 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() {
}
// 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 }
#!/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
// 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
// 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
// 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() {
}
#!/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
// 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
}
// 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
}
// 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
}
// 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")
}
// 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")
}
}
// 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)
}
// 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)
}
// 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
// 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() {}
// 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")
}
}
// 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) {}
// 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")
}
// 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 <errno.h>
//#include <string.h>
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")
}
// 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")
}
#!/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
// 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() {}
// 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() {}
// 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 <stdint.h>
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)
}
}
}
// 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 <string.h>
#include <stdint.h>
#include <stdlib.h>
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)))
}
// 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)
}
}
// 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 <time.h>
#include <unistd.h>
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) {
}
// 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 <stdlib.h>
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()
}
// 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 <string.h>
#include <stdint.h>
#include <stdlib.h>
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)))
}
// 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() {}
#!/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
// 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)
}
}
// 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)
}
}
// 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
}
}
// 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 <stdlib.h>
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()
}
// 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 <stdlib.h>
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()
}
// 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()
}
// 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()
}
// 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 <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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
}
// 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 <stdlib.h>
#include <sys/time.h>
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()
}
// 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, &note{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")
}
package dep2
import "depBase"
var W int = 1
var hasProg depBase.HasProg
type Dep2 struct {
depBase.Dep
}
func G() int {
return depBase.F() + 1
}
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
}
// 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
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
}
//+build gccgo
package depBase
func ImplementedInAsm() {}
//+build !gccgo
package depBase
func ImplementedInAsm()
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")
}
}
package main
import "dep2"
func main() {
d := &dep2.Dep2{}
dep2.W = dep2.G() + 1 + d.Method()
}
package main
import "dep3"
func main() {
dep3.D3()
}
package main
/*
*/
import "C"
func main() {
}
package explicit
import (
"implicit"
)
func E() int {
return implicit.I()
}
// 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")
}
}
// 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)
}
// 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)
}
// 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
package implicit
func I() int {
return 42
}
package main
import (
"explicit"
"implicit"
)
func main() {
println(implicit.I() + explicit.E())
}
// 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 <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
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()
}
// 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
// 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() {
}
// 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();
}
// 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")
}
}
// 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()
}
// 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))
}
}
// 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";
// 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;
// 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()
}
// 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 <pthread.h>
// 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)
}
}
// 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)
}
// 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 <pthread.h>
static __thread int tls;
void
setTLS(int v)
{
tls = v;
}
int
getTLS()
{
return tls;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment