github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/runtime/crash_cgo_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build cgo
     6  
     7  package runtime_test
     8  
     9  import (
    10  	"os/exec"
    11  	"runtime"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func TestCgoCrashHandler(t *testing.T) {
    17  	testCrashHandler(t, true)
    18  }
    19  
    20  func TestCgoSignalDeadlock(t *testing.T) {
    21  	if testing.Short() && runtime.GOOS == "windows" {
    22  		t.Skip("Skipping in short mode") // takes up to 64 seconds
    23  	}
    24  	got := executeTest(t, cgoSignalDeadlockSource, nil)
    25  	want := "OK\n"
    26  	if got != want {
    27  		t.Fatalf("expected %q, but got %q", want, got)
    28  	}
    29  }
    30  
    31  func TestCgoTraceback(t *testing.T) {
    32  	got := executeTest(t, cgoTracebackSource, nil)
    33  	want := "OK\n"
    34  	if got != want {
    35  		t.Fatalf("expected %q, but got %q", want, got)
    36  	}
    37  }
    38  
    39  func TestCgoCallbackGC(t *testing.T) {
    40  	if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
    41  		t.Skipf("no pthreads on %s", runtime.GOOS)
    42  	}
    43  	if testing.Short() && runtime.GOOS == "dragonfly" {
    44  		t.Skip("see golang.org/issue/11990")
    45  	}
    46  	got := executeTest(t, cgoCallbackGCSource, nil)
    47  	want := "OK\n"
    48  	if got != want {
    49  		t.Fatalf("expected %q, but got %q", want, got)
    50  	}
    51  }
    52  
    53  func TestCgoExternalThreadPanic(t *testing.T) {
    54  	if runtime.GOOS == "plan9" {
    55  		t.Skipf("no pthreads on %s", runtime.GOOS)
    56  	}
    57  	csrc := cgoExternalThreadPanicC
    58  	if runtime.GOOS == "windows" {
    59  		csrc = cgoExternalThreadPanicC_windows
    60  	}
    61  	got := executeTest(t, cgoExternalThreadPanicSource, nil, "main.c", csrc)
    62  	want := "panic: BOOM"
    63  	if !strings.Contains(got, want) {
    64  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
    65  	}
    66  }
    67  
    68  func TestCgoExternalThreadSIGPROF(t *testing.T) {
    69  	// issue 9456.
    70  	switch runtime.GOOS {
    71  	case "plan9", "windows":
    72  		t.Skipf("no pthreads on %s", runtime.GOOS)
    73  	case "darwin":
    74  		if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" {
    75  			// static constructor needs external linking, but we don't support
    76  			// external linking on OS X 10.6.
    77  			out, err := exec.Command("uname", "-r").Output()
    78  			if err != nil {
    79  				t.Fatalf("uname -r failed: %v", err)
    80  			}
    81  			// OS X 10.6 == Darwin 10.x
    82  			if strings.HasPrefix(string(out), "10.") {
    83  				t.Skipf("no external linking on OS X 10.6")
    84  			}
    85  		}
    86  	}
    87  	if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
    88  		// TODO(austin) External linking not implemented on
    89  		// ppc64 (issue #8912)
    90  		t.Skipf("no external linking on ppc64")
    91  	}
    92  	got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
    93  	want := "OK\n"
    94  	if got != want {
    95  		t.Fatalf("expected %q, but got %q", want, got)
    96  	}
    97  }
    98  
    99  func TestCgoExternalThreadSignal(t *testing.T) {
   100  	// issue 10139
   101  	switch runtime.GOOS {
   102  	case "plan9", "windows":
   103  		t.Skipf("no pthreads on %s", runtime.GOOS)
   104  	}
   105  	got := executeTest(t, cgoExternalThreadSignalSource, nil)
   106  	want := "OK\n"
   107  	if got != want {
   108  		t.Fatalf("expected %q, but got %q", want, got)
   109  	}
   110  }
   111  
   112  func TestCgoDLLImports(t *testing.T) {
   113  	// test issue 9356
   114  	if runtime.GOOS != "windows" {
   115  		t.Skip("skipping windows specific test")
   116  	}
   117  	got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource)
   118  	want := "OK\n"
   119  	if got != want {
   120  		t.Fatalf("expected %q, but got %v", want, got)
   121  	}
   122  }
   123  
   124  const cgoSignalDeadlockSource = `
   125  package main
   126  
   127  import "C"
   128  
   129  import (
   130  	"fmt"
   131  	"runtime"
   132  	"time"
   133  )
   134  
   135  func main() {
   136  	runtime.GOMAXPROCS(100)
   137  	ping := make(chan bool)
   138  	go func() {
   139  		for i := 0; ; i++ {
   140  			runtime.Gosched()
   141  			select {
   142  			case done := <-ping:
   143  				if done {
   144  					ping <- true
   145  					return
   146  				}
   147  				ping <- true
   148  			default:
   149  			}
   150  			func() {
   151  				defer func() {
   152  					recover()
   153  				}()
   154  				var s *string
   155  				*s = ""
   156  			}()
   157  		}
   158  	}()
   159  	time.Sleep(time.Millisecond)
   160  	for i := 0; i < 64; i++ {
   161  		go func() {
   162  			runtime.LockOSThread()
   163  			select {}
   164  		}()
   165  		go func() {
   166  			runtime.LockOSThread()
   167  			select {}
   168  		}()
   169  		time.Sleep(time.Millisecond)
   170  		ping <- false
   171  		select {
   172  		case <-ping:
   173  		case <-time.After(time.Second):
   174  			fmt.Printf("HANG\n")
   175  			return
   176  		}
   177  	}
   178  	ping <- true
   179  	select {
   180  	case <-ping:
   181  	case <-time.After(time.Second):
   182  		fmt.Printf("HANG\n")
   183  		return
   184  	}
   185  	fmt.Printf("OK\n")
   186  }
   187  `
   188  
   189  const cgoTracebackSource = `
   190  package main
   191  
   192  /* void foo(void) {} */
   193  import "C"
   194  
   195  import (
   196  	"fmt"
   197  	"runtime"
   198  )
   199  
   200  func main() {
   201  	C.foo()
   202  	buf := make([]byte, 1)
   203  	runtime.Stack(buf, true)
   204  	fmt.Printf("OK\n")
   205  }
   206  `
   207  
   208  const cgoCallbackGCSource = `
   209  package main
   210  
   211  import "runtime"
   212  
   213  /*
   214  #include <pthread.h>
   215  
   216  void go_callback();
   217  
   218  static void *thr(void *arg) {
   219      go_callback();
   220      return 0;
   221  }
   222  
   223  static void foo() {
   224      pthread_t th;
   225      pthread_attr_t attr;
   226      pthread_attr_init(&attr);
   227      pthread_attr_setstacksize(&attr, 256 << 10);
   228      pthread_create(&th, &attr, thr, 0);
   229      pthread_join(th, 0);
   230  }
   231  */
   232  import "C"
   233  import "fmt"
   234  
   235  //export go_callback
   236  func go_callback() {
   237  	runtime.GC()
   238  	grow()
   239  	runtime.GC()
   240  }
   241  
   242  var cnt int
   243  
   244  func grow() {
   245  	x := 10000
   246  	sum := 0
   247  	if grow1(&x, &sum) == 0 {
   248  		panic("bad")
   249  	}
   250  }
   251  
   252  func grow1(x, sum *int) int {
   253  	if *x == 0 {
   254  		return *sum + 1
   255  	}
   256  	*x--
   257  	sum1 := *sum + *x
   258  	return grow1(x, &sum1)
   259  }
   260  
   261  func main() {
   262  	const P = 100
   263  	done := make(chan bool)
   264  	// allocate a bunch of stack frames and spray them with pointers
   265  	for i := 0; i < P; i++ {
   266  		go func() {
   267  			grow()
   268  			done <- true
   269  		}()
   270  	}
   271  	for i := 0; i < P; i++ {
   272  		<-done
   273  	}
   274  	// now give these stack frames to cgo callbacks
   275  	for i := 0; i < P; i++ {
   276  		go func() {
   277  			C.foo()
   278  			done <- true
   279  		}()
   280  	}
   281  	for i := 0; i < P; i++ {
   282  		<-done
   283  	}
   284  	fmt.Printf("OK\n")
   285  }
   286  `
   287  
   288  const cgoExternalThreadPanicSource = `
   289  package main
   290  
   291  // void start(void);
   292  import "C"
   293  
   294  func main() {
   295  	C.start()
   296  	select {}
   297  }
   298  
   299  //export gopanic
   300  func gopanic() {
   301  	panic("BOOM")
   302  }
   303  `
   304  
   305  const cgoExternalThreadPanicC = `
   306  #include <stdlib.h>
   307  #include <stdio.h>
   308  #include <pthread.h>
   309  
   310  void gopanic(void);
   311  
   312  static void*
   313  die(void* x)
   314  {
   315  	gopanic();
   316  	return 0;
   317  }
   318  
   319  void
   320  start(void)
   321  {
   322  	pthread_t t;
   323  	if(pthread_create(&t, 0, die, 0) != 0)
   324  		printf("pthread_create failed\n");
   325  }
   326  `
   327  
   328  const cgoExternalThreadPanicC_windows = `
   329  #include <stdlib.h>
   330  #include <stdio.h>
   331  
   332  void gopanic(void);
   333  
   334  static void*
   335  die(void* x)
   336  {
   337  	gopanic();
   338  	return 0;
   339  }
   340  
   341  void
   342  start(void)
   343  {
   344  	if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
   345  		printf("_beginthreadex failed\n");
   346  }
   347  `
   348  
   349  const cgoExternalThreadSIGPROFSource = `
   350  package main
   351  
   352  /*
   353  #include <stdint.h>
   354  #include <signal.h>
   355  #include <pthread.h>
   356  
   357  volatile int32_t spinlock;
   358  
   359  static void *thread1(void *p) {
   360  	(void)p;
   361  	while (spinlock == 0)
   362  		;
   363  	pthread_kill(pthread_self(), SIGPROF);
   364  	spinlock = 0;
   365  	return NULL;
   366  }
   367  __attribute__((constructor)) void issue9456() {
   368  	pthread_t tid;
   369  	pthread_create(&tid, 0, thread1, NULL);
   370  }
   371  */
   372  import "C"
   373  
   374  import (
   375  	"runtime"
   376  	"sync/atomic"
   377  	"unsafe"
   378  )
   379  
   380  func main() {
   381  	// This test intends to test that sending SIGPROF to foreign threads
   382  	// before we make any cgo call will not abort the whole process, so
   383  	// we cannot make any cgo call here. See https://golang.org/issue/9456.
   384  	atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
   385  	for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
   386  		runtime.Gosched()
   387  	}
   388  	println("OK")
   389  }
   390  `
   391  
   392  const cgoExternalThreadSignalSource = `
   393  package main
   394  
   395  /*
   396  #include <pthread.h>
   397  
   398  void **nullptr;
   399  
   400  void *crash(void *p) {
   401  	*nullptr = p;
   402  	return 0;
   403  }
   404  
   405  int start_crashing_thread(void) {
   406  	pthread_t tid;
   407  	return pthread_create(&tid, 0, crash, 0);
   408  }
   409  */
   410  import "C"
   411  
   412  import (
   413  	"fmt"
   414  	"os"
   415  	"os/exec"
   416  	"time"
   417  )
   418  
   419  func main() {
   420  	if len(os.Args) > 1 && os.Args[1] == "crash" {
   421  		i := C.start_crashing_thread()
   422  		if i != 0 {
   423  			fmt.Println("pthread_create failed:", i)
   424  			// Exit with 0 because parent expects us to crash.
   425  			return
   426  		}
   427  
   428  		// We should crash immediately, but give it plenty of
   429  		// time before failing (by exiting 0) in case we are
   430  		// running on a slow system.
   431  		time.Sleep(5 * time.Second)
   432  		return
   433  	}
   434  
   435  	out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
   436  	if err == nil {
   437  		fmt.Println("C signal did not crash as expected\n")
   438  		fmt.Printf("%s\n", out)
   439  		os.Exit(1)
   440  	}
   441  
   442  	fmt.Println("OK")
   443  }
   444  `
   445  
   446  const cgoDLLImportsMainSource = `
   447  package main
   448  
   449  /*
   450  #include <windows.h>
   451  
   452  DWORD getthread() {
   453  	return GetCurrentThreadId();
   454  }
   455  */
   456  import "C"
   457  
   458  import "./a"
   459  
   460  func main() {
   461  	C.getthread()
   462  	a.GetThread()
   463  	println("OK")
   464  }
   465  `
   466  
   467  const cgoDLLImportsPkgSource = `
   468  package a
   469  
   470  /*
   471  #cgo CFLAGS: -mnop-fun-dllimport
   472  
   473  #include <windows.h>
   474  
   475  DWORD agetthread() {
   476  	return GetCurrentThreadId();
   477  }
   478  */
   479  import "C"
   480  
   481  func GetThread() uint32 {
   482  	return uint32(C.agetthread())
   483  }
   484  `