Commit 6c4943cb authored by Rémy Oudompheng's avatar Rémy Oudompheng

cmd/gc: fix race instrumentation of selectors T(v).Field

Fixes #5424.

R=golang-dev, daniel.morsing, dvyukov, r
CC=golang-dev
https://golang.org/cl/9033048
parent b3946dc1
......@@ -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)
{
......
......@@ -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
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment