diff options
Diffstat (limited to 'src/pkg/runtime/race')
-rw-r--r-- | src/pkg/runtime/race/README | 2 | ||||
-rw-r--r-- | src/pkg/runtime/race/race.go | 118 | ||||
-rw-r--r-- | src/pkg/runtime/race/race_darwin_amd64.syso | bin | 192988 -> 222964 bytes | |||
-rw-r--r-- | src/pkg/runtime/race/race_linux_amd64.syso | bin | 195144 -> 243208 bytes | |||
-rw-r--r-- | src/pkg/runtime/race/race_test.go | 17 | ||||
-rw-r--r-- | src/pkg/runtime/race/race_windows_amd64.syso | bin | 161295 -> 210859 bytes | |||
-rw-r--r-- | src/pkg/runtime/race/testdata/chan_test.go | 207 | ||||
-rw-r--r-- | src/pkg/runtime/race/testdata/finalizer_test.go | 22 | ||||
-rw-r--r-- | src/pkg/runtime/race/testdata/map_test.go | 79 | ||||
-rw-r--r-- | src/pkg/runtime/race/testdata/mop_test.go | 22 |
10 files changed, 328 insertions, 139 deletions
diff --git a/src/pkg/runtime/race/README b/src/pkg/runtime/race/README index 0b73bd857..785640607 100644 --- a/src/pkg/runtime/race/README +++ b/src/pkg/runtime/race/README @@ -9,4 +9,4 @@ $ ./buildgo.sh Tested with gcc 4.6.1 and 4.7.0. On Windows it's built with 64-bit MinGW. -Current runtime is built on rev 191161. +Current runtime is built on rev 203116. diff --git a/src/pkg/runtime/race/race.go b/src/pkg/runtime/race/race.go index 5b44bde83..e53cacf4a 100644 --- a/src/pkg/runtime/race/race.go +++ b/src/pkg/runtime/race/race.go @@ -6,116 +6,10 @@ package race -/* -void __tsan_init(void **racectx); -void __tsan_fini(void); -void __tsan_map_shadow(void *addr, void *size); -void __tsan_go_start(void *racectx, void **chracectx, void *pc); -void __tsan_go_end(void *racectx); -void __tsan_read(void *racectx, void *addr, void *pc); -void __tsan_write(void *racectx, void *addr, void *pc); -void __tsan_read_range(void *racectx, void *addr, long sz, long step, void *pc); -void __tsan_write_range(void *racectx, void *addr, long sz, long step, void *pc); -void __tsan_func_enter(void *racectx, void *pc); -void __tsan_func_exit(void *racectx); -void __tsan_malloc(void *racectx, void *p, long sz, void *pc); -void __tsan_free(void *p); -void __tsan_acquire(void *racectx, void *addr); -void __tsan_release(void *racectx, void *addr); -void __tsan_release_merge(void *racectx, void *addr); -void __tsan_finalizer_goroutine(void *racectx); -*/ -import "C" - -import ( - "runtime" - "unsafe" -) - -func Initialize(racectx *uintptr) { - C.__tsan_init((*unsafe.Pointer)(unsafe.Pointer(racectx))) -} - -func Finalize() { - C.__tsan_fini() -} - -func MapShadow(addr, size uintptr) { - C.__tsan_map_shadow(unsafe.Pointer(addr), unsafe.Pointer(size)) -} - -func FinalizerGoroutine(racectx uintptr) { - C.__tsan_finalizer_goroutine(unsafe.Pointer(racectx)) -} - -func Read(racectx uintptr, addr, pc uintptr) { - C.__tsan_read(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc)) -} - -func Write(racectx uintptr, addr, pc uintptr) { - C.__tsan_write(unsafe.Pointer(racectx), unsafe.Pointer(addr), unsafe.Pointer(pc)) -} - -func ReadRange(racectx uintptr, addr, sz, pc uintptr) { - C.__tsan_read_range(unsafe.Pointer(racectx), unsafe.Pointer(addr), - C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc)) -} - -func WriteRange(racectx uintptr, addr, sz, pc uintptr) { - C.__tsan_write_range(unsafe.Pointer(racectx), unsafe.Pointer(addr), - C.long(sz), 0 /*step is unused*/, unsafe.Pointer(pc)) -} +// This file merely ensures that we link in runtime/cgo in race build, +// this is turn ensures that runtime uses pthread_create to create threads. +// The prebuilt race runtime lives in race_GOOS_GOARCH.syso. +// Calls to the runtime are done directly from src/pkg/runtime/race.c. -func FuncEnter(racectx uintptr, pc uintptr) { - C.__tsan_func_enter(unsafe.Pointer(racectx), unsafe.Pointer(pc)) -} - -func FuncExit(racectx uintptr) { - C.__tsan_func_exit(unsafe.Pointer(racectx)) -} - -func Malloc(racectx uintptr, p, sz, pc uintptr) { - C.__tsan_malloc(unsafe.Pointer(racectx), unsafe.Pointer(p), C.long(sz), unsafe.Pointer(pc)) -} - -func Free(p uintptr) { - C.__tsan_free(unsafe.Pointer(p)) -} - -func GoStart(racectx uintptr, chracectx *uintptr, pc uintptr) { - C.__tsan_go_start(unsafe.Pointer(racectx), (*unsafe.Pointer)(unsafe.Pointer(chracectx)), unsafe.Pointer(pc)) -} - -func GoEnd(racectx uintptr) { - C.__tsan_go_end(unsafe.Pointer(racectx)) -} - -func Acquire(racectx uintptr, addr uintptr) { - C.__tsan_acquire(unsafe.Pointer(racectx), unsafe.Pointer(addr)) -} - -func Release(racectx uintptr, addr uintptr) { - C.__tsan_release(unsafe.Pointer(racectx), unsafe.Pointer(addr)) -} - -func ReleaseMerge(racectx uintptr, addr uintptr) { - C.__tsan_release_merge(unsafe.Pointer(racectx), unsafe.Pointer(addr)) -} - -//export __tsan_symbolize -func __tsan_symbolize(pc uintptr, fun, file **C.char, line, off *C.int) C.int { - f := runtime.FuncForPC(pc) - if f == nil { - *fun = C.CString("??") - *file = C.CString("-") - *line = 0 - *off = C.int(pc) - return 1 - } - fi, l := f.FileLine(pc) - *fun = C.CString(f.Name()) - *file = C.CString(fi) - *line = C.int(l) - *off = C.int(pc - f.Entry()) - return 1 -} +// void __race_unused_func(void); +import "C" diff --git a/src/pkg/runtime/race/race_darwin_amd64.syso b/src/pkg/runtime/race/race_darwin_amd64.syso Binary files differindex 96a43c9a9..249a878ef 100644 --- a/src/pkg/runtime/race/race_darwin_amd64.syso +++ b/src/pkg/runtime/race/race_darwin_amd64.syso diff --git a/src/pkg/runtime/race/race_linux_amd64.syso b/src/pkg/runtime/race/race_linux_amd64.syso Binary files differindex 50bde9648..8120484d4 100644 --- a/src/pkg/runtime/race/race_linux_amd64.syso +++ b/src/pkg/runtime/race/race_linux_amd64.syso diff --git a/src/pkg/runtime/race/race_test.go b/src/pkg/runtime/race/race_test.go index 4776ae22d..7e0ee866a 100644 --- a/src/pkg/runtime/race/race_test.go +++ b/src/pkg/runtime/race/race_test.go @@ -44,7 +44,7 @@ func TestRace(t *testing.T) { if err != nil { t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput)) } - reader := bufio.NewReader(bytes.NewBuffer(testOutput)) + reader := bufio.NewReader(bytes.NewReader(testOutput)) funcName := "" var tsanLog []string @@ -155,3 +155,18 @@ func runTests() ([]byte, error) { cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`) return cmd.CombinedOutput() } + +func TestIssue8102(t *testing.T) { + // If this compiles with -race, the test passes. + type S struct { + x interface{} + i int + } + c := make(chan int) + a := [2]*int{} + for ; ; c <- *a[S{}.i] { + if t != nil { + break + } + } +} diff --git a/src/pkg/runtime/race/race_windows_amd64.syso b/src/pkg/runtime/race/race_windows_amd64.syso Binary files differindex 46eb1274f..67db40f21 100644 --- a/src/pkg/runtime/race/race_windows_amd64.syso +++ b/src/pkg/runtime/race/race_windows_amd64.syso diff --git a/src/pkg/runtime/race/testdata/chan_test.go b/src/pkg/runtime/race/testdata/chan_test.go index 614ba4a4e..4a3d5290f 100644 --- a/src/pkg/runtime/race/testdata/chan_test.go +++ b/src/pkg/runtime/race/testdata/chan_test.go @@ -347,6 +347,119 @@ func TestRaceChanSendSelectClose(t *testing.T) { <-compl } +func TestRaceSelectReadWriteAsync(t *testing.T) { + done := make(chan bool) + x := 0 + c1 := make(chan int, 10) + c2 := make(chan int, 10) + c3 := make(chan int) + c2 <- 1 + go func() { + select { + case c1 <- x: // read of x races with... + case c3 <- 1: + } + done <- true + }() + select { + case x = <-c2: // ... write to x here + case c3 <- 1: + } + <-done +} + +func TestRaceSelectReadWriteSync(t *testing.T) { + done := make(chan bool) + x := 0 + c1 := make(chan int) + c2 := make(chan int) + c3 := make(chan int) + // make c1 and c2 ready for communication + go func() { + <-c1 + }() + go func() { + c2 <- 1 + }() + go func() { + select { + case c1 <- x: // read of x races with... + case c3 <- 1: + } + done <- true + }() + select { + case x = <-c2: // ... write to x here + case c3 <- 1: + } + <-done +} + +func TestNoRaceSelectReadWriteAsync(t *testing.T) { + done := make(chan bool) + x := 0 + c1 := make(chan int) + c2 := make(chan int) + go func() { + select { + case c1 <- x: // read of x does not race with... + case c2 <- 1: + } + done <- true + }() + select { + case x = <-c1: // ... write to x here + case c2 <- 1: + } + <-done +} + +func TestRaceChanReadWriteAsync(t *testing.T) { + done := make(chan bool) + c1 := make(chan int, 10) + c2 := make(chan int, 10) + c2 <- 10 + x := 0 + go func() { + c1 <- x // read of x races with... + done <- true + }() + x = <-c2 // ... write to x here + <-done +} + +func TestRaceChanReadWriteSync(t *testing.T) { + done := make(chan bool) + c1 := make(chan int) + c2 := make(chan int) + // make c1 and c2 ready for communication + go func() { + <-c1 + }() + go func() { + c2 <- 10 + }() + x := 0 + go func() { + c1 <- x // read of x races with... + done <- true + }() + x = <-c2 // ... write to x here + <-done +} + +func TestNoRaceChanReadWriteAsync(t *testing.T) { + done := make(chan bool) + c1 := make(chan int, 10) + x := 0 + go func() { + c1 <- x // read of x does not race with... + done <- true + }() + x = <-c1 // ... write to x here + <-done +} + func TestNoRaceProducerConsumerUnbuffered(t *testing.T) { type Task struct { f func() @@ -454,20 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) { v = 2 } -func TestRaceChanSameCell(t *testing.T) { - c := make(chan int, 1) - v := 0 - go func() { - v = 1 - c <- 42 - <-c - }() - time.Sleep(1e7) - c <- 43 - <-c - _ = v -} - func TestRaceChanCloseSend(t *testing.T) { compl := make(chan bool, 1) c := make(chan int, 10) @@ -478,3 +577,83 @@ func TestRaceChanCloseSend(t *testing.T) { c <- 0 <-compl } + +func TestNoRaceChanMutex(t *testing.T) { + done := make(chan struct{}) + mtx := make(chan struct{}, 1) + data := 0 + go func() { + mtx <- struct{}{} + data = 42 + <-mtx + done <- struct{}{} + }() + mtx <- struct{}{} + data = 43 + <-mtx + <-done +} + +func TestNoRaceSelectMutex(t *testing.T) { + done := make(chan struct{}) + mtx := make(chan struct{}, 1) + aux := make(chan bool) + data := 0 + go func() { + select { + case mtx <- struct{}{}: + case <-aux: + } + data = 42 + select { + case <-mtx: + case <-aux: + } + done <- struct{}{} + }() + select { + case mtx <- struct{}{}: + case <-aux: + } + data = 43 + select { + case <-mtx: + case <-aux: + } + <-done +} + +func TestRaceChanSem(t *testing.T) { + done := make(chan struct{}) + mtx := make(chan bool, 2) + data := 0 + go func() { + mtx <- true + data = 42 + <-mtx + done <- struct{}{} + }() + mtx <- true + data = 43 + <-mtx + <-done +} + +func TestNoRaceChanWaitGroup(t *testing.T) { + const N = 10 + chanWg := make(chan bool, N/2) + data := make([]int, N) + for i := 0; i < N; i++ { + chanWg <- true + go func(i int) { + data[i] = 42 + <-chanWg + }(i) + } + for i := 0; i < cap(chanWg); i++ { + chanWg <- true + } + for i := 0; i < N; i++ { + _ = data[i] + } +} diff --git a/src/pkg/runtime/race/testdata/finalizer_test.go b/src/pkg/runtime/race/testdata/finalizer_test.go index 2b2607689..222cbf67a 100644 --- a/src/pkg/runtime/race/testdata/finalizer_test.go +++ b/src/pkg/runtime/race/testdata/finalizer_test.go @@ -14,16 +14,16 @@ import ( func TestNoRaceFin(t *testing.T) { c := make(chan bool) go func() { - x := new(int) - runtime.SetFinalizer(x, func(x *int) { - *x = 42 + x := new(string) + runtime.SetFinalizer(x, func(x *string) { + *x = "foo" }) - *x = 66 + *x = "bar" c <- true }() <-c runtime.GC() - time.Sleep(1e8) + time.Sleep(100 * time.Millisecond) } var finVar struct { @@ -34,8 +34,8 @@ var finVar struct { func TestNoRaceFinGlobal(t *testing.T) { c := make(chan bool) go func() { - x := new(int) - runtime.SetFinalizer(x, func(x *int) { + x := new(string) + runtime.SetFinalizer(x, func(x *string) { finVar.Lock() finVar.cnt++ finVar.Unlock() @@ -44,7 +44,7 @@ func TestNoRaceFinGlobal(t *testing.T) { }() <-c runtime.GC() - time.Sleep(1e8) + time.Sleep(100 * time.Millisecond) finVar.Lock() finVar.cnt++ finVar.Unlock() @@ -54,14 +54,14 @@ func TestRaceFin(t *testing.T) { c := make(chan bool) y := 0 go func() { - x := new(int) - runtime.SetFinalizer(x, func(x *int) { + x := new(string) + runtime.SetFinalizer(x, func(x *string) { y = 42 }) c <- true }() <-c runtime.GC() - time.Sleep(1e8) + time.Sleep(100 * time.Millisecond) y = 66 } diff --git a/src/pkg/runtime/race/testdata/map_test.go b/src/pkg/runtime/race/testdata/map_test.go index 35db8db69..98e2a5f10 100644 --- a/src/pkg/runtime/race/testdata/map_test.go +++ b/src/pkg/runtime/race/testdata/map_test.go @@ -159,3 +159,82 @@ func TestRaceMapVariable3(t *testing.T) { m = make(map[int]int) <-ch } + +type Big struct { + x [17]int32 +} + +func TestRaceMapLookupPartKey(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + _ = m[*k] + <-ch +} + +func TestRaceMapLookupPartKey2(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + _, _ = m[*k] + <-ch +} +func TestRaceMapDeletePartKey(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + delete(m, *k) + <-ch +} + +func TestRaceMapInsertPartKey(t *testing.T) { + k := &Big{} + m := make(map[Big]bool) + ch := make(chan bool, 1) + go func() { + k.x[8] = 1 + ch <- true + }() + m[*k] = true + <-ch +} + +func TestRaceMapInsertPartVal(t *testing.T) { + v := &Big{} + m := make(map[int]Big) + ch := make(chan bool, 1) + go func() { + v.x[8] = 1 + ch <- true + }() + m[1] = *v + <-ch +} + +// Test for issue 7561. +func TestRaceMapAssignMultipleReturn(t *testing.T) { + connect := func() (int, error) { return 42, nil } + conns := make(map[int][]int) + conns[1] = []int{0} + ch := make(chan bool, 1) + var err error + go func() { + conns[1][0], err = connect() + ch <- true + }() + x := conns[1][0] + _ = x + <-ch +} diff --git a/src/pkg/runtime/race/testdata/mop_test.go b/src/pkg/runtime/race/testdata/mop_test.go index b0b66562c..14591b184 100644 --- a/src/pkg/runtime/race/testdata/mop_test.go +++ b/src/pkg/runtime/race/testdata/mop_test.go @@ -1933,3 +1933,25 @@ func TestRaceMethodThunk4(t *testing.T) { *(*int)(d.Base) = 42 <-done } + +func TestNoRaceTinyAlloc(t *testing.T) { + const P = 4 + const N = 1e6 + var tinySink *byte + done := make(chan bool) + for p := 0; p < P; p++ { + go func() { + for i := 0; i < N; i++ { + var b byte + if b != 0 { + tinySink = &b // make it heap allocated + } + b = 42 + } + done <- true + }() + } + for p := 0; p < P; p++ { + <-done + } +} |