From bc998d034f45d1828a8663b2eed928faf22a7d01 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 14 Sep 2017 17:11:35 +0000 Subject: libgo: update to go1.9 Reviewed-on: https://go-review.googlesource.com/63753 From-SVN: r252767 --- libgo/misc/cgo/errors/issue18452.go | 18 +++ libgo/misc/cgo/errors/issue18889.go | 7 + libgo/misc/cgo/errors/ptr.go | 8 + libgo/misc/cgo/errors/test.bash | 4 +- libgo/misc/cgo/fortran/test.bash | 2 +- libgo/misc/cgo/test/cgo_test.go | 4 + libgo/misc/cgo/test/issue18720.go | 28 ++++ libgo/misc/cgo/test/issue20129.go | 33 ++++ libgo/misc/cgo/test/issue20266.go | 21 +++ libgo/misc/cgo/test/issue20266/issue20266.h | 9 ++ libgo/misc/cgo/test/issue20369.go | 20 +++ libgo/misc/cgo/test/issue6612.go | 17 +-- libgo/misc/cgo/testcarchive/carchive_test.go | 170 ++++++++++++++++----- libgo/misc/cgo/testcarchive/main2.c | 35 ++++- libgo/misc/cgo/testcarchive/main3.c | 34 +++++ libgo/misc/cgo/testcarchive/main5.c | 18 +++ libgo/misc/cgo/testcarchive/main6.c | 34 +++++ libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go | 30 ++++ libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go | 12 ++ libgo/misc/cgo/testcarchive/src/libgo6/sigprof.go | 25 +++ libgo/misc/cgo/testcshared/main0.c | 6 + libgo/misc/cgo/testcshared/src/p/p.go | 3 + libgo/misc/cgo/testcshared/test.bash | 20 +-- libgo/misc/cgo/testplugin/src/issue19534/main.go | 23 +++ libgo/misc/cgo/testplugin/src/issue19534/plugin.go | 9 ++ libgo/misc/cgo/testplugin/test.bash | 8 +- libgo/misc/cgo/testplugin/unnamed1.go | 11 ++ libgo/misc/cgo/testplugin/unnamed2.go | 9 ++ libgo/misc/cgo/testsanitizers/test.bash | 57 +++++-- libgo/misc/cgo/testsanitizers/tsan10.go | 31 ++++ libgo/misc/cgo/testsanitizers/tsan11.go | 55 +++++++ libgo/misc/cgo/testsanitizers/tsan12.go | 35 +++++ libgo/misc/cgo/testsanitizers/tsan_shared.go | 63 ++++++++ libgo/misc/cgo/testshared/shared_test.go | 20 ++- libgo/misc/cgo/testshared/src/division/division.go | 17 +++ 35 files changed, 813 insertions(+), 83 deletions(-) create mode 100644 libgo/misc/cgo/errors/issue18452.go create mode 100644 libgo/misc/cgo/errors/issue18889.go create mode 100644 libgo/misc/cgo/test/issue18720.go create mode 100644 libgo/misc/cgo/test/issue20129.go create mode 100644 libgo/misc/cgo/test/issue20266.go create mode 100644 libgo/misc/cgo/test/issue20266/issue20266.h create mode 100644 libgo/misc/cgo/test/issue20369.go create mode 100644 libgo/misc/cgo/testcarchive/main6.c create mode 100644 libgo/misc/cgo/testcarchive/src/libgo6/sigprof.go create mode 100644 libgo/misc/cgo/testplugin/src/issue19534/main.go create mode 100644 libgo/misc/cgo/testplugin/src/issue19534/plugin.go create mode 100644 libgo/misc/cgo/testsanitizers/tsan10.go create mode 100644 libgo/misc/cgo/testsanitizers/tsan11.go create mode 100644 libgo/misc/cgo/testsanitizers/tsan12.go create mode 100644 libgo/misc/cgo/testsanitizers/tsan_shared.go create mode 100644 libgo/misc/cgo/testshared/src/division/division.go (limited to 'libgo/misc') diff --git a/libgo/misc/cgo/errors/issue18452.go b/libgo/misc/cgo/errors/issue18452.go new file mode 100644 index 0000000..36ef7f5 --- /dev/null +++ b/libgo/misc/cgo/errors/issue18452.go @@ -0,0 +1,18 @@ +// 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. + +// Issue 18452: show pos info in undefined name errors + +package p + +import ( + "C" + "fmt" +) + +func a() { + fmt.Println("Hello, world!") + C.function_that_does_not_exist() // line 16 + C.pi // line 17 +} diff --git a/libgo/misc/cgo/errors/issue18889.go b/libgo/misc/cgo/errors/issue18889.go new file mode 100644 index 0000000..bba6b8f --- /dev/null +++ b/libgo/misc/cgo/errors/issue18889.go @@ -0,0 +1,7 @@ +package main + +import "C" + +func main() { + _ = C.malloc // ERROR HERE +} diff --git a/libgo/misc/cgo/errors/ptr.go b/libgo/misc/cgo/errors/ptr.go index 4dafbdf..3e11766 100644 --- a/libgo/misc/cgo/errors/ptr.go +++ b/libgo/misc/cgo/errors/ptr.go @@ -343,6 +343,14 @@ var ptrTests = []ptrTest{ body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`, fail: false, }, + { + // Issue #21306. + name: "preempt-during-call", + c: `void f() {}`, + imports: []string{"runtime", "sync"}, + body: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`, + fail: false, + }, } func main() { diff --git a/libgo/misc/cgo/errors/test.bash b/libgo/misc/cgo/errors/test.bash index 05261e9..ed0b094 100644 --- a/libgo/misc/cgo/errors/test.bash +++ b/libgo/misc/cgo/errors/test.bash @@ -17,7 +17,7 @@ check() { expect() { file=$1 shift - if go build $file >errs 2>&1; then + if go build -gcflags=-C $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 @@ -47,6 +47,8 @@ expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulongl check issue13830.go check issue16116.go check issue16591.go +check issue18889.go +expect issue18452.go issue18452.go:16 issue18452.go:17 if ! go build issue14669.go; then exit 1 diff --git a/libgo/misc/cgo/fortran/test.bash b/libgo/misc/cgo/fortran/test.bash index 3d1bc9d..1e0d59e 100644 --- a/libgo/misc/cgo/fortran/test.bash +++ b/libgo/misc/cgo/fortran/test.bash @@ -12,7 +12,7 @@ FC=$1 goos=$(go env GOOS) libext="so" -if [ "$goos" == "darwin" ]; then +if [ "$goos" = "darwin" ]; then libext="dylib" fi diff --git a/libgo/misc/cgo/test/cgo_test.go b/libgo/misc/cgo/test/cgo_test.go index a6de999..f7cf6f6 100644 --- a/libgo/misc/cgo/test/cgo_test.go +++ b/libgo/misc/cgo/test/cgo_test.go @@ -76,5 +76,9 @@ 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 Test20369(t *testing.T) { test20369(t) } +func Test18720(t *testing.T) { test18720(t) } +func Test20266(t *testing.T) { test20266(t) } +func Test20129(t *testing.T) { test20129(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } diff --git a/libgo/misc/cgo/test/issue18720.go b/libgo/misc/cgo/test/issue18720.go new file mode 100644 index 0000000..a933044 --- /dev/null +++ b/libgo/misc/cgo/test/issue18720.go @@ -0,0 +1,28 @@ +// 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 cgotest + +/* +#define HELLO "hello" +#define WORLD "world" +#define HELLO_WORLD HELLO "\000" WORLD + +struct foo { char c; }; +#define SIZE_OF(x) sizeof(x) +#define SIZE_OF_FOO SIZE_OF(struct foo) +*/ +import "C" +import "testing" + +func test18720(t *testing.T) { + if C.HELLO_WORLD != "hello\000world" { + t.Fatalf(`expected "hello\000world", but got %q`, C.HELLO_WORLD) + } + + // Issue 20125. + if got, want := C.SIZE_OF_FOO, 1; got != want { + t.Errorf("C.SIZE_OF_FOO == %v, expected %v", got, want) + } +} diff --git a/libgo/misc/cgo/test/issue20129.go b/libgo/misc/cgo/test/issue20129.go new file mode 100644 index 0000000..e69e0e1 --- /dev/null +++ b/libgo/misc/cgo/test/issue20129.go @@ -0,0 +1,33 @@ +// 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 cgotest + +/* +int issue20129 = 0; +typedef void issue20129Void; +issue20129Void issue20129Foo() { + issue20129 = 1; +} +typedef issue20129Void issue20129Void2; +issue20129Void2 issue20129Bar() { + issue20129 = 2; +} +*/ +import "C" +import "testing" + +func test20129(t *testing.T) { + if C.issue20129 != 0 { + t.Fatal("test is broken") + } + C.issue20129Foo() + if C.issue20129 != 1 { + t.Errorf("got %v but expected %v", C.issue20129, 1) + } + C.issue20129Bar() + if C.issue20129 != 2 { + t.Errorf("got %v but expected %v", C.issue20129, 2) + } +} diff --git a/libgo/misc/cgo/test/issue20266.go b/libgo/misc/cgo/test/issue20266.go new file mode 100644 index 0000000..9f95086 --- /dev/null +++ b/libgo/misc/cgo/test/issue20266.go @@ -0,0 +1,21 @@ +// 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. + +// Issue 20266: use -I with a relative path. + +package cgotest + +/* +#cgo CFLAGS: -I issue20266 -Iissue20266 -Ddef20266 +#include "issue20266.h" +*/ +import "C" + +import "testing" + +func test20266(t *testing.T) { + if got, want := C.issue20266, 20266; got != want { + t.Errorf("got %d, want %d", got, want) + } +} diff --git a/libgo/misc/cgo/test/issue20266/issue20266.h b/libgo/misc/cgo/test/issue20266/issue20266.h new file mode 100644 index 0000000..8d3258e --- /dev/null +++ b/libgo/misc/cgo/test/issue20266/issue20266.h @@ -0,0 +1,9 @@ +// 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. + +#define issue20266 20266 + +#ifndef def20266 +#error "expected def20266 to be defined" +#endif diff --git a/libgo/misc/cgo/test/issue20369.go b/libgo/misc/cgo/test/issue20369.go new file mode 100644 index 0000000..37b4b78 --- /dev/null +++ b/libgo/misc/cgo/test/issue20369.go @@ -0,0 +1,20 @@ +// 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 cgotest + +/* +#define UINT64_MAX 18446744073709551615ULL +*/ +import "C" +import ( + "math" + "testing" +) + +func test20369(t *testing.T) { + if C.UINT64_MAX != math.MaxUint64 { + t.Fatalf("got %v, want %v", uint64(C.UINT64_MAX), uint64(math.MaxUint64)) + } +} diff --git a/libgo/misc/cgo/test/issue6612.go b/libgo/misc/cgo/test/issue6612.go index c337f91..15a12fa 100644 --- a/libgo/misc/cgo/test/issue6612.go +++ b/libgo/misc/cgo/test/issue6612.go @@ -74,18 +74,15 @@ func testNaming(t *testing.T) { } } - // 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 { + if c := C.myfloat_def; c != 1.5 { + t.Errorf("C.myint_def = %v, want 1.5", c) + } + { + const c = C.myfloat_def + if c != 1.5 { t.Errorf("C.myint as const = %v, want 1.5", c) - } } - */ + } if s := C.mystring_def; s != "hello" { t.Errorf("C.mystring_def = %q, want %q", s, "hello") diff --git a/libgo/misc/cgo/testcarchive/carchive_test.go b/libgo/misc/cgo/testcarchive/carchive_test.go index a2ad9c5..4865b80 100644 --- a/libgo/misc/cgo/testcarchive/carchive_test.go +++ b/libgo/misc/cgo/testcarchive/carchive_test.go @@ -120,8 +120,10 @@ func init() { 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) + fmt.Fprintf(os.Stderr, "go env %s failed:\n%s\n", key, err) + if ee, ok := err.(*exec.ExitError); ok { + fmt.Fprintf(os.Stderr, "%s", ee.Stderr) + } os.Exit(2) } return strings.TrimSpace(string(out)) @@ -238,15 +240,7 @@ func TestEarlySignalHandler(t *testing.T) { } 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") - } + checkSignalForwardingTest(t) defer func() { os.Remove("libgo2.a") @@ -274,32 +268,19 @@ func TestSignalForwarding(t *testing.T) { cmd = exec.Command(bin[0], append(bin[1:], "1")...) out, err := cmd.CombinedOutput() + t.Logf("%s", out) + expectSignal(t, err, syscall.SIGSEGV) - 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) - } + // Test SIGPIPE forwarding + cmd = exec.Command(bin[0], append(bin[1:], "3")...) + + out, err = cmd.CombinedOutput() + t.Logf("%s", out) + expectSignal(t, err, syscall.SIGPIPE) } 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") - } + checkSignalForwardingTest(t) defer func() { os.Remove("libgo2.a") @@ -370,14 +351,7 @@ func TestSignalForwardingExternal(t *testing.T) { 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. + if expectSignal(t, err, syscall.SIGSEGV) { return } } @@ -385,6 +359,38 @@ func TestSignalForwardingExternal(t *testing.T) { t.Errorf("program succeeded unexpectedly %d times", tries) } +// checkSignalForwardingTest calls t.Skip if the SignalForwarding test +// doesn't work on this platform. +func checkSignalForwardingTest(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") + } +} + +// expectSignal checks that err, the exit status of a test program, +// shows a failure due to a specific signal. Returns whether we found +// the expected signal. +func expectSignal(t *testing.T, err error, sig syscall.Signal) bool { + if err == nil { + t.Error("test program succeeded unexpectedly") + } else 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() != sig { + t.Errorf("got %v; expected signal %v", ee, sig) + } else { + return true + } + return false +} + func TestOsSignal(t *testing.T) { switch GOOS { case "windows": @@ -585,3 +591,85 @@ func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool { } return false } + +func TestSIGPROF(t *testing.T) { + switch GOOS { + case "windows", "plan9": + t.Skipf("skipping SIGPROF test on %s", GOOS) + } + + t.Parallel() + + defer func() { + os.Remove("testp6" + exeSuffix) + os.Remove("libgo6.a") + os.Remove("libgo6.h") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo6.a", "libgo6") + cmd.Env = gopathEnv + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } + if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } + + argv := cmdToRun("./testp6") + cmd = exec.Command(argv[0], argv[1:]...) + if out, err := cmd.CombinedOutput(); err != nil { + t.Logf("%s", out) + t.Fatal(err) + } +} + +// TestCompileWithoutShared tests that if we compile code without the +// -shared option, we can put it into an archive. When we use the go +// tool with -buildmode=c-archive, it passes -shared to the compiler, +// so we override that. The go tool doesn't work this way, but Bazel +// will likely do it in the future. And it ought to work. This test +// was added because at one time it did not work on PPC GNU/Linux. +func TestCompileWithoutShared(t *testing.T) { + // For simplicity, reuse the signal forwarding test. + checkSignalForwardingTest(t) + + defer func() { + os.Remove("libgo2.a") + os.Remove("libgo2.h") + }() + + cmd := exec.Command("go", "build", "-buildmode=c-archive", "-gcflags=-shared=false", "-o", "libgo2.a", "libgo2") + cmd.Env = gopathEnv + t.Log(cmd.Args) + out, err := cmd.CombinedOutput() + t.Logf("%s", out) + if err != nil { + t.Fatal(err) + } + + exe := "./testnoshared" + exeSuffix + ccArgs := append(cc, "-o", exe, "main5.c", "libgo2.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } + t.Log(ccArgs) + out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput() + t.Logf("%s", out) + if err != nil { + t.Fatal(err) + } + defer os.Remove(exe) + + binArgs := append(cmdToRun(exe), "3") + t.Log(binArgs) + out, err = exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput() + t.Logf("%s", out) + expectSignal(t, err, syscall.SIGPIPE) +} diff --git a/libgo/misc/cgo/testcarchive/main2.c b/libgo/misc/cgo/testcarchive/main2.c index 774e014..769cd49 100644 --- a/libgo/misc/cgo/testcarchive/main2.c +++ b/libgo/misc/cgo/testcarchive/main2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "libgo2.h" @@ -26,6 +27,7 @@ static void die(const char* msg) { } static volatile sig_atomic_t sigioSeen; +static volatile sig_atomic_t sigpipeSeen; // Use up some stack space. static void recur(int i, char *p) { @@ -37,6 +39,10 @@ static void recur(int i, char *p) { } } +static void pipeHandler(int signo, siginfo_t* info, void* ctxt) { + sigpipeSeen = 1; +} + // 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]; @@ -106,6 +112,10 @@ static void init() { die("sigaction"); } + sa.sa_sigaction = pipeHandler; + if (sigaction(SIGPIPE, &sa, NULL) < 0) { + die("sigaction"); + } } int main(int argc, char** argv) { @@ -167,7 +177,30 @@ int main(int argc, char** argv) { nanosleep(&ts, NULL); i++; if (i > 5000) { - fprintf(stderr, "looping too long waiting for signal\n"); + fprintf(stderr, "looping too long waiting for SIGIO\n"); + exit(EXIT_FAILURE); + } + } + + if (verbose) { + printf("provoking SIGPIPE\n"); + } + + GoRaiseSIGPIPE(); + + if (verbose) { + printf("waiting for sigpipeSeen\n"); + } + + // Wait until the signal has been delivered. + i = 0; + while (!sigpipeSeen) { + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); + i++; + if (i > 5000) { + fprintf(stderr, "looping too long waiting for SIGPIPE\n"); exit(EXIT_FAILURE); } } diff --git a/libgo/misc/cgo/testcarchive/main3.c b/libgo/misc/cgo/testcarchive/main3.c index 0a6c0d3..60a16cf 100644 --- a/libgo/misc/cgo/testcarchive/main3.c +++ b/libgo/misc/cgo/testcarchive/main3.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "libgo3.h" @@ -25,6 +26,31 @@ static void ioHandler(int signo, siginfo_t* info, void* ctxt) { sigioSeen = 1; } +// Set up the SIGPIPE signal handler in a high priority constructor, so +// that it is installed before the Go code starts. + +static void pipeHandler(int signo, siginfo_t* info, void* ctxt) { + const char *s = "unexpected SIGPIPE\n"; + write(2, s, strlen(s)); + exit(EXIT_FAILURE); +} + +static void init(void) __attribute__ ((constructor (200))); + +static void init() { + struct sigaction sa; + + memset(&sa, 0, sizeof sa); + sa.sa_sigaction = pipeHandler; + if (sigemptyset(&sa.sa_mask) < 0) { + die("sigemptyset"); + } + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGPIPE, &sa, NULL) < 0) { + die("sigaction"); + } +} + int main(int argc, char** argv) { int verbose; struct sigaction sa; @@ -35,6 +61,14 @@ int main(int argc, char** argv) { setvbuf(stdout, NULL, _IONBF, 0); if (verbose) { + printf("raising SIGPIPE\n"); + } + + // Test that the Go runtime handles SIGPIPE, even if we installed + // a non-default SIGPIPE handler before the runtime initializes. + ProvokeSIGPIPE(); + + if (verbose) { printf("calling sigaction\n"); } diff --git a/libgo/misc/cgo/testcarchive/main5.c b/libgo/misc/cgo/testcarchive/main5.c index 9fadf08..2437bf0 100644 --- a/libgo/misc/cgo/testcarchive/main5.c +++ b/libgo/misc/cgo/testcarchive/main5.c @@ -68,6 +68,24 @@ int main(int argc, char** argv) { break; } + case 3: { + if (verbose) { + printf("attempting SIGPIPE\n"); + } + + int fd[2]; + if (pipe(fd) != 0) { + printf("pipe(2) failed\n"); + return 0; + } + // Close the reading end. + close(fd[0]); + // Expect that write(2) fails (EPIPE) + if (write(fd[1], "some data", 9) != -1) { + printf("write(2) unexpectedly succeeded\n"); + return 0; + } + } default: printf("Unknown test: %d\n", test); return 0; diff --git a/libgo/misc/cgo/testcarchive/main6.c b/libgo/misc/cgo/testcarchive/main6.c new file mode 100644 index 0000000..2745eb9 --- /dev/null +++ b/libgo/misc/cgo/testcarchive/main6.c @@ -0,0 +1,34 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test that using the Go profiler in a C program does not crash. + +#include +#include + +#include "libgo6.h" + +int main(int argc, char **argv) { + struct timeval tvstart, tvnow; + int diff; + + gettimeofday(&tvstart, NULL); + + go_start_profile(); + + // Busy wait so we have something to profile. + // If we just sleep the profiling signal will never fire. + while (1) { + 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; + } + + go_stop_profile(); + return 0; +} diff --git a/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go b/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go index fbed493..19c8e1a 100644 --- a/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go +++ b/libgo/misc/cgo/testcarchive/src/libgo2/libgo2.go @@ -4,6 +4,30 @@ package main +/* +#include +#include +#include +#include + +// Raise SIGPIPE. +static void CRaiseSIGPIPE() { + int fds[2]; + + if (pipe(fds) == -1) { + perror("pipe"); + exit(EXIT_FAILURE); + } + // Close the reader end + close(fds[0]); + // Write to the writer end to provoke a SIGPIPE + if (write(fds[1], "some data", 9) != -1) { + fprintf(stderr, "write to a closed pipe succeeded\n"); + exit(EXIT_FAILURE); + } + close(fds[1]); +} +*/ import "C" import ( @@ -46,5 +70,11 @@ func TestSEGV() { func Noop() { } +// Raise SIGPIPE. +//export GoRaiseSIGPIPE +func GoRaiseSIGPIPE() { + C.CRaiseSIGPIPE() +} + func main() { } diff --git a/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go b/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go index 94e5d21c..e276a3c 100644 --- a/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go +++ b/libgo/misc/cgo/testcarchive/src/libgo3/libgo3.go @@ -40,5 +40,17 @@ func SawSIGIO() C.int { } } +// ProvokeSIGPIPE provokes a kernel-initiated SIGPIPE. +//export ProvokeSIGPIPE +func ProvokeSIGPIPE() { + r, w, err := os.Pipe() + if err != nil { + panic(err) + } + r.Close() + defer w.Close() + w.Write([]byte("some data")) +} + func main() { } diff --git a/libgo/misc/cgo/testcarchive/src/libgo6/sigprof.go b/libgo/misc/cgo/testcarchive/src/libgo6/sigprof.go new file mode 100644 index 0000000..4cb05dc --- /dev/null +++ b/libgo/misc/cgo/testcarchive/src/libgo6/sigprof.go @@ -0,0 +1,25 @@ +// 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 ( + "io/ioutil" + "runtime/pprof" +) + +import "C" + +//export go_start_profile +func go_start_profile() { + pprof.StartCPUProfile(ioutil.Discard) +} + +//export go_stop_profile +func go_stop_profile() { + pprof.StopCPUProfile() +} + +func main() { +} diff --git a/libgo/misc/cgo/testcshared/main0.c b/libgo/misc/cgo/testcshared/main0.c index 1274b89..39ef7e3 100644 --- a/libgo/misc/cgo/testcshared/main0.c +++ b/libgo/misc/cgo/testcshared/main0.c @@ -12,6 +12,7 @@ // int8_t DidInitRun(); // int8_t DidMainRun(); // int32_t FromPkg(); +// uint32_t Divu(uint32_t, uint32_t); int main(void) { int8_t ran_init = DidInitRun(); if (!ran_init) { @@ -30,6 +31,11 @@ int main(void) { fprintf(stderr, "ERROR: FromPkg=%d, want %d\n", from_pkg, 1024); return 1; } + uint32_t divu = Divu(2264, 31); + if (divu != 73) { + fprintf(stderr, "ERROR: Divu(2264, 31)=%d, want %d\n", divu, 73); + return 1; + } // test.bash looks for "PASS" to ensure this program has reached the end. printf("PASS\n"); return 0; diff --git a/libgo/misc/cgo/testcshared/src/p/p.go b/libgo/misc/cgo/testcshared/src/p/p.go index 82b445c..0f02cf3 100644 --- a/libgo/misc/cgo/testcshared/src/p/p.go +++ b/libgo/misc/cgo/testcshared/src/p/p.go @@ -8,3 +8,6 @@ import "C" //export FromPkg func FromPkg() int32 { return 1024 } + +//export Divu +func Divu(a, b uint32) uint32 { return a / b } diff --git a/libgo/misc/cgo/testcshared/test.bash b/libgo/misc/cgo/testcshared/test.bash index 0315fb0..315a0d4 100644 --- a/libgo/misc/cgo/testcshared/test.bash +++ b/libgo/misc/cgo/testcshared/test.bash @@ -27,7 +27,7 @@ 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 +if [ "${goos}" = "darwin" ]; then installdir=pkg/${goos}_${goarch}_testcshared fi @@ -40,13 +40,13 @@ function cleanup() { rm -f testp testp2 testp3 testp4 testp5 rm -rf pkg "${goroot}/${installdir}" - if [ "$goos" == "android" ]; then + if [ "$goos" = "android" ]; then adb shell rm -rf "$androidpath" fi } trap cleanup EXIT -if [ "$goos" == "android" ]; then +if [ "$goos" = "android" ]; then adb shell mkdir -p "$androidpath" fi @@ -69,7 +69,7 @@ function run() { function binpush() { bin=${1} - if [ "$goos" == "android" ]; then + if [ "$goos" = "android" ]; then adb push "$bin" "${androidpath}/${bin}" 2>/dev/null fi } @@ -79,7 +79,7 @@ rm -rf pkg suffix="-installsuffix testcshared" libext="so" -if [ "$goos" == "darwin" ]; then +if [ "$goos" = "darwin" ]; then libext="dylib" fi @@ -89,7 +89,7 @@ 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 [ "$goos" = "linux" ] || [ "$goos" = "android" ] ; then if readelf -d libgo.$libext | grep TEXTREL >/dev/null; then echo "libgo.$libext has TEXTREL set" exit 1 @@ -97,8 +97,8 @@ if [ "$goos" == "linux" ] || [ "$goos" == "android" ] ; then fi GOGCCFLAGS=$(go env GOGCCFLAGS) -if [ "$goos" == "android" ]; then - GOGCCFLAGS="${GOGCCFLAGS} -pie" +if [ "$goos" = "android" ]; then + GOGCCFLAGS="${GOGCCFLAGS} -pie -fuse-ld=gold" fi status=0 @@ -127,7 +127,7 @@ fi GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext libgo2 binpush libgo2.$libext linkflags="-Wl,--no-as-needed" -if [ "$goos" == "darwin" ]; then +if [ "$goos" = "darwin" ]; then linkflags="" fi $(go env CC) ${GOGCCFLAGS} -o testp2 main2.c $linkflags libgo2.$libext @@ -139,7 +139,7 @@ if [ "$output" != "PASS" ]; then fi # test3: tests main.main is exported on android. -if [ "$goos" == "android" ]; then +if [ "$goos" = "android" ]; then $(go env CC) ${GOGCCFLAGS} -o testp3 main3.c -ldl binpush testp3 output=$(run ./testp ./libgo.so) diff --git a/libgo/misc/cgo/testplugin/src/issue19534/main.go b/libgo/misc/cgo/testplugin/src/issue19534/main.go new file mode 100644 index 0000000..de263b6 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue19534/main.go @@ -0,0 +1,23 @@ +// 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 "plugin" + +func main() { + p, err := plugin.Open("plugin.so") + if err != nil { + panic(err) + } + + sym, err := p.Lookup("Foo") + if err != nil { + panic(err) + } + f := sym.(func() int) + if f() != 42 { + panic("expected f() == 42") + } +} diff --git a/libgo/misc/cgo/testplugin/src/issue19534/plugin.go b/libgo/misc/cgo/testplugin/src/issue19534/plugin.go new file mode 100644 index 0000000..582d333 --- /dev/null +++ b/libgo/misc/cgo/testplugin/src/issue19534/plugin.go @@ -0,0 +1,9 @@ +// 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 + +func Foo() int { + return 42 +} diff --git a/libgo/misc/cgo/testplugin/test.bash b/libgo/misc/cgo/testplugin/test.bash index ab7430a..69df5bd 100644 --- a/libgo/misc/cgo/testplugin/test.bash +++ b/libgo/misc/cgo/testplugin/test.bash @@ -16,7 +16,7 @@ goarch=$(go env GOARCH) function cleanup() { rm -f plugin*.so unnamed*.so iface*.so - rm -rf host pkg sub iface issue18676 + rm -rf host pkg sub iface issue18676 issue19534 } trap cleanup EXIT @@ -44,3 +44,9 @@ LD_LIBRARY_PATH=$(pwd) ./iface 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 + +# Test for issue 19534 - that we can load a plugin built in a path with non-alpha +# characters +GOPATH=$(pwd) go build -buildmode=plugin -ldflags='-pluginpath=issue.19534' -o plugin.so src/issue19534/plugin.go +GOPATH=$(pwd) go build -o issue19534 src/issue19534/main.go +./issue19534 diff --git a/libgo/misc/cgo/testplugin/unnamed1.go b/libgo/misc/cgo/testplugin/unnamed1.go index 102edaf..5c1df08 100644 --- a/libgo/misc/cgo/testplugin/unnamed1.go +++ b/libgo/misc/cgo/testplugin/unnamed1.go @@ -9,4 +9,15 @@ import "C" func FuncInt() int { return 1 } +// Add a recursive type to to check that type equality across plugins doesn't +// crash. See https://golang.org/issues/19258 +func FuncRecursive() X { return X{} } + +type Y struct { + X *X +} +type X struct { + Y Y +} + func main() {} diff --git a/libgo/misc/cgo/testplugin/unnamed2.go b/libgo/misc/cgo/testplugin/unnamed2.go index 55070d5..7ef6610 100644 --- a/libgo/misc/cgo/testplugin/unnamed2.go +++ b/libgo/misc/cgo/testplugin/unnamed2.go @@ -9,4 +9,13 @@ import "C" func FuncInt() int { return 2 } +func FuncRecursive() X { return X{} } + +type Y struct { + X *X +} +type X struct { + Y Y +} + func main() {} diff --git a/libgo/misc/cgo/testsanitizers/test.bash b/libgo/misc/cgo/testsanitizers/test.bash index 4da8502..9f80af6 100644 --- a/libgo/misc/cgo/testsanitizers/test.bash +++ b/libgo/misc/cgo/testsanitizers/test.bash @@ -72,12 +72,12 @@ testmsanshared() { goos=$(go env GOOS) suffix="-installsuffix testsanitizers" libext="so" - if [ "$goos" == "darwin" ]; then + 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 + 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 @@ -131,21 +131,43 @@ if test "$msan" = "yes"; then testmsanshared fi +testtsanshared() { + goos=$(go env GOOS) + suffix="-installsuffix tsan" + libext="so" + if [ "$goos" = "darwin" ]; then + libext="dylib" + fi + go build -buildmode=c-shared $suffix -o ${TMPDIR}/libtsanshared.$libext tsan_shared.go + + echo 'int main() { return 0; }' > ${TMPDIR}/testtsanshared.c + $CC $(go env GOGCCFLAGS) -fsanitize=thread -o ${TMPDIR}/testtsanshared ${TMPDIR}/testtsanshared.c ${TMPDIR}/libtsanshared.$libext + + if ! LD_LIBRARY_PATH=. ${TMPDIR}/testtsanshared; then + echo "FAIL: tsan_shared" + status=1 + fi + rm -f ${TMPDIR}/{testtsanshared,testtsanshared.c,libtsanshared.$libext} +} + 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 + 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$$* + elif test "$ok" != "yes"; then + cat ${TMPDIR}/testsanitizers$$.err + echo "skipping tsan tests: -fsanitizer=thread build failed" + tsan=no + elif ! ${TMPDIR}/testsanitizers$$ 2>&1; then + echo "skipping tsan tests: running tsan program failed" + tsan=no + fi + rm -f ${TMPDIR}/testsanitizers$$* fi # Run a TSAN test. @@ -177,8 +199,10 @@ if test "$tsan" = "yes"; then # 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 + clang=false if ${CC} --version | grep clang >/dev/null 2>&1; then ok=true + clang=true else ver=$($CC -dumpversion) major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/') @@ -190,14 +214,19 @@ if test "$tsan" = "yes"; then fi if test "$ok" = "true"; then - # This test requires rebuilding os/user with -fsanitize=thread. + # These tests require 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" + + # The remaining tests reportedly hang when built with GCC; issue #21196. + if test "$clang" = "true"; then + testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan" + fi + + testtsanshared fi fi diff --git a/libgo/misc/cgo/testsanitizers/tsan10.go b/libgo/misc/cgo/testsanitizers/tsan10.go new file mode 100644 index 0000000..a40f245 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan10.go @@ -0,0 +1,31 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// This program hung when run under the C/C++ ThreadSanitizer. +// TSAN defers asynchronous signals until the signaled thread calls into libc. +// Since the Go runtime makes direct futex syscalls, Go runtime threads could +// run for an arbitrarily long time without triggering the libc interceptors. +// See https://golang.org/issue/18717. + +import ( + "os" + "os/signal" + "syscall" +) + +/* +#cgo CFLAGS: -g -fsanitize=thread +#cgo LDFLAGS: -g -fsanitize=thread +*/ +import "C" + +func main() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGUSR1) + defer signal.Stop(c) + syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) + <-c +} diff --git a/libgo/misc/cgo/testsanitizers/tsan11.go b/libgo/misc/cgo/testsanitizers/tsan11.go new file mode 100644 index 0000000..70ac9c8 --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan11.go @@ -0,0 +1,55 @@ +// 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 + +// This program hung when run under the C/C++ ThreadSanitizer. TSAN defers +// asynchronous signals until the signaled thread calls into libc. The runtime's +// sysmon goroutine idles itself using direct usleep syscalls, so it could +// run for an arbitrarily long time without triggering the libc interceptors. +// See https://golang.org/issue/18717. + +import ( + "os" + "os/signal" + "syscall" +) + +/* +#cgo CFLAGS: -g -fsanitize=thread +#cgo LDFLAGS: -g -fsanitize=thread + +#include +#include +#include +#include + +static void raise_usr2(int signo) { + raise(SIGUSR2); +} + +static void register_handler(int signo) { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + sa.sa_handler = raise_usr2; + + if (sigaction(SIGUSR1, &sa, NULL) != 0) { + perror("failed to register SIGUSR1 handler"); + exit(EXIT_FAILURE); + } +} +*/ +import "C" + +func main() { + ch := make(chan os.Signal) + signal.Notify(ch, syscall.SIGUSR2) + + C.register_handler(C.int(syscall.SIGUSR1)) + syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) + + <-ch +} diff --git a/libgo/misc/cgo/testsanitizers/tsan12.go b/libgo/misc/cgo/testsanitizers/tsan12.go new file mode 100644 index 0000000..3e767ee --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan12.go @@ -0,0 +1,35 @@ +// 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 + +// This program hung when run under the C/C++ ThreadSanitizer. TSAN installs a +// libc interceptor that writes signal handlers to a global variable within the +// TSAN runtime instead of making a sigaction system call. A bug in +// syscall.runtime_AfterForkInChild corrupted TSAN's signal forwarding table +// during calls to (*os/exec.Cmd).Run, causing the parent process to fail to +// invoke signal handlers. + +import ( + "fmt" + "os" + "os/exec" + "os/signal" + "syscall" +) + +import "C" + +func main() { + ch := make(chan os.Signal) + signal.Notify(ch, syscall.SIGUSR1) + + if err := exec.Command("true").Run(); err != nil { + fmt.Fprintf(os.Stderr, "Unexpected error from `true`: %v", err) + os.Exit(1) + } + + syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) + <-ch +} diff --git a/libgo/misc/cgo/testsanitizers/tsan_shared.go b/libgo/misc/cgo/testsanitizers/tsan_shared.go new file mode 100644 index 0000000..55ff67e --- /dev/null +++ b/libgo/misc/cgo/testsanitizers/tsan_shared.go @@ -0,0 +1,63 @@ +// 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 + +// This program failed with SIGSEGV when run under the C/C++ ThreadSanitizer. +// The Go runtime had re-registered the C handler with the wrong flags due to a +// typo, resulting in null pointers being passed for the info and context +// parameters to the handler. + +/* +#cgo CFLAGS: -fsanitize=thread +#cgo LDFLAGS: -fsanitize=thread + +#include +#include +#include +#include +#include + +void check_params(int signo, siginfo_t *info, void *context) { + ucontext_t* uc = (ucontext_t*)(context); + + if (info->si_signo != signo) { + fprintf(stderr, "info->si_signo does not match signo.\n"); + abort(); + } + + if (uc->uc_stack.ss_size == 0) { + fprintf(stderr, "uc_stack has size 0.\n"); + abort(); + } +} + + +// Set up the signal handler in a high priority constructor, so +// that it is installed before the Go code starts. + +static void register_handler(void) __attribute__ ((constructor (200))); + +static void register_handler() { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = check_params; + + if (sigaction(SIGUSR1, &sa, NULL) != 0) { + perror("failed to register SIGUSR1 handler"); + exit(EXIT_FAILURE); + } +} +*/ +import "C" + +import "syscall" + +func init() { + C.raise(C.int(syscall.SIGUSR1)) +} + +func main() {} diff --git a/libgo/misc/cgo/testshared/shared_test.go b/libgo/misc/cgo/testshared/shared_test.go index f0766e5..9e682a2 100644 --- a/libgo/misc/cgo/testshared/shared_test.go +++ b/libgo/misc/cgo/testshared/shared_test.go @@ -10,7 +10,6 @@ import ( "debug/elf" "encoding/binary" "errors" - "flag" "fmt" "go/build" "io" @@ -166,7 +165,6 @@ func TestMain(m *testing.M) { // That won't work if GOBIN is set. os.Unsetenv("GOBIN") - flag.Parse() exitCode, err := testMain(m) if err != nil { log.Fatal(err) @@ -402,6 +400,12 @@ func TestTrivialExecutablePIE(t *testing.T) { AssertHasRPath(t, "./trivial.pie", gorootInstallDir) } +// Build a division test program and check it runs. +func TestDivisionExecutable(t *testing.T) { + goCmd(t, "install", "-linkshared", "division") + run(t, "division executable", "./bin/division") +} + // Build an executable that uses cgo linked against the shared runtime and check it // runs. func TestCgoExecutable(t *testing.T) { @@ -759,6 +763,13 @@ func appendFile(path, content string) { } } +func writeFile(path, content string) { + err := ioutil.WriteFile(path, []byte(content), 0644) + if err != nil { + log.Fatalf("ioutil.WriteFile failed: %v", err) + } +} + func TestABIChecking(t *testing.T) { goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") goCmd(t, "install", "-linkshared", "exe") @@ -797,9 +808,10 @@ func TestABIChecking(t *testing.T) { 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. + // function) and rebuild libdepBase.so, exe still works, even if new function + // is in a file by itself. resetFileStamps() - appendFile("src/depBase/dep.go", "func noABIBreak() {}\n") + writeFile("src/depBase/dep2.go", "package depBase\nfunc noABIBreak() {}\n") goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase") run(t, "after non-ABI breaking change", "./bin/exe") } diff --git a/libgo/misc/cgo/testshared/src/division/division.go b/libgo/misc/cgo/testshared/src/division/division.go new file mode 100644 index 0000000..bb5fc98 --- /dev/null +++ b/libgo/misc/cgo/testshared/src/division/division.go @@ -0,0 +1,17 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +//go:noinline +func div(x, y uint32) uint32 { + return x / y +} + +func main() { + a := div(97, 11) + if a != 8 { + panic("FAIL") + } +} -- cgit v1.1