github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/runtime/crash_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  package runtime_test
     6  
     7  import (
     8  	"io/ioutil"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"strings"
    13  	"testing"
    14  	"text/template"
    15  )
    16  
    17  // testEnv excludes GODEBUG from the environment
    18  // to prevent its output from breaking tests that
    19  // are trying to parse other command output.
    20  func testEnv(cmd *exec.Cmd) *exec.Cmd {
    21  	if cmd.Env != nil {
    22  		panic("environment already set")
    23  	}
    24  	for _, env := range os.Environ() {
    25  		if strings.HasPrefix(env, "GODEBUG=") {
    26  			continue
    27  		}
    28  		cmd.Env = append(cmd.Env, env)
    29  	}
    30  	return cmd
    31  }
    32  
    33  func executeTest(t *testing.T, templ string, data interface{}) string {
    34  	checkStaleRuntime(t)
    35  
    36  	st := template.Must(template.New("crashSource").Parse(templ))
    37  
    38  	dir, err := ioutil.TempDir("", "go-build")
    39  	if err != nil {
    40  		t.Fatalf("failed to create temp directory: %v", err)
    41  	}
    42  	defer os.RemoveAll(dir)
    43  
    44  	src := filepath.Join(dir, "main.go")
    45  	f, err := os.Create(src)
    46  	if err != nil {
    47  		t.Fatalf("failed to create file: %v", err)
    48  	}
    49  	err = st.Execute(f, data)
    50  	if err != nil {
    51  		f.Close()
    52  		t.Fatalf("failed to execute template: %v", err)
    53  	}
    54  	if err := f.Close(); err != nil {
    55  		t.Fatalf("failed to close file: %v", err)
    56  	}
    57  
    58  	got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
    59  	return string(got)
    60  }
    61  
    62  func checkStaleRuntime(t *testing.T) {
    63  	// 'go run' uses the installed copy of runtime.a, which may be out of date.
    64  	out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
    65  	if err != nil {
    66  		t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
    67  	}
    68  	if string(out) != "false\n" {
    69  		t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
    70  	}
    71  }
    72  
    73  func testCrashHandler(t *testing.T, cgo bool) {
    74  	type crashTest struct {
    75  		Cgo bool
    76  	}
    77  	output := executeTest(t, crashSource, &crashTest{Cgo: cgo})
    78  	want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
    79  	if output != want {
    80  		t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
    81  	}
    82  }
    83  
    84  func TestCrashHandler(t *testing.T) {
    85  	testCrashHandler(t, false)
    86  }
    87  
    88  func testDeadlock(t *testing.T, source string) {
    89  	output := executeTest(t, source, nil)
    90  	want := "fatal error: all goroutines are asleep - deadlock!\n"
    91  	if !strings.HasPrefix(output, want) {
    92  		t.Fatalf("output does not start with %q:\n%s", want, output)
    93  	}
    94  }
    95  
    96  func TestSimpleDeadlock(t *testing.T) {
    97  	testDeadlock(t, simpleDeadlockSource)
    98  }
    99  
   100  func TestInitDeadlock(t *testing.T) {
   101  	testDeadlock(t, initDeadlockSource)
   102  }
   103  
   104  func TestLockedDeadlock(t *testing.T) {
   105  	testDeadlock(t, lockedDeadlockSource)
   106  }
   107  
   108  func TestLockedDeadlock2(t *testing.T) {
   109  	testDeadlock(t, lockedDeadlockSource2)
   110  }
   111  
   112  func TestGoexitDeadlock(t *testing.T) {
   113  	output := executeTest(t, goexitDeadlockSource, nil)
   114  	if output != "" {
   115  		t.Fatalf("expected no output, got:\n%s", output)
   116  	}
   117  }
   118  
   119  func TestStackOverflow(t *testing.T) {
   120  	output := executeTest(t, stackOverflowSource, nil)
   121  	want := "runtime: goroutine stack exceeds 4194304-byte limit\nfatal error: stack overflow"
   122  	if !strings.HasPrefix(output, want) {
   123  		t.Fatalf("output does not start with %q:\n%s", want, output)
   124  	}
   125  }
   126  
   127  func TestThreadExhaustion(t *testing.T) {
   128  	output := executeTest(t, threadExhaustionSource, nil)
   129  	want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
   130  	if !strings.HasPrefix(output, want) {
   131  		t.Fatalf("output does not start with %q:\n%s", want, output)
   132  	}
   133  }
   134  
   135  const crashSource = `
   136  package main
   137  
   138  import (
   139  	"fmt"
   140  	"runtime"
   141  )
   142  
   143  {{if .Cgo}}
   144  import "C"
   145  {{end}}
   146  
   147  func test(name string) {
   148  	defer func() {
   149  		if x := recover(); x != nil {
   150  			fmt.Printf(" recovered")
   151  		}
   152  		fmt.Printf(" done\n")
   153  	}()
   154  	fmt.Printf("%s:", name)
   155  	var s *string
   156  	_ = *s
   157  	fmt.Print("SHOULD NOT BE HERE")
   158  }
   159  
   160  func testInNewThread(name string) {
   161  	c := make(chan bool)
   162  	go func() {
   163  		runtime.LockOSThread()
   164  		test(name)
   165  		c <- true
   166  	}()
   167  	<-c
   168  }
   169  
   170  func main() {
   171  	runtime.LockOSThread()
   172  	test("main")
   173  	testInNewThread("new-thread")
   174  	testInNewThread("second-new-thread")
   175  	test("main-again")
   176  }
   177  `
   178  
   179  const simpleDeadlockSource = `
   180  package main
   181  func main() {
   182  	select {}
   183  }
   184  `
   185  
   186  const initDeadlockSource = `
   187  package main
   188  func init() {
   189  	select {}
   190  }
   191  func main() {
   192  }
   193  `
   194  
   195  const lockedDeadlockSource = `
   196  package main
   197  import "runtime"
   198  func main() {
   199  	runtime.LockOSThread()
   200  	select {}
   201  }
   202  `
   203  
   204  const lockedDeadlockSource2 = `
   205  package main
   206  import (
   207  	"runtime"
   208  	"time"
   209  )
   210  func main() {
   211  	go func() {
   212  		runtime.LockOSThread()
   213  		select {}
   214  	}()
   215  	time.Sleep(time.Millisecond)
   216  	select {}
   217  }
   218  `
   219  
   220  const goexitDeadlockSource = `
   221  package main
   222  import (
   223        "runtime"
   224  )
   225  
   226  func F() {
   227        for i := 0; i < 10; i++ {
   228        }
   229  }
   230  
   231  func main() {
   232        go F()
   233        go F()
   234        runtime.Goexit()
   235  }
   236  `
   237  
   238  const stackOverflowSource = `
   239  package main
   240  
   241  import "runtime/debug"
   242  
   243  func main() {
   244  	debug.SetMaxStack(4<<20)
   245  	f(make([]byte, 10))
   246  }
   247  
   248  func f(x []byte) byte {
   249  	var buf [64<<10]byte
   250  	return x[0] + f(buf[:])
   251  }
   252  `
   253  
   254  const threadExhaustionSource = `
   255  package main
   256  
   257  import (
   258  	"runtime"
   259  	"runtime/debug"
   260  )
   261  
   262  func main() {
   263  	debug.SetMaxThreads(10)
   264  	c := make(chan int)
   265  	for i := 0; i < 100; i++ {
   266  		go func() {
   267  			runtime.LockOSThread()
   268  			c <- 0
   269  			select{}
   270  		}()
   271  		<-c
   272  	}
   273  }
   274  `