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