Commit 3be794cd authored by Rémy Oudompheng's avatar Rémy Oudompheng

cmd/gc: instrument arrays properly in race detector.

The previous implementation would only record access to
the address of the array but the memory access to the whole
memory range must be recorded instead.

R=golang-dev, dvyukov, r
CC=golang-dev
https://golang.org/cl/8053044
parent bc081248
...@@ -113,6 +113,8 @@ char *runtimeimport = ...@@ -113,6 +113,8 @@ char *runtimeimport =
"func @\"\".racefuncexit ()\n" "func @\"\".racefuncexit ()\n"
"func @\"\".raceread (? uintptr)\n" "func @\"\".raceread (? uintptr)\n"
"func @\"\".racewrite (? uintptr)\n" "func @\"\".racewrite (? uintptr)\n"
"func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
"func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
"\n" "\n"
"$$\n"; "$$\n";
char *unsafeimport = char *unsafeimport =
......
...@@ -439,8 +439,8 @@ static int ...@@ -439,8 +439,8 @@ static int
callinstr(Node **np, NodeList **init, int wr, int skip) callinstr(Node **np, NodeList **init, int wr, int skip)
{ {
Node *f, *b, *n; Node *f, *b, *n;
Type *t, *t1; Type *t;
int class, res, hascalls; int class, hascalls;
n = *np; n = *np;
//print("callinstr for %+N [ %O ] etype=%E class=%d\n", //print("callinstr for %+N [ %O ] etype=%E class=%d\n",
...@@ -451,33 +451,6 @@ callinstr(Node **np, NodeList **init, int wr, int skip) ...@@ -451,33 +451,6 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
t = n->type; t = n->type;
if(isartificial(n)) if(isartificial(n))
return 0; return 0;
if(t->etype == TSTRUCT) {
// TODO: instrument arrays similarly.
// PARAMs w/o PHEAP are not interesting.
if(n->class == PPARAM || n->class == PPARAMOUT)
return 0;
res = 0;
hascalls = 0;
foreach(n, hascallspred, &hascalls);
if(hascalls) {
n = detachexpr(n, init);
*np = n;
}
for(t1=t->type; t1; t1=t1->down) {
if(t1->sym && strcmp(t1->sym->name, "_")) {
n = treecopy(n);
f = nod(OXDOT, n, newname(t1->sym));
f->type = t1;
if(f->type->etype == TFIELD)
f->type = f->type->type;
if(callinstr(&f, init, wr, 0)) {
typecheck(&f, Erv);
res = 1;
}
}
}
return res;
}
b = basenod(n); b = basenod(n);
// it skips e.g. stores to ... parameter array // it skips e.g. stores to ... parameter array
...@@ -498,7 +471,11 @@ callinstr(Node **np, NodeList **init, int wr, int skip) ...@@ -498,7 +471,11 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
} }
n = treecopy(n); n = treecopy(n);
makeaddable(n); makeaddable(n);
f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n)); if(t->etype == TSTRUCT || isfixedarray(t)) {
f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n),
nodintconst(t->width));
} else
f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
*init = list(*init, f); *init = list(*init, f);
return 1; return 1;
} }
......
...@@ -149,3 +149,5 @@ func racefuncenter(uintptr) ...@@ -149,3 +149,5 @@ func racefuncenter(uintptr)
func racefuncexit() func racefuncexit()
func raceread(uintptr) func raceread(uintptr)
func racewrite(uintptr) func racewrite(uintptr)
func racereadrange(addr, size uintptr)
func racewriterange(addr, size uintptr)
...@@ -77,6 +77,17 @@ runtime·racewrite(uintptr addr) ...@@ -77,6 +77,17 @@ runtime·racewrite(uintptr addr)
} }
} }
#pragma textflag 7
void
runtime·racewriterange(uintptr addr, uintptr sz)
{
if(!onstack(addr)) {
m->racecall = true;
runtimerace·WriteRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
m->racecall = false;
}
}
// Called from instrumented code. // Called from instrumented code.
// If we split stack, getcallerpc() can return runtime·lessstack(). // If we split stack, getcallerpc() can return runtime·lessstack().
#pragma textflag 7 #pragma textflag 7
...@@ -90,6 +101,17 @@ runtime·raceread(uintptr addr) ...@@ -90,6 +101,17 @@ runtime·raceread(uintptr addr)
} }
} }
#pragma textflag 7
void
runtime·racereadrange(uintptr addr, uintptr sz)
{
if(!onstack(addr)) {
m->racecall = true;
runtimerace·ReadRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
m->racecall = false;
}
}
// Called from runtime·racefuncenter (assembly). // Called from runtime·racefuncenter (assembly).
#pragma textflag 7 #pragma textflag 7
void void
......
...@@ -600,8 +600,7 @@ func TestRaceSprint(t *testing.T) { ...@@ -600,8 +600,7 @@ func TestRaceSprint(t *testing.T) {
<-ch <-ch
} }
// Not implemented. func TestRaceArrayCopy(t *testing.T) {
func TestRaceFailingArrayCopy(t *testing.T) {
ch := make(chan bool, 1) ch := make(chan bool, 1)
var a [5]int var a [5]int
go func() { go func() {
...@@ -612,6 +611,24 @@ func TestRaceFailingArrayCopy(t *testing.T) { ...@@ -612,6 +611,24 @@ func TestRaceFailingArrayCopy(t *testing.T) {
<-ch <-ch
} }
// Blows up a naive compiler.
func TestRaceNestedArrayCopy(t *testing.T) {
ch := make(chan bool, 1)
type (
Point32 [2][2][2][2][2]Point
Point1024 [2][2][2][2][2]Point32
Point32k [2][2][2][2][2]Point1024
Point1M [2][2][2][2][2]Point32k
)
var a, b Point1M
go func() {
a[0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1][0][1].y = 1
ch <- true
}()
a = b
<-ch
}
func TestRaceStructRW(t *testing.T) { func TestRaceStructRW(t *testing.T) {
p := Point{0, 0} p := Point{0, 0}
ch := make(chan bool, 1) ch := make(chan bool, 1)
......
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