diff options
Diffstat (limited to 'libgo/go/runtime/crash_cgo_test.go')
-rw-r--r-- | libgo/go/runtime/crash_cgo_test.go | 237 |
1 files changed, 227 insertions, 10 deletions
diff --git a/libgo/go/runtime/crash_cgo_test.go b/libgo/go/runtime/crash_cgo_test.go index 29f90fa36d2..2e65e4c7543 100644 --- a/libgo/go/runtime/crash_cgo_test.go +++ b/libgo/go/runtime/crash_cgo_test.go @@ -36,6 +36,20 @@ func TestCgoTraceback(t *testing.T) { } } +func TestCgoCallbackGC(t *testing.T) { + if runtime.GOOS == "plan9" || runtime.GOOS == "windows" { + t.Skipf("no pthreads on %s", runtime.GOOS) + } + if testing.Short() && runtime.GOOS == "dragonfly" { + t.Skip("see golang.org/issue/11990") + } + got := executeTest(t, cgoCallbackGCSource, nil) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %q", want, got) + } +} + func TestCgoExternalThreadPanic(t *testing.T) { if runtime.GOOS == "plan9" { t.Skipf("no pthreads on %s", runtime.GOOS) @@ -57,17 +71,24 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) { case "plan9", "windows": t.Skipf("no pthreads on %s", runtime.GOOS) case "darwin": - // static constructor needs external linking, but we don't support - // external linking on OS X 10.6. - out, err := exec.Command("uname", "-r").Output() - if err != nil { - t.Fatalf("uname -r failed: %v", err) - } - // OS X 10.6 == Darwin 10.x - if strings.HasPrefix(string(out), "10.") { - t.Skipf("no external linking on OS X 10.6") + if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" { + // static constructor needs external linking, but we don't support + // external linking on OS X 10.6. + out, err := exec.Command("uname", "-r").Output() + if err != nil { + t.Fatalf("uname -r failed: %v", err) + } + // OS X 10.6 == Darwin 10.x + if strings.HasPrefix(string(out), "10.") { + t.Skipf("no external linking on OS X 10.6") + } } } + if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { + // TODO(austin) External linking not implemented on + // ppc64 (issue #8912) + t.Skipf("no external linking on ppc64") + } got := executeTest(t, cgoExternalThreadSIGPROFSource, nil) want := "OK\n" if got != want { @@ -75,6 +96,31 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) { } } +func TestCgoExternalThreadSignal(t *testing.T) { + // issue 10139 + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("no pthreads on %s", runtime.GOOS) + } + got := executeTest(t, cgoExternalThreadSignalSource, nil) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %q", want, got) + } +} + +func TestCgoDLLImports(t *testing.T) { + // test issue 9356 + if runtime.GOOS != "windows" { + t.Skip("skipping windows specific test") + } + got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %v", want, got) + } +} + const cgoSignalDeadlockSource = ` package main @@ -159,6 +205,83 @@ func main() { } ` +const cgoCallbackGCSource = ` +package main + +import "runtime" + +/* +#include <pthread.h> + +void go_callback(); + +static void *thr(void *arg) { + go_callback(); + return 0; +} + +static void foo() { + pthread_t th; + pthread_create(&th, 0, thr, 0); + pthread_join(th, 0); +} +*/ +import "C" +import "fmt" + +//export go_callback +func go_callback() { + runtime.GC() + grow() + runtime.GC() +} + +var cnt int + +func grow() { + x := 10000 + sum := 0 + if grow1(&x, &sum) == 0 { + panic("bad") + } +} + +func grow1(x, sum *int) int { + if *x == 0 { + return *sum + 1 + } + *x-- + sum1 := *sum + *x + return grow1(x, &sum1) +} + +func main() { + const P = 100 + done := make(chan bool) + // allocate a bunch of stack frames and spray them with pointers + for i := 0; i < P; i++ { + go func() { + grow() + done <- true + }() + } + for i := 0; i < P; i++ { + <-done + } + // now give these stack frames to cgo callbacks + for i := 0; i < P; i++ { + go func() { + C.foo() + done <- true + }() + } + for i := 0; i < P; i++ { + <-done + } + fmt.Printf("OK\n") +} +` + const cgoExternalThreadPanicSource = ` package main @@ -254,7 +377,7 @@ import ( func main() { // This test intends to test that sending SIGPROF to foreign threads // before we make any cgo call will not abort the whole process, so - // we cannot make any cgo call here. See http://golang.org/issue/9456. + // we cannot make any cgo call here. See https://golang.org/issue/9456. atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1) for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 { runtime.Gosched() @@ -262,3 +385,97 @@ func main() { println("OK") } ` + +const cgoExternalThreadSignalSource = ` +package main + +/* +#include <pthread.h> + +void **nullptr; + +void *crash(void *p) { + *nullptr = p; + return 0; +} + +int start_crashing_thread(void) { + pthread_t tid; + return pthread_create(&tid, 0, crash, 0); +} +*/ +import "C" + +import ( + "fmt" + "os" + "os/exec" + "time" +) + +func main() { + if len(os.Args) > 1 && os.Args[1] == "crash" { + i := C.start_crashing_thread() + if i != 0 { + fmt.Println("pthread_create failed:", i) + // Exit with 0 because parent expects us to crash. + return + } + + // We should crash immediately, but give it plenty of + // time before failing (by exiting 0) in case we are + // running on a slow system. + time.Sleep(5 * time.Second) + return + } + + out, err := exec.Command(os.Args[0], "crash").CombinedOutput() + if err == nil { + fmt.Println("C signal did not crash as expected\n") + fmt.Printf("%s\n", out) + os.Exit(1) + } + + fmt.Println("OK") +} +` + +const cgoDLLImportsMainSource = ` +package main + +/* +#include <windows.h> + +DWORD getthread() { + return GetCurrentThreadId(); +} +*/ +import "C" + +import "./a" + +func main() { + C.getthread() + a.GetThread() + println("OK") +} +` + +const cgoDLLImportsPkgSource = ` +package a + +/* +#cgo CFLAGS: -mnop-fun-dllimport + +#include <windows.h> + +DWORD agetthread() { + return GetCurrentThreadId(); +} +*/ +import "C" + +func GetThread() uint32 { + return uint32(C.agetthread()) +} +` |