"func @\"\".racefuncexit ()\n"
"func @\"\".raceread (? 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";
char *unsafeimport =
callinstr(Node **np, NodeList **init, int wr, int skip)
{
Node *f, *b, *n;
- Type *t, *t1;
- int class, res, hascalls;
+ Type *t;
+ int class, hascalls;
n = *np;
//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
t = n->type;
if(isartificial(n))
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);
// it skips e.g. stores to ... parameter array
}
n = treecopy(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);
return 1;
}
}
}
+#pragma textflag 7
+void
+runtime·racewriterange(uintptr addr, uintptr sz)
+{
+ if(!onstack(addr)) {
+ m->racecall = true;
+ runtime∕race·WriteRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
+ m->racecall = false;
+ }
+}
+
// Called from instrumented code.
// If we split stack, getcallerpc() can return runtime·lessstack().
#pragma textflag 7
}
}
+#pragma textflag 7
+void
+runtime·racereadrange(uintptr addr, uintptr sz)
+{
+ if(!onstack(addr)) {
+ m->racecall = true;
+ runtime∕race·ReadRange(g->racectx, (void*)addr, sz, runtime·getcallerpc(&addr));
+ m->racecall = false;
+ }
+}
+
// Called from runtime·racefuncenter (assembly).
#pragma textflag 7
void
<-ch
}
-// Not implemented.
-func TestRaceFailingArrayCopy(t *testing.T) {
+func TestRaceArrayCopy(t *testing.T) {
ch := make(chan bool, 1)
var a [5]int
go func() {
<-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) {
p := Point{0, 0}
ch := make(chan bool, 1)