Black Lives Matter. Support the Equal Justice Initiative.

Source file src/runtime/race/output_test.go

Documentation: runtime/race

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

View as plain text