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