github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/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_create(&th, 0, thr, 0);
   226      pthread_join(th, 0);
   227  }
   228  */
   229  import "C"
   230  import "fmt"
   231  
   232  //export go_callback
   233  func go_callback() {
   234  	runtime.GC()
   235  	grow()
   236  	runtime.GC()
   237  }
   238  
   239  var cnt int
   240  
   241  func grow() {
   242  	x := 10000
   243  	sum := 0
   244  	if grow1(&x, &sum) == 0 {
   245  		panic("bad")
   246  	}
   247  }
   248  
   249  func grow1(x, sum *int) int {
   250  	if *x == 0 {
   251  		return *sum + 1
   252  	}
   253  	*x--
   254  	sum1 := *sum + *x
   255  	return grow1(x, &sum1)
   256  }
   257  
   258  func main() {
   259  	const P = 100
   260  	done := make(chan bool)
   261  	// allocate a bunch of stack frames and spray them with pointers
   262  	for i := 0; i < P; i++ {
   263  		go func() {
   264  			grow()
   265  			done <- true
   266  		}()
   267  	}
   268  	for i := 0; i < P; i++ {
   269  		<-done
   270  	}
   271  	// now give these stack frames to cgo callbacks
   272  	for i := 0; i < P; i++ {
   273  		go func() {
   274  			C.foo()
   275  			done <- true
   276  		}()
   277  	}
   278  	for i := 0; i < P; i++ {
   279  		<-done
   280  	}
   281  	fmt.Printf("OK\n")
   282  }
   283  `
   284  
   285  const cgoExternalThreadPanicSource = `
   286  package main
   287  
   288  // void start(void);
   289  import "C"
   290  
   291  func main() {
   292  	C.start()
   293  	select {}
   294  }
   295  
   296  //export gopanic
   297  func gopanic() {
   298  	panic("BOOM")
   299  }
   300  `
   301  
   302  const cgoExternalThreadPanicC = `
   303  #include <stdlib.h>
   304  #include <stdio.h>
   305  #include <pthread.h>
   306  
   307  void gopanic(void);
   308  
   309  static void*
   310  die(void* x)
   311  {
   312  	gopanic();
   313  	return 0;
   314  }
   315  
   316  void
   317  start(void)
   318  {
   319  	pthread_t t;
   320  	if(pthread_create(&t, 0, die, 0) != 0)
   321  		printf("pthread_create failed\n");
   322  }
   323  `
   324  
   325  const cgoExternalThreadPanicC_windows = `
   326  #include <stdlib.h>
   327  #include <stdio.h>
   328  
   329  void gopanic(void);
   330  
   331  static void*
   332  die(void* x)
   333  {
   334  	gopanic();
   335  	return 0;
   336  }
   337  
   338  void
   339  start(void)
   340  {
   341  	if(_beginthreadex(0, 0, die, 0, 0, 0) != 0)
   342  		printf("_beginthreadex failed\n");
   343  }
   344  `
   345  
   346  const cgoExternalThreadSIGPROFSource = `
   347  package main
   348  
   349  /*
   350  #include <stdint.h>
   351  #include <signal.h>
   352  #include <pthread.h>
   353  
   354  volatile int32_t spinlock;
   355  
   356  static void *thread1(void *p) {
   357  	(void)p;
   358  	while (spinlock == 0)
   359  		;
   360  	pthread_kill(pthread_self(), SIGPROF);
   361  	spinlock = 0;
   362  	return NULL;
   363  }
   364  __attribute__((constructor)) void issue9456() {
   365  	pthread_t tid;
   366  	pthread_create(&tid, 0, thread1, NULL);
   367  }
   368  */
   369  import "C"
   370  
   371  import (
   372  	"runtime"
   373  	"sync/atomic"
   374  	"unsafe"
   375  )
   376  
   377  func main() {
   378  	// This test intends to test that sending SIGPROF to foreign threads
   379  	// before we make any cgo call will not abort the whole process, so
   380  	// we cannot make any cgo call here. See https://golang.org/issue/9456.
   381  	atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
   382  	for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
   383  		runtime.Gosched()
   384  	}
   385  	println("OK")
   386  }
   387  `
   388  
   389  const cgoExternalThreadSignalSource = `
   390  package main
   391  
   392  /*
   393  #include <pthread.h>
   394  
   395  void **nullptr;
   396  
   397  void *crash(void *p) {
   398  	*nullptr = p;
   399  	return 0;
   400  }
   401  
   402  int start_crashing_thread(void) {
   403  	pthread_t tid;
   404  	return pthread_create(&tid, 0, crash, 0);
   405  }
   406  */
   407  import "C"
   408  
   409  import (
   410  	"fmt"
   411  	"os"
   412  	"os/exec"
   413  	"time"
   414  )
   415  
   416  func main() {
   417  	if len(os.Args) > 1 && os.Args[1] == "crash" {
   418  		i := C.start_crashing_thread()
   419  		if i != 0 {
   420  			fmt.Println("pthread_create failed:", i)
   421  			// Exit with 0 because parent expects us to crash.
   422  			return
   423  		}
   424  
   425  		// We should crash immediately, but give it plenty of
   426  		// time before failing (by exiting 0) in case we are
   427  		// running on a slow system.
   428  		time.Sleep(5 * time.Second)
   429  		return
   430  	}
   431  
   432  	out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
   433  	if err == nil {
   434  		fmt.Println("C signal did not crash as expected\n")
   435  		fmt.Printf("%s\n", out)
   436  		os.Exit(1)
   437  	}
   438  
   439  	fmt.Println("OK")
   440  }
   441  `
   442  
   443  const cgoDLLImportsMainSource = `
   444  package main
   445  
   446  /*
   447  #include <windows.h>
   448  
   449  DWORD getthread() {
   450  	return GetCurrentThreadId();
   451  }
   452  */
   453  import "C"
   454  
   455  import "./a"
   456  
   457  func main() {
   458  	C.getthread()
   459  	a.GetThread()
   460  	println("OK")
   461  }
   462  `
   463  
   464  const cgoDLLImportsPkgSource = `
   465  package a
   466  
   467  /*
   468  #cgo CFLAGS: -mnop-fun-dllimport
   469  
   470  #include <windows.h>
   471  
   472  DWORD agetthread() {
   473  	return GetCurrentThreadId();
   474  }
   475  */
   476  import "C"
   477  
   478  func GetThread() uint32 {
   479  	return uint32(C.agetthread())
   480  }
   481  `