]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: properly race-instrument for loops
authorDmitriy Vyukov <dvyukov@google.com>
Thu, 13 Jun 2013 12:03:58 +0000 (16:03 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Thu, 13 Jun 2013 12:03:58 +0000 (16:03 +0400)
Instrumentation of ntest expression should go to ntest->init.
Same for nincr.
Fixes #5340.

R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/10026046

src/cmd/gc/racewalk.c
src/pkg/runtime/race/testdata/mop_test.go
src/pkg/runtime/race/testdata/regression_test.go

index 41edc52c761a9c1ada4919b7c03b60e9a815dcb6..74d8522580544aeb95c8f455164e2f1bbde7a5a5 100644 (file)
@@ -122,8 +122,20 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
        if(debug['w'] > 1)
                dump("racewalk-before", n);
        setlineno(n);
-       if(init == nil || init == &n->ninit)
+       if(init == nil)
                fatal("racewalk: bad init list");
+       if(init == &n->ninit) {
+               // If init == &n->ninit and n->ninit is non-nil,
+               // racewalknode might append it to itself.
+               // nil it out and handle it separately before putting it back.
+               l = n->ninit;
+               n->ninit = nil;
+               racewalklist(l, nil);
+               racewalknode(&n, &l, wr, skip);  // recurse with nil n->ninit
+               appendinit(&n, l);
+               *np = n;
+               return;
+       }
 
        racewalklist(n->ninit, nil);
 
@@ -255,13 +267,7 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
                // side effects are safe.
                // n->right may not be executed,
                // so instrumentation goes to n->right->ninit, not init.
-               // If right->ninit is non-nil, racewalknode might append it to itself.
-               // nil it out and handle it separately before putting it back.
-               l = n->right->ninit;
-               n->right->ninit = nil;
-               racewalklist(l, nil);
-               racewalknode(&n->right, &l, wr, 0);
-               appendinit(&n->right, l);
+               racewalknode(&n->right, &n->right->ninit, wr, 0);
                goto ret;
 
        case ONAME:
@@ -400,12 +406,8 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
 ret:
        if(n->op != OBLOCK)  // OBLOCK is handled above in a special way.
                racewalklist(n->list, init);
-       l = nil;
-       racewalknode(&n->ntest, &l, 0, 0);
-       n->ninit = concat(n->ninit, l);
-       l = nil;
-       racewalknode(&n->nincr, &l, 0, 0);
-       n->ninit = concat(n->ninit, l);
+       racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
+       racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
        racewalklist(n->nbody, nil);
        racewalklist(n->nelse, nil);
        racewalklist(n->rlist, nil);
index d221f444e301583cdb6e24a2ab12dba803f6aef1..620b7ab6e4ad05b59ff5bbad0972154420d9fed8 100644 (file)
@@ -306,6 +306,94 @@ func TestRaceRange(t *testing.T) {
        }
 }
 
+func TestRaceForInit(t *testing.T) {
+       c := make(chan int)
+       x := 0
+       go func() {
+               c <- x
+       }()
+       for x = 42; false; {
+       }
+       <-c
+}
+
+func TestNoRaceForInit(t *testing.T) {
+       done := make(chan bool)
+       c := make(chan bool)
+       x := 0
+       go func() {
+               for {
+                       _, ok := <-c
+                       if !ok {
+                               done <- true
+                               return
+                       }
+                       x++
+               }
+       }()
+       i := 0
+       for x = 42; i < 10; i++ {
+               c <- true
+       }
+       close(c)
+       <-done
+}
+
+func TestRaceForTest(t *testing.T) {
+       done := make(chan bool)
+       c := make(chan bool)
+       stop := false
+       go func() {
+               for {
+                       _, ok := <-c
+                       if !ok {
+                               done <- true
+                               return
+                       }
+                       stop = true
+               }
+       }()
+       for !stop {
+               c <- true
+       }
+       close(c)
+       <-done
+}
+
+func TestRaceForIncr(t *testing.T) {
+       done := make(chan bool)
+       c := make(chan bool)
+       x := 0
+       go func() {
+               for {
+                       _, ok := <-c
+                       if !ok {
+                               done <- true
+                               return
+                       }
+                       x++
+               }
+       }()
+       for i := 0; i < 10; x++ {
+               i++
+               c <- true
+       }
+       close(c)
+       <-done
+}
+
+func TestNoRaceForIncr(t *testing.T) {
+       done := make(chan bool)
+       x := 0
+       go func() {
+               x++
+               done <- true
+       }()
+       for i := 0; i < 0; x++ {
+       }
+       <-done
+}
+
 func TestRacePlus(t *testing.T) {
        var x, y, z int
        ch := make(chan int, 2)
index 49e03d9082d76874ab36ed2019ff315d6cd92c89..d461269d98225d3bf0471e7979399d3e52cde7cd 100644 (file)
@@ -175,3 +175,20 @@ type inltype struct {
 func inlinetest(p **inltype) *inltype {
        return *p
 }
+
+type iface interface {
+       Foo() *struct{ b bool }
+}
+
+type Int int
+
+func (i Int) Foo() *struct{ b bool } {
+       return &struct{ b bool }{false}
+}
+
+func TestNoRaceForInfiniteLoop(t *testing.T) {
+       var x Int
+       // interface conversion causes nodes to be put on init list
+       for iface(x).Foo().b {
+       }
+}