github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/race/output_test.go (about)

     1  // Copyright 2013 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 race
     6  
     7  package race_test
     8  
     9  import (
    10  	"internal/testenv"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"regexp"
    15  	"runtime"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  func TestOutput(t *testing.T) {
    21  	pkgdir, err := os.MkdirTemp("", "go-build-race-output")
    22  	if err != nil {
    23  		t.Fatal(err)
    24  	}
    25  	defer os.RemoveAll(pkgdir)
    26  	out, err := exec.Command(testenv.GoToolPath(t), "install", "-race", "-pkgdir="+pkgdir, "testing").CombinedOutput()
    27  	if err != nil {
    28  		t.Fatalf("go install -race: %v\n%s", err, out)
    29  	}
    30  
    31  	for _, test := range tests {
    32  		if test.goos != "" && test.goos != runtime.GOOS {
    33  			t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)
    34  			continue
    35  		}
    36  		dir, err := os.MkdirTemp("", "go-build")
    37  		if err != nil {
    38  			t.Fatalf("failed to create temp directory: %v", err)
    39  		}
    40  		defer os.RemoveAll(dir)
    41  		source := "main.go"
    42  		if test.run == "test" {
    43  			source = "main_test.go"
    44  		}
    45  		src := filepath.Join(dir, source)
    46  		f, err := os.Create(src)
    47  		if err != nil {
    48  			t.Fatalf("failed to create file: %v", err)
    49  		}
    50  		_, err = f.WriteString(test.source)
    51  		if err != nil {
    52  			f.Close()
    53  			t.Fatalf("failed to write: %v", err)
    54  		}
    55  		if err := f.Close(); err != nil {
    56  			t.Fatalf("failed to close file: %v", err)
    57  		}
    58  
    59  		cmd := exec.Command(testenv.GoToolPath(t), test.run, "-race", "-pkgdir="+pkgdir, src)
    60  		// GODEBUG spoils program output, GOMAXPROCS makes it flaky.
    61  		for _, env := range os.Environ() {
    62  			if strings.HasPrefix(env, "GODEBUG=") ||
    63  				strings.HasPrefix(env, "GOMAXPROCS=") ||
    64  				strings.HasPrefix(env, "GORACE=") {
    65  				continue
    66  			}
    67  			cmd.Env = append(cmd.Env, env)
    68  		}
    69  		cmd.Env = append(cmd.Env,
    70  			"GOMAXPROCS=1", // see comment in race_test.go
    71  			"GORACE="+test.gorace,
    72  		)
    73  		got, _ := cmd.CombinedOutput()
    74  		if !regexp.MustCompile(test.re).MatchString(string(got)) {
    75  			t.Fatalf("failed test case %v, expect:\n%v\ngot:\n%s",
    76  				test.name, test.re, got)
    77  		}
    78  	}
    79  }
    80  
    81  var tests = []struct {
    82  	name   string
    83  	run    string
    84  	goos   string
    85  	gorace string
    86  	source string
    87  	re     string
    88  }{
    89  	{"simple", "run", "", "atexit_sleep_ms=0", `
    90  package main
    91  import "time"
    92  func main() {
    93  	done := make(chan bool)
    94  	x := 0
    95  	startRacer(&x, done)
    96  	store(&x, 43)
    97  	<-done
    98  }
    99  func store(x *int, v int) {
   100  	*x = v
   101  }
   102  func startRacer(x *int, done chan bool) {
   103  	go racer(x, done)
   104  }
   105  func racer(x *int, done chan bool) {
   106  	time.Sleep(10*time.Millisecond)
   107  	store(x, 42)
   108  	done <- true
   109  }
   110  `, `==================
   111  WARNING: DATA RACE
   112  Write at 0x[0-9,a-f]+ by goroutine [0-9]:
   113    main\.store\(\)
   114        .+/main\.go:12 \+0x[0-9,a-f]+
   115    main\.racer\(\)
   116        .+/main\.go:19 \+0x[0-9,a-f]+
   117  
   118  Previous write at 0x[0-9,a-f]+ by main goroutine:
   119    main\.store\(\)
   120        .+/main\.go:12 \+0x[0-9,a-f]+
   121    main\.main\(\)
   122        .+/main\.go:8 \+0x[0-9,a-f]+
   123  
   124  Goroutine [0-9] \(running\) created at:
   125    main\.startRacer\(\)
   126        .+/main\.go:15 \+0x[0-9,a-f]+
   127    main\.main\(\)
   128        .+/main\.go:7 \+0x[0-9,a-f]+
   129  ==================
   130  Found 1 data race\(s\)
   131  exit status 66
   132  `},
   133  
   134  	{"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
   135  package main
   136  func main() {
   137  	done := make(chan bool)
   138  	x := 0
   139  	go func() {
   140  		x = 42
   141  		done <- true
   142  	}()
   143  	x = 43
   144  	<-done
   145  }
   146  `, `exit status 13`},
   147  
   148  	{"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
   149  package main
   150  func main() {
   151  	done := make(chan bool)
   152  	x := 0
   153  	go func() {
   154  		x = 42
   155  		done <- true
   156  	}()
   157  	x = 43
   158  	<-done
   159  }
   160  `, `
   161        go:7 \+0x[0-9,a-f]+
   162  `},
   163  
   164  	{"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
   165  package main
   166  func main() {
   167  	done := make(chan bool)
   168  	x := 0
   169  	go func() {
   170  		x = 42
   171  		done <- true
   172  	}()
   173  	x = 43
   174  	<-done
   175  }
   176  `, `
   177  ==================
   178  exit status 66
   179  `},
   180  
   181  	{"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
   182  package main_test
   183  import "testing"
   184  func TestFail(t *testing.T) {
   185  	done := make(chan bool)
   186  	x := 0
   187  	_ = x
   188  	go func() {
   189  		x = 42
   190  		done <- true
   191  	}()
   192  	x = 43
   193  	<-done
   194  	t.Log(t.Failed())
   195  }
   196  `, `
   197  ==================
   198  --- FAIL: TestFail \(0...s\)
   199  .*main_test.go:14: true
   200  .*testing.go:.*: race detected during execution of test
   201  FAIL`},
   202  
   203  	{"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
   204  package main
   205  func main() {
   206  	done := make(chan string)
   207  	data := make([]byte, 10)
   208  	go func() {
   209  		done <- string(data)
   210  	}()
   211  	data[0] = 1
   212  	<-done
   213  }
   214  `, `
   215    runtime\.slicebytetostring\(\)
   216        .*/runtime/string\.go:.*
   217    main\.main\.func1\(\)
   218        .*/main.go:7`},
   219  
   220  	// Test for https://golang.org/issue/33309
   221  	{"midstack_inlining_traceback", "run", "linux", "atexit_sleep_ms=0", `
   222  package main
   223  
   224  var x int
   225  
   226  func main() {
   227  	c := make(chan int)
   228  	go f(c)
   229  	x = 1
   230  	<-c
   231  }
   232  
   233  func f(c chan int) {
   234  	g(c)
   235  }
   236  
   237  func g(c chan int) {
   238  	h(c)
   239  }
   240  
   241  func h(c chan int) {
   242  	c <- x
   243  }
   244  `, `==================
   245  WARNING: DATA RACE
   246  Read at 0x[0-9,a-f]+ by goroutine [0-9]:
   247    main\.h\(\)
   248        .+/main\.go:22 \+0x[0-9,a-f]+
   249    main\.g\(\)
   250        .+/main\.go:18 \+0x[0-9,a-f]+
   251    main\.f\(\)
   252        .+/main\.go:14 \+0x[0-9,a-f]+
   253  
   254  Previous write at 0x[0-9,a-f]+ by main goroutine:
   255    main\.main\(\)
   256        .+/main\.go:9 \+0x[0-9,a-f]+
   257  
   258  Goroutine [0-9] \(running\) created at:
   259    main\.main\(\)
   260        .+/main\.go:8 \+0x[0-9,a-f]+
   261  ==================
   262  Found 1 data race\(s\)
   263  exit status 66
   264  `},
   265  
   266  	// Test for https://golang.org/issue/17190
   267  	{"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
   268  package main
   269  
   270  /*
   271  #include <pthread.h>
   272  typedef struct cb {
   273          int foo;
   274  } cb;
   275  extern void goCallback();
   276  static inline void *threadFunc(void *p) {
   277  	goCallback();
   278  	return 0;
   279  }
   280  static inline void startThread(cb* c) {
   281  	pthread_t th;
   282  	pthread_create(&th, 0, threadFunc, 0);
   283  }
   284  */
   285  import "C"
   286  
   287  var done chan bool
   288  var racy int
   289  
   290  //export goCallback
   291  func goCallback() {
   292  	racy++
   293  	done <- true
   294  }
   295  
   296  func main() {
   297  	done = make(chan bool)
   298  	var c C.cb
   299  	C.startThread(&c)
   300  	racy++
   301  	<- done
   302  }
   303  `, `==================
   304  WARNING: DATA RACE
   305  Read at 0x[0-9,a-f]+ by .*:
   306    main\..*
   307        .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
   308  
   309  Previous write at 0x[0-9,a-f]+ by .*:
   310    main\..*
   311        .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
   312  
   313  Goroutine [0-9] \(running\) created at:
   314    runtime\.newextram\(\)
   315        .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
   316  ==================`},
   317  	{"second_test_passes", "test", "", "atexit_sleep_ms=0", `
   318  package main_test
   319  import "testing"
   320  func TestFail(t *testing.T) {
   321  	done := make(chan bool)
   322  	x := 0
   323  	_ = x
   324  	go func() {
   325  		x = 42
   326  		done <- true
   327  	}()
   328  	x = 43
   329  	<-done
   330  }
   331  
   332  func TestPass(t *testing.T) {
   333  }
   334  `, `
   335  ==================
   336  --- FAIL: TestFail \(0...s\)
   337  .*testing.go:.*: race detected during execution of test
   338  FAIL`},
   339  	{"mutex", "run", "", "atexit_sleep_ms=0", `
   340  package main
   341  import (
   342  	"sync"
   343  	"fmt"
   344  )
   345  func main() {
   346  	c := make(chan bool, 1)
   347  	threads := 1
   348  	iterations := 20000
   349  	data := 0
   350  	var wg sync.WaitGroup
   351  	for i := 0; i < threads; i++ {
   352  		wg.Add(1)
   353  		go func() {
   354  			defer wg.Done()
   355  			for i := 0; i < iterations; i++ {
   356  				c <- true
   357  				data += 1
   358  				<- c
   359  			}
   360  		}()
   361  	}
   362  	for i := 0; i < iterations; i++ {
   363  		c <- true
   364  		data += 1
   365  		<- c
   366  	}
   367  	wg.Wait()
   368  	if (data == iterations*(threads+1)) { fmt.Println("pass") }
   369  }`, `pass`},
   370  	// Test for https://github.com/golang/go/issues/37355
   371  	{"chanmm", "run", "", "atexit_sleep_ms=0", `
   372  package main
   373  import (
   374  	"sync"
   375  	"time"
   376  )
   377  func main() {
   378  	c := make(chan bool, 1)
   379  	var data uint64
   380  	var wg sync.WaitGroup
   381  	wg.Add(2)
   382  	c <- true
   383  	go func() {
   384  		defer wg.Done()
   385  		c <- true
   386  	}()
   387  	go func() {
   388  		defer wg.Done()
   389  		time.Sleep(time.Second)
   390  		<-c
   391  		data = 2
   392  	}()
   393  	data = 1
   394  	<-c
   395  	wg.Wait()
   396  	_ = data
   397  }
   398  `, `==================
   399  WARNING: DATA RACE
   400  Write at 0x[0-9,a-f]+ by goroutine [0-9]:
   401    main\.main\.func2\(\)
   402        .*/main\.go:21 \+0x[0-9,a-f]+
   403  
   404  Previous write at 0x[0-9,a-f]+ by main goroutine:
   405    main\.main\(\)
   406        .*/main\.go:23 \+0x[0-9,a-f]+
   407  
   408  Goroutine [0-9] \(running\) created at:
   409    main\.main\(\)
   410        .*/main.go:[0-9]+ \+0x[0-9,a-f]+
   411  ==================`},
   412  }