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 `