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 "bytes" 11 "fmt" 12 "internal/testenv" 13 "os" 14 "os/exec" 15 "runtime" 16 "strings" 17 "testing" 18 "time" 19 ) 20 21 func TestCgoCrashHandler(t *testing.T) { 22 t.Parallel() 23 testCrashHandler(t, true) 24 } 25 26 func TestCgoSignalDeadlock(t *testing.T) { 27 t.Parallel() 28 if testing.Short() && runtime.GOOS == "windows" { 29 t.Skip("Skipping in short mode") // takes up to 64 seconds 30 } 31 got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock") 32 want := "OK\n" 33 if got != want { 34 t.Fatalf("expected %q, but got:\n%s", want, got) 35 } 36 } 37 38 func TestCgoTraceback(t *testing.T) { 39 t.Parallel() 40 got := runTestProg(t, "testprogcgo", "CgoTraceback") 41 want := "OK\n" 42 if got != want { 43 t.Fatalf("expected %q, but got:\n%s", want, got) 44 } 45 } 46 47 func TestCgoCallbackGC(t *testing.T) { 48 t.Parallel() 49 switch runtime.GOOS { 50 case "plan9", "windows": 51 t.Skipf("no pthreads on %s", runtime.GOOS) 52 } 53 if testing.Short() { 54 switch { 55 case runtime.GOOS == "dragonfly": 56 t.Skip("see golang.org/issue/11990") 57 case runtime.GOOS == "linux" && runtime.GOARCH == "arm": 58 t.Skip("too slow for arm builders") 59 case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le"): 60 t.Skip("too slow for mips64x builders") 61 } 62 } 63 got := runTestProg(t, "testprogcgo", "CgoCallbackGC") 64 want := "OK\n" 65 if got != want { 66 t.Fatalf("expected %q, but got:\n%s", want, got) 67 } 68 } 69 70 func TestCgoExternalThreadPanic(t *testing.T) { 71 t.Parallel() 72 if runtime.GOOS == "plan9" { 73 t.Skipf("no pthreads on %s", runtime.GOOS) 74 } 75 got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic") 76 want := "panic: BOOM" 77 if !strings.Contains(got, want) { 78 t.Fatalf("want failure containing %q. output:\n%s\n", want, got) 79 } 80 } 81 82 func TestCgoExternalThreadSIGPROF(t *testing.T) { 83 t.Parallel() 84 // issue 9456. 85 switch runtime.GOOS { 86 case "plan9", "windows": 87 t.Skipf("no pthreads on %s", runtime.GOOS) 88 case "darwin": 89 if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" { 90 // static constructor needs external linking, but we don't support 91 // external linking on OS X 10.6. 92 out, err := exec.Command("uname", "-r").Output() 93 if err != nil { 94 t.Fatalf("uname -r failed: %v", err) 95 } 96 // OS X 10.6 == Darwin 10.x 97 if strings.HasPrefix(string(out), "10.") { 98 t.Skipf("no external linking on OS X 10.6") 99 } 100 } 101 } 102 if runtime.GOARCH == "ppc64" { 103 // TODO(austin) External linking not implemented on 104 // ppc64 (issue #8912) 105 t.Skipf("no external linking on ppc64") 106 } 107 108 exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof") 109 if err != nil { 110 t.Fatal(err) 111 } 112 113 got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() 114 if err != nil { 115 t.Fatalf("exit status: %v\n%s", err, got) 116 } 117 118 if want := "OK\n"; string(got) != want { 119 t.Fatalf("expected %q, but got:\n%s", want, got) 120 } 121 } 122 123 func TestCgoExternalThreadSignal(t *testing.T) { 124 t.Parallel() 125 // issue 10139 126 switch runtime.GOOS { 127 case "plan9", "windows": 128 t.Skipf("no pthreads on %s", runtime.GOOS) 129 } 130 131 exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof") 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() 137 if err != nil { 138 t.Fatalf("exit status: %v\n%s", err, got) 139 } 140 141 want := []byte("OK\n") 142 if !bytes.Equal(got, want) { 143 t.Fatalf("expected %q, but got:\n%s", want, got) 144 } 145 } 146 147 func TestCgoDLLImports(t *testing.T) { 148 // test issue 9356 149 if runtime.GOOS != "windows" { 150 t.Skip("skipping windows specific test") 151 } 152 got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain") 153 want := "OK\n" 154 if got != want { 155 t.Fatalf("expected %q, but got %v", want, got) 156 } 157 } 158 159 func TestCgoExecSignalMask(t *testing.T) { 160 t.Parallel() 161 // Test issue 13164. 162 switch runtime.GOOS { 163 case "windows", "plan9": 164 t.Skipf("skipping signal mask test on %s", runtime.GOOS) 165 } 166 got := runTestProg(t, "testprogcgo", "CgoExecSignalMask") 167 want := "OK\n" 168 if got != want { 169 t.Errorf("expected %q, got %v", want, got) 170 } 171 } 172 173 func TestEnsureDropM(t *testing.T) { 174 t.Parallel() 175 // Test for issue 13881. 176 switch runtime.GOOS { 177 case "windows", "plan9": 178 t.Skipf("skipping dropm test on %s", runtime.GOOS) 179 } 180 got := runTestProg(t, "testprogcgo", "EnsureDropM") 181 want := "OK\n" 182 if got != want { 183 t.Errorf("expected %q, got %v", want, got) 184 } 185 } 186 187 // Test for issue 14387. 188 // Test that the program that doesn't need any cgo pointer checking 189 // takes about the same amount of time with it as without it. 190 func TestCgoCheckBytes(t *testing.T) { 191 t.Parallel() 192 // Make sure we don't count the build time as part of the run time. 193 testenv.MustHaveGoBuild(t) 194 exe, err := buildTestProg(t, "testprogcgo") 195 if err != nil { 196 t.Fatal(err) 197 } 198 199 // Try it 10 times to avoid flakiness. 200 const tries = 10 201 var tot1, tot2 time.Duration 202 for i := 0; i < tries; i++ { 203 cmd := testEnv(exec.Command(exe, "CgoCheckBytes")) 204 cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) 205 206 start := time.Now() 207 cmd.Run() 208 d1 := time.Since(start) 209 210 cmd = testEnv(exec.Command(exe, "CgoCheckBytes")) 211 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) 212 213 start = time.Now() 214 cmd.Run() 215 d2 := time.Since(start) 216 217 if d1*20 > d2 { 218 // The slow version (d2) was less than 20 times 219 // slower than the fast version (d1), so OK. 220 return 221 } 222 223 tot1 += d1 224 tot2 += d2 225 } 226 227 t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20) 228 } 229 230 func TestCgoPanicDeadlock(t *testing.T) { 231 t.Parallel() 232 // test issue 14432 233 got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock") 234 want := "panic: cgo error\n\n" 235 if !strings.HasPrefix(got, want) { 236 t.Fatalf("output does not start with %q:\n%s", want, got) 237 } 238 } 239 240 func TestCgoCCodeSIGPROF(t *testing.T) { 241 t.Parallel() 242 got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF") 243 want := "OK\n" 244 if got != want { 245 t.Errorf("expected %q got %v", want, got) 246 } 247 } 248 249 func TestCgoCrashTraceback(t *testing.T) { 250 t.Parallel() 251 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 252 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 253 } 254 got := runTestProg(t, "testprogcgo", "CrashTraceback") 255 for i := 1; i <= 3; i++ { 256 if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) { 257 t.Errorf("missing cgo symbolizer:%d", i) 258 } 259 } 260 } 261 262 func TestCgoTracebackContext(t *testing.T) { 263 t.Parallel() 264 got := runTestProg(t, "testprogcgo", "TracebackContext") 265 want := "OK\n" 266 if got != want { 267 t.Errorf("expected %q got %v", want, got) 268 } 269 } 270 271 func testCgoPprof(t *testing.T, buildArg, runArg string) { 272 t.Parallel() 273 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 274 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 275 } 276 testenv.MustHaveGoRun(t) 277 278 exe, err := buildTestProg(t, "testprogcgo", buildArg) 279 if err != nil { 280 t.Fatal(err) 281 } 282 283 got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput() 284 if err != nil { 285 t.Fatal(err) 286 } 287 fn := strings.TrimSpace(string(got)) 288 defer os.Remove(fn) 289 290 cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1", exe, fn)) 291 292 found := false 293 for i, e := range cmd.Env { 294 if strings.HasPrefix(e, "PPROF_TMPDIR=") { 295 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir() 296 found = true 297 break 298 } 299 } 300 if !found { 301 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir()) 302 } 303 304 top, err := cmd.CombinedOutput() 305 t.Logf("%s", top) 306 if err != nil { 307 t.Fatal(err) 308 } 309 310 if !bytes.Contains(top, []byte("cpuHog")) { 311 t.Error("missing cpuHog in pprof output") 312 } 313 } 314 315 func TestCgoPprof(t *testing.T) { 316 testCgoPprof(t, "", "CgoPprof") 317 } 318 319 func TestCgoPprofPIE(t *testing.T) { 320 testCgoPprof(t, "-ldflags=-extldflags=-pie", "CgoPprof") 321 } 322 323 func TestCgoPprofThread(t *testing.T) { 324 testCgoPprof(t, "", "CgoPprofThread") 325 } 326 327 func TestCgoPprofThreadNoTraceback(t *testing.T) { 328 testCgoPprof(t, "", "CgoPprofThreadNoTraceback") 329 } 330 331 func TestRaceProf(t *testing.T) { 332 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 333 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 334 } 335 336 testenv.MustHaveGoRun(t) 337 338 // This test requires building various packages with -race, so 339 // it's somewhat slow. 340 if testing.Short() { 341 t.Skip("skipping test in -short mode") 342 } 343 344 exe, err := buildTestProg(t, "testprogcgo", "-race") 345 if err != nil { 346 t.Fatal(err) 347 } 348 349 got, err := testEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput() 350 if err != nil { 351 t.Fatal(err) 352 } 353 want := "OK\n" 354 if string(got) != want { 355 t.Errorf("expected %q got %s", want, got) 356 } 357 } 358 359 func TestRaceSignal(t *testing.T) { 360 t.Parallel() 361 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 362 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 363 } 364 365 testenv.MustHaveGoRun(t) 366 367 // This test requires building various packages with -race, so 368 // it's somewhat slow. 369 if testing.Short() { 370 t.Skip("skipping test in -short mode") 371 } 372 373 exe, err := buildTestProg(t, "testprogcgo", "-race") 374 if err != nil { 375 t.Fatal(err) 376 } 377 378 got, err := testEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput() 379 if err != nil { 380 t.Logf("%s\n", got) 381 t.Fatal(err) 382 } 383 want := "OK\n" 384 if string(got) != want { 385 t.Errorf("expected %q got %s", want, got) 386 } 387 } 388