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