github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/gc/racewalk.c (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // The racewalk pass modifies the code tree for the function as follows: 6 // 7 // 1. It inserts a call to racefuncenter at the beginning of each function. 8 // 2. It inserts a call to racefuncexit at the end of each function. 9 // 3. It inserts a call to raceread before each memory read. 10 // 4. It inserts a call to racewrite before each memory write. 11 // 12 // The rewriting is not yet complete. Certain nodes are not rewritten 13 // but should be. 14 15 #include <u.h> 16 #include <libc.h> 17 #include "go.h" 18 19 // TODO(dvyukov): do not instrument initialization as writes: 20 // a := make([]int, 10) 21 22 static void racewalklist(NodeList *l, NodeList **init); 23 static void racewalknode(Node **np, NodeList **init, int wr, int skip); 24 static int callinstr(Node **n, NodeList **init, int wr, int skip); 25 static Node* uintptraddr(Node *n); 26 static void makeaddable(Node *n); 27 static Node* basenod(Node *n); 28 static void foreach(Node *n, void(*f)(Node*, void*), void *c); 29 static void hascallspred(Node *n, void *c); 30 static void appendinit(Node **np, NodeList *init); 31 static Node* detachexpr(Node *n, NodeList **init); 32 33 // Do not instrument the following packages at all, 34 // at best instrumentation would cause infinite recursion. 35 static const char *omit_pkgs[] = {"runtime", "runtime/race"}; 36 // Only insert racefuncenter/racefuncexit into the following packages. 37 // Memory accesses in the packages are either uninteresting or will cause false positives. 38 static const char *noinst_pkgs[] = {"sync", "sync/atomic"}; 39 40 static int 41 ispkgin(const char **pkgs, int n) 42 { 43 int i; 44 45 if(myimportpath) { 46 for(i=0; i<n; i++) { 47 if(strcmp(myimportpath, pkgs[i]) == 0) 48 return 1; 49 } 50 } 51 return 0; 52 } 53 54 static int 55 isforkfunc(Node *fn) 56 { 57 // Special case for syscall.forkAndExecInChild. 58 // In the child, this function must not acquire any locks, because 59 // they might have been locked at the time of the fork. This means 60 // no rescheduling, no malloc calls, and no new stack segments. 61 // Race instrumentation does all of the above. 62 return myimportpath != nil && strcmp(myimportpath, "syscall") == 0 && 63 strcmp(fn->nname->sym->name, "forkAndExecInChild") == 0; 64 } 65 66 void 67 racewalk(Node *fn) 68 { 69 Node *nd; 70 Node *nodpc; 71 char s[1024]; 72 73 if(ispkgin(omit_pkgs, nelem(omit_pkgs)) || isforkfunc(fn)) 74 return; 75 76 if(!ispkgin(noinst_pkgs, nelem(noinst_pkgs))) { 77 racewalklist(fn->nbody, nil); 78 // nothing interesting for race detector in fn->enter 79 racewalklist(fn->exit, nil); 80 } 81 82 // nodpc is the PC of the caller as extracted by 83 // getcallerpc. We use -widthptr(FP) for x86. 84 // BUG: this will not work on arm. 85 nodpc = nod(OXXX, nil, nil); 86 *nodpc = *nodfp; 87 nodpc->type = types[TUINTPTR]; 88 nodpc->xoffset = -widthptr; 89 nd = mkcall("racefuncenter", T, nil, nodpc); 90 fn->enter = concat(list1(nd), fn->enter); 91 nd = mkcall("racefuncexit", T, nil); 92 fn->exit = list(fn->exit, nd); 93 94 if(debug['W']) { 95 snprint(s, sizeof(s), "after racewalk %S", fn->nname->sym); 96 dumplist(s, fn->nbody); 97 snprint(s, sizeof(s), "enter %S", fn->nname->sym); 98 dumplist(s, fn->enter); 99 snprint(s, sizeof(s), "exit %S", fn->nname->sym); 100 dumplist(s, fn->exit); 101 } 102 } 103 104 static void 105 racewalklist(NodeList *l, NodeList **init) 106 { 107 NodeList *instr; 108 109 for(; l; l = l->next) { 110 instr = nil; 111 racewalknode(&l->n, &instr, 0, 0); 112 if(init == nil) 113 l->n->ninit = concat(l->n->ninit, instr); 114 else 115 *init = concat(*init, instr); 116 } 117 } 118 119 // walkexpr and walkstmt combined 120 // walks the tree and adds calls to the 121 // instrumentation code to top-level (statement) nodes' init 122 static void 123 racewalknode(Node **np, NodeList **init, int wr, int skip) 124 { 125 Node *n, *n1; 126 NodeList *l; 127 NodeList *fini; 128 129 n = *np; 130 131 if(n == N) 132 return; 133 134 if(debug['w'] > 1) 135 dump("racewalk-before", n); 136 setlineno(n); 137 if(init == nil) 138 fatal("racewalk: bad init list"); 139 if(init == &n->ninit) { 140 // If init == &n->ninit and n->ninit is non-nil, 141 // racewalknode might append it to itself. 142 // nil it out and handle it separately before putting it back. 143 l = n->ninit; 144 n->ninit = nil; 145 racewalklist(l, nil); 146 racewalknode(&n, &l, wr, skip); // recurse with nil n->ninit 147 appendinit(&n, l); 148 *np = n; 149 return; 150 } 151 152 racewalklist(n->ninit, nil); 153 154 switch(n->op) { 155 default: 156 fatal("racewalk: unknown node type %O", n->op); 157 158 case OASOP: 159 case OAS: 160 case OAS2: 161 case OAS2RECV: 162 case OAS2FUNC: 163 case OAS2MAPR: 164 racewalknode(&n->left, init, 1, 0); 165 racewalknode(&n->right, init, 0, 0); 166 goto ret; 167 168 case OCFUNC: 169 case OVARKILL: 170 // can't matter 171 goto ret; 172 173 case OBLOCK: 174 if(n->list == nil) 175 goto ret; 176 177 switch(n->list->n->op) { 178 case OCALLFUNC: 179 case OCALLMETH: 180 case OCALLINTER: 181 // Blocks are used for multiple return function calls. 182 // x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]} 183 // We don't want to instrument between the statements because it will 184 // smash the results. 185 racewalknode(&n->list->n, &n->list->n->ninit, 0, 0); 186 fini = nil; 187 racewalklist(n->list->next, &fini); 188 n->list = concat(n->list, fini); 189 break; 190 191 default: 192 // Ordinary block, for loop initialization or inlined bodies. 193 racewalklist(n->list, nil); 194 break; 195 } 196 goto ret; 197 198 case ODEFER: 199 racewalknode(&n->left, init, 0, 0); 200 goto ret; 201 202 case OPROC: 203 racewalknode(&n->left, init, 0, 0); 204 goto ret; 205 206 case OCALLINTER: 207 racewalknode(&n->left, init, 0, 0); 208 goto ret; 209 210 case OCALLFUNC: 211 // Instrument dst argument of runtime.writebarrier* calls 212 // as we do not instrument runtime code. 213 if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) { 214 // Find the dst argument. 215 // The list can be reordered, so it's not necessary just the first or the second element. 216 for(l = n->list; l; l = l->next) { 217 if(strcmp(n->left->sym->name, "writebarrierfat") == 0) { 218 if(l->n->left->xoffset == widthptr) 219 break; 220 } else { 221 if(l->n->left->xoffset == 0) 222 break; 223 } 224 } 225 if(l == nil) 226 fatal("racewalk: writebarrier no arg"); 227 if(l->n->right->op != OADDR) 228 fatal("racewalk: writebarrier bad arg"); 229 callinstr(&l->n->right->left, init, 1, 0); 230 } 231 racewalknode(&n->left, init, 0, 0); 232 goto ret; 233 234 case ONOT: 235 case OMINUS: 236 case OPLUS: 237 case OREAL: 238 case OIMAG: 239 case OCOM: 240 racewalknode(&n->left, init, wr, 0); 241 goto ret; 242 243 case ODOTINTER: 244 racewalknode(&n->left, init, 0, 0); 245 goto ret; 246 247 case ODOT: 248 racewalknode(&n->left, init, 0, 1); 249 callinstr(&n, init, wr, skip); 250 goto ret; 251 252 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND 253 racewalknode(&n->left, init, 0, 0); 254 callinstr(&n, init, wr, skip); 255 goto ret; 256 257 case OIND: // *p 258 racewalknode(&n->left, init, 0, 0); 259 callinstr(&n, init, wr, skip); 260 goto ret; 261 262 case OSPTR: 263 case OLEN: 264 case OCAP: 265 racewalknode(&n->left, init, 0, 0); 266 if(istype(n->left->type, TMAP)) { 267 n1 = nod(OCONVNOP, n->left, N); 268 n1->type = ptrto(types[TUINT8]); 269 n1 = nod(OIND, n1, N); 270 typecheck(&n1, Erv); 271 callinstr(&n1, init, 0, skip); 272 } 273 goto ret; 274 275 case OLSH: 276 case ORSH: 277 case OLROT: 278 case OAND: 279 case OANDNOT: 280 case OOR: 281 case OXOR: 282 case OSUB: 283 case OMUL: 284 case OHMUL: 285 case OEQ: 286 case ONE: 287 case OLT: 288 case OLE: 289 case OGE: 290 case OGT: 291 case OADD: 292 case OCOMPLEX: 293 racewalknode(&n->left, init, wr, 0); 294 racewalknode(&n->right, init, wr, 0); 295 goto ret; 296 297 case OANDAND: 298 case OOROR: 299 racewalknode(&n->left, init, wr, 0); 300 // walk has ensured the node has moved to a location where 301 // side effects are safe. 302 // n->right may not be executed, 303 // so instrumentation goes to n->right->ninit, not init. 304 racewalknode(&n->right, &n->right->ninit, wr, 0); 305 goto ret; 306 307 case ONAME: 308 callinstr(&n, init, wr, skip); 309 goto ret; 310 311 case OCONV: 312 racewalknode(&n->left, init, wr, 0); 313 goto ret; 314 315 case OCONVNOP: 316 racewalknode(&n->left, init, wr, 0); 317 goto ret; 318 319 case ODIV: 320 case OMOD: 321 racewalknode(&n->left, init, wr, 0); 322 racewalknode(&n->right, init, wr, 0); 323 goto ret; 324 325 case OINDEX: 326 if(!isfixedarray(n->left->type)) 327 racewalknode(&n->left, init, 0, 0); 328 else if(!islvalue(n->left)) { 329 // index of unaddressable array, like Map[k][i]. 330 racewalknode(&n->left, init, wr, 0); 331 racewalknode(&n->right, init, 0, 0); 332 goto ret; 333 } 334 racewalknode(&n->right, init, 0, 0); 335 if(n->left->type->etype != TSTRING) 336 callinstr(&n, init, wr, skip); 337 goto ret; 338 339 case OSLICE: 340 case OSLICEARR: 341 case OSLICE3: 342 case OSLICE3ARR: 343 // Seems to only lead to double instrumentation. 344 //racewalknode(&n->left, init, 0, 0); 345 goto ret; 346 347 case OADDR: 348 racewalknode(&n->left, init, 0, 1); 349 goto ret; 350 351 case OEFACE: 352 racewalknode(&n->left, init, 0, 0); 353 racewalknode(&n->right, init, 0, 0); 354 goto ret; 355 356 case OITAB: 357 racewalknode(&n->left, init, 0, 0); 358 goto ret; 359 360 // should not appear in AST by now 361 case OSEND: 362 case ORECV: 363 case OCLOSE: 364 case ONEW: 365 case OXCASE: 366 case OXFALL: 367 case OCASE: 368 case OPANIC: 369 case ORECOVER: 370 case OCONVIFACE: 371 case OCMPIFACE: 372 case OMAKECHAN: 373 case OMAKEMAP: 374 case OMAKESLICE: 375 case OCALL: 376 case OCOPY: 377 case OAPPEND: 378 case ORUNESTR: 379 case OARRAYBYTESTR: 380 case OARRAYRUNESTR: 381 case OSTRARRAYBYTE: 382 case OSTRARRAYRUNE: 383 case OINDEXMAP: // lowered to call 384 case OCMPSTR: 385 case OADDSTR: 386 case ODOTTYPE: 387 case ODOTTYPE2: 388 case OAS2DOTTYPE: 389 case OCALLPART: // lowered to PTRLIT 390 case OCLOSURE: // lowered to PTRLIT 391 case ORANGE: // lowered to ordinary for loop 392 case OARRAYLIT: // lowered to assignments 393 case OMAPLIT: 394 case OSTRUCTLIT: 395 yyerror("racewalk: %O must be lowered by now", n->op); 396 goto ret; 397 398 // impossible nodes: only appear in backend. 399 case ORROTC: 400 case OEXTEND: 401 yyerror("racewalk: %O cannot exist now", n->op); 402 goto ret; 403 404 // just do generic traversal 405 case OFOR: 406 case OIF: 407 case OCALLMETH: 408 case ORETURN: 409 case ORETJMP: 410 case OSWITCH: 411 case OSELECT: 412 case OEMPTY: 413 case OBREAK: 414 case OCONTINUE: 415 case OFALL: 416 case OGOTO: 417 case OLABEL: 418 goto ret; 419 420 // does not require instrumentation 421 case OPRINT: // don't bother instrumenting it 422 case OPRINTN: // don't bother instrumenting it 423 case OCHECKNIL: // always followed by a read. 424 case OPARAM: // it appears only in fn->exit to copy heap params back 425 case OCLOSUREVAR:// immutable pointer to captured variable 426 case ODOTMETH: // either part of CALLMETH or CALLPART (lowered to PTRLIT) 427 case OINDREG: // at this stage, only n(SP) nodes from nodarg 428 case ODCL: // declarations (without value) cannot be races 429 case ODCLCONST: 430 case ODCLTYPE: 431 case OTYPE: 432 case ONONAME: 433 case OLITERAL: 434 case OSLICESTR: // always preceded by bounds checking, avoid double instrumentation. 435 case OTYPESW: // ignored by code generation, do not instrument. 436 goto ret; 437 } 438 439 ret: 440 if(n->op != OBLOCK) // OBLOCK is handled above in a special way. 441 racewalklist(n->list, init); 442 if(n->ntest != N) 443 racewalknode(&n->ntest, &n->ntest->ninit, 0, 0); 444 if(n->nincr != N) 445 racewalknode(&n->nincr, &n->nincr->ninit, 0, 0); 446 racewalklist(n->nbody, nil); 447 racewalklist(n->nelse, nil); 448 racewalklist(n->rlist, nil); 449 *np = n; 450 } 451 452 static int 453 isartificial(Node *n) 454 { 455 // compiler-emitted artificial things that we do not want to instrument, 456 // cant' possibly participate in a data race. 457 if(n->op == ONAME && n->sym != S && n->sym->name != nil) { 458 if(strcmp(n->sym->name, "_") == 0) 459 return 1; 460 // autotmp's are always local 461 if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0) 462 return 1; 463 // statictmp's are read-only 464 if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0) 465 return 1; 466 // go.itab is accessed only by the compiler and runtime (assume safe) 467 if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0) 468 return 1; 469 } 470 return 0; 471 } 472 473 static int 474 callinstr(Node **np, NodeList **init, int wr, int skip) 475 { 476 Node *f, *b, *n; 477 Type *t; 478 int class, hascalls; 479 480 n = *np; 481 //print("callinstr for %+N [ %O ] etype=%E class=%d\n", 482 // n, n->op, n->type ? n->type->etype : -1, n->class); 483 484 if(skip || n->type == T || n->type->etype >= TIDEAL) 485 return 0; 486 t = n->type; 487 if(isartificial(n)) 488 return 0; 489 490 b = basenod(n); 491 // it skips e.g. stores to ... parameter array 492 if(isartificial(b)) 493 return 0; 494 class = b->class; 495 // BUG: we _may_ want to instrument PAUTO sometimes 496 // e.g. if we've got a local variable/method receiver 497 // that has got a pointer inside. Whether it points to 498 // the heap or not is impossible to know at compile time 499 if((class&PHEAP) || class == PPARAMREF || class == PEXTERN 500 || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) { 501 hascalls = 0; 502 foreach(n, hascallspred, &hascalls); 503 if(hascalls) { 504 n = detachexpr(n, init); 505 *np = n; 506 } 507 n = treecopy(n); 508 makeaddable(n); 509 if(t->etype == TSTRUCT || isfixedarray(t)) { 510 f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n), 511 nodintconst(t->width)); 512 } else 513 f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n)); 514 *init = list(*init, f); 515 return 1; 516 } 517 return 0; 518 } 519 520 // makeaddable returns a node whose memory location is the 521 // same as n, but which is addressable in the Go language 522 // sense. 523 // This is different from functions like cheapexpr that may make 524 // a copy of their argument. 525 static void 526 makeaddable(Node *n) 527 { 528 // The arguments to uintptraddr technically have an address but 529 // may not be addressable in the Go sense: for example, in the case 530 // of T(v).Field where T is a struct type and v is 531 // an addressable value. 532 switch(n->op) { 533 case OINDEX: 534 if(isfixedarray(n->left->type)) 535 makeaddable(n->left); 536 break; 537 case ODOT: 538 case OXDOT: 539 // Turn T(v).Field into v.Field 540 if(n->left->op == OCONVNOP) 541 n->left = n->left->left; 542 makeaddable(n->left); 543 break; 544 case ODOTPTR: 545 default: 546 // nothing to do 547 break; 548 } 549 } 550 551 static Node* 552 uintptraddr(Node *n) 553 { 554 Node *r; 555 556 r = nod(OADDR, n, N); 557 r->bounded = 1; 558 r = conv(r, types[TUNSAFEPTR]); 559 r = conv(r, types[TUINTPTR]); 560 return r; 561 } 562 563 // basenod returns the simplest child node of n pointing to the same 564 // memory area. 565 static Node* 566 basenod(Node *n) 567 { 568 for(;;) { 569 if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) { 570 n = n->left; 571 continue; 572 } 573 if(n->op == OINDEX && isfixedarray(n->type)) { 574 n = n->left; 575 continue; 576 } 577 break; 578 } 579 return n; 580 } 581 582 static Node* 583 detachexpr(Node *n, NodeList **init) 584 { 585 Node *addr, *as, *ind, *l; 586 587 addr = nod(OADDR, n, N); 588 l = temp(ptrto(n->type)); 589 as = nod(OAS, l, addr); 590 typecheck(&as, Etop); 591 walkexpr(&as, init); 592 *init = list(*init, as); 593 ind = nod(OIND, l, N); 594 typecheck(&ind, Erv); 595 walkexpr(&ind, init); 596 return ind; 597 } 598 599 static void 600 foreachnode(Node *n, void(*f)(Node*, void*), void *c) 601 { 602 if(n) 603 f(n, c); 604 } 605 606 static void 607 foreachlist(NodeList *l, void(*f)(Node*, void*), void *c) 608 { 609 for(; l; l = l->next) 610 foreachnode(l->n, f, c); 611 } 612 613 static void 614 foreach(Node *n, void(*f)(Node*, void*), void *c) 615 { 616 foreachlist(n->ninit, f, c); 617 foreachnode(n->left, f, c); 618 foreachnode(n->right, f, c); 619 foreachlist(n->list, f, c); 620 foreachnode(n->ntest, f, c); 621 foreachnode(n->nincr, f, c); 622 foreachlist(n->nbody, f, c); 623 foreachlist(n->nelse, f, c); 624 foreachlist(n->rlist, f, c); 625 } 626 627 static void 628 hascallspred(Node *n, void *c) 629 { 630 switch(n->op) { 631 case OCALL: 632 case OCALLFUNC: 633 case OCALLMETH: 634 case OCALLINTER: 635 (*(int*)c)++; 636 } 637 } 638 639 // appendinit is like addinit in subr.c 640 // but appends rather than prepends. 641 static void 642 appendinit(Node **np, NodeList *init) 643 { 644 Node *n; 645 646 if(init == nil) 647 return; 648 649 n = *np; 650 switch(n->op) { 651 case ONAME: 652 case OLITERAL: 653 // There may be multiple refs to this node; 654 // introduce OCONVNOP to hold init list. 655 n = nod(OCONVNOP, n, N); 656 n->type = n->left->type; 657 n->typecheck = 1; 658 *np = n; 659 break; 660 } 661 n->ninit = concat(n->ninit, init); 662 n->ullman = UINF; 663 } 664