Home | History | Annotate | Download | only in runtime
      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