]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gc: fix race instrumentation of selectors T(v).Field
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Tue, 14 May 2013 23:25:20 +0000 (01:25 +0200)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Tue, 14 May 2013 23:25:20 +0000 (01:25 +0200)
Fixes #5424.

R=golang-dev, daniel.morsing, dvyukov, r
CC=golang-dev
https://golang.org/cl/9033048

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

index 5d4f62e761c2f63d414a3a1d52030038e6ab4a93..790c7efd7cb63a4b970b2ba19a9c9722bb15ad64 100644 (file)
@@ -23,6 +23,7 @@ static void racewalklist(NodeList *l, NodeList **init);
 static void racewalknode(Node **np, NodeList **init, int wr, int skip);
 static int callinstr(Node **n, NodeList **init, int wr, int skip);
 static Node* uintptraddr(Node *n);
+static void makeaddable(Node *n);
 static Node* basenod(Node *n);
 static void foreach(Node *n, void(*f)(Node*, void*), void *c);
 static void hascallspred(Node *n, void *c);
@@ -489,6 +490,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
                        *np = n;
                }
                n = treecopy(n);
+               makeaddable(n);
                f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
                *init = list(*init, f);
                return 1;
@@ -496,6 +498,37 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
        return 0;
 }
 
+// makeaddable returns a node whose memory location is the
+// same as n, but which is addressable in the Go language
+// sense.
+// This is different from functions like cheapexpr that may make
+// a copy of their argument.
+static void
+makeaddable(Node *n)
+{
+       // The arguments to uintptraddr technically have an address but
+       // may not be addressable in the Go sense: for example, in the case
+       // of T(v).Field where T is a struct type and v is
+       // an addressable value.
+       switch(n->op) {
+       case OINDEX:
+               if(isfixedarray(n->left->type))
+                       makeaddable(n->left);
+               break;
+       case ODOT:
+       case OXDOT:
+               // Turn T(v).Field into v.Field
+               if(n->left->op == OCONVNOP)
+                       n->left = n->left->left;
+               makeaddable(n->left);
+               break;
+       case ODOTPTR:
+       default:
+               // nothing to do
+               break;
+       }
+}
+
 static Node*
 uintptraddr(Node *n)
 {
index 754e4db6d439678cf1bc76668f64cfe7d8cc6eed..27b2d0081d3538c505f75ff43b43b888ba387b41 100644 (file)
@@ -83,6 +83,60 @@ func TestRaceCompArray(t *testing.T) {
        <-c
 }
 
+type P2 P
+type S2 S
+
+func TestRaceConv1(t *testing.T) {
+       c := make(chan bool, 1)
+       var p P2
+       go func() {
+               p.x = 1
+               c <- true
+       }()
+       _ = P(p).x
+       <-c
+}
+
+func TestRaceConv2(t *testing.T) {
+       c := make(chan bool, 1)
+       var p P2
+       go func() {
+               p.x = 1
+               c <- true
+       }()
+       ptr := &p
+       _ = P(*ptr).x
+       <-c
+}
+
+func TestRaceConv3(t *testing.T) {
+       c := make(chan bool, 1)
+       var s S2
+       go func() {
+               s.s1.x = 1
+               c <- true
+       }()
+       _ = P2(S(s).s1).x
+       <-c
+}
+
+type X struct {
+       V [4]P
+}
+
+type X2 X
+
+func TestRaceConv4(t *testing.T) {
+       c := make(chan bool, 1)
+       var x X2
+       go func() {
+               x.V[1].x = 1
+               c <- true
+       }()
+       _ = P2(X(x).V[1]).x
+       <-c
+}
+
 type Ptr struct {
        s1, s2 *P
 }