github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 // can't matter 170 goto ret; 171 172 case OBLOCK: 173 if(n->list == nil) 174 goto ret; 175 176 switch(n->list->n->op) { 177 case OCALLFUNC: 178 case OCALLMETH: 179 case OCALLINTER: 180 // Blocks are used for multiple return function calls. 181 // x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]} 182 // We don't want to instrument between the statements because it will 183 // smash the results. 184 racewalknode(&n->list->n, &n->ninit, 0, 0); 185 fini = nil; 186 racewalklist(n->list->next, &fini); 187 n->list = concat(n->list, fini); 188 break; 189 190 default: 191 // Ordinary block, for loop initialization or inlined bodies. 192 racewalklist(n->list, nil); 193 break; 194 } 195 goto ret; 196 197 case ODEFER: 198 racewalknode(&n->left, init, 0, 0); 199 goto ret; 200 201 case OPROC: 202 racewalknode(&n->left, init, 0, 0); 203 goto ret; 204 205 case OCALLINTER: 206 racewalknode(&n->left, init, 0, 0); 207 goto ret; 208 209 case OCALLFUNC: 210 racewalknode(&n->left, init, 0, 0); 211 goto ret; 212 213 case ONOT: 214 case OMINUS: 215 case OPLUS: 216 case OREAL: 217 case OIMAG: 218 case OCOM: 219 racewalknode(&n->left, init, wr, 0); 220 goto ret; 221 222 case ODOTINTER: 223 racewalknode(&n->left, init, 0, 0); 224 goto ret; 225 226 case ODOT: 227 racewalknode(&n->left, init, 0, 1); 228 callinstr(&n, init, wr, skip); 229 goto ret; 230 231 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND 232 racewalknode(&n->left, init, 0, 0); 233 callinstr(&n, init, wr, skip); 234 goto ret; 235 236 case OIND: // *p 237 racewalknode(&n->left, init, 0, 0); 238 callinstr(&n, init, wr, skip); 239 goto ret; 240 241 case OSPTR: 242 case OLEN: 243 case OCAP: 244 racewalknode(&n->left, init, 0, 0); 245 if(istype(n->left->type, TMAP)) { 246 n1 = nod(OCONVNOP, n->left, N); 247 n1->type = ptrto(types[TUINT8]); 248 n1 = nod(OIND, n1, N); 249 typecheck(&n1, Erv); 250 callinstr(&n1, init, 0, skip); 251 } 252 goto ret; 253 254 case OLSH: 255 case ORSH: 256 case OLROT: 257 case OAND: 258 case OANDNOT: 259 case OOR: 260 case OXOR: 261 case OSUB: 262 case OMUL: 263 case OHMUL: 264 case OEQ: 265 case ONE: 266 case OLT: 267 case OLE: 268 case OGE: 269 case OGT: 270 case OADD: 271 case OCOMPLEX: 272 racewalknode(&n->left, init, wr, 0); 273 racewalknode(&n->right, init, wr, 0); 274 goto ret; 275 276 case OANDAND: 277 case OOROR: 278 racewalknode(&n->left, init, wr, 0); 279 // walk has ensured the node has moved to a location where 280 // side effects are safe. 281 // n->right may not be executed, 282 // so instrumentation goes to n->right->ninit, not init. 283 racewalknode(&n->right, &n->right->ninit, wr, 0); 284 goto ret; 285 286 case ONAME: 287 callinstr(&n, init, wr, skip); 288 goto ret; 289 290 case OCONV: 291 racewalknode(&n->left, init, wr, 0); 292 goto ret; 293 294 case OCONVNOP: 295 racewalknode(&n->left, init, wr, 0); 296 goto ret; 297 298 case ODIV: 299 case OMOD: 300 racewalknode(&n->left, init, wr, 0); 301 racewalknode(&n->right, init, wr, 0); 302 goto ret; 303 304 case OINDEX: 305 if(!isfixedarray(n->left->type)) 306 racewalknode(&n->left, init, 0, 0); 307 else if(!islvalue(n->left)) { 308 // index of unaddressable array, like Map[k][i]. 309 racewalknode(&n->left, init, wr, 0); 310 racewalknode(&n->right, init, 0, 0); 311 goto ret; 312 } 313 racewalknode(&n->right, init, 0, 0); 314 if(n->left->type->etype != TSTRING) 315 callinstr(&n, init, wr, skip); 316 goto ret; 317 318 case OSLICE: 319 case OSLICEARR: 320 case OSLICE3: 321 case OSLICE3ARR: 322 // Seems to only lead to double instrumentation. 323 //racewalknode(&n->left, init, 0, 0); 324 goto ret; 325 326 case OADDR: 327 racewalknode(&n->left, init, 0, 1); 328 goto ret; 329 330 case OEFACE: 331 racewalknode(&n->left, init, 0, 0); 332 racewalknode(&n->right, init, 0, 0); 333 goto ret; 334 335 case OITAB: 336 racewalknode(&n->left, init, 0, 0); 337 goto ret; 338 339 // should not appear in AST by now 340 case OSEND: 341 case ORECV: 342 case OCLOSE: 343 case ONEW: 344 case OXCASE: 345 case OXFALL: 346 case OCASE: 347 case OPANIC: 348 case ORECOVER: 349 case OCONVIFACE: 350 case OCMPIFACE: 351 case OMAKECHAN: 352 case OMAKEMAP: 353 case OMAKESLICE: 354 case OCALL: 355 case OCOPY: 356 case OAPPEND: 357 case ORUNESTR: 358 case OARRAYBYTESTR: 359 case OARRAYRUNESTR: 360 case OSTRARRAYBYTE: 361 case OSTRARRAYRUNE: 362 case OINDEXMAP: // lowered to call 363 case OCMPSTR: 364 case OADDSTR: 365 case ODOTTYPE: 366 case ODOTTYPE2: 367 case OAS2DOTTYPE: 368 case OCALLPART: // lowered to PTRLIT 369 case OCLOSURE: // lowered to PTRLIT 370 case ORANGE: // lowered to ordinary for loop 371 case OARRAYLIT: // lowered to assignments 372 case OMAPLIT: 373 case OSTRUCTLIT: 374 yyerror("racewalk: %O must be lowered by now", n->op); 375 goto ret; 376 377 // impossible nodes: only appear in backend. 378 case ORROTC: 379 case OEXTEND: 380 yyerror("racewalk: %O cannot exist now", n->op); 381 goto ret; 382 383 // just do generic traversal 384 case OFOR: 385 case OIF: 386 case OCALLMETH: 387 case ORETURN: 388 case ORETJMP: 389 case OSWITCH: 390 case OSELECT: 391 case OEMPTY: 392 case OBREAK: 393 case OCONTINUE: 394 case OFALL: 395 case OGOTO: 396 case OLABEL: 397 goto ret; 398 399 // does not require instrumentation 400 case OPRINT: // don't bother instrumenting it 401 case OPRINTN: // don't bother instrumenting it 402 case OCHECKNIL: // always followed by a read. 403 case OPARAM: // it appears only in fn->exit to copy heap params back 404 case OCLOSUREVAR:// immutable pointer to captured variable 405 case ODOTMETH: // either part of CALLMETH or CALLPART (lowered to PTRLIT) 406 case OINDREG: // at this stage, only n(SP) nodes from nodarg 407 case ODCL: // declarations (without value) cannot be races 408 case ODCLCONST: 409 case ODCLTYPE: 410 case OTYPE: 411 case ONONAME: 412 case OLITERAL: 413 case OSLICESTR: // always preceded by bounds checking, avoid double instrumentation. 414 case OTYPESW: // ignored by code generation, do not instrument. 415 goto ret; 416 } 417 418 ret: 419 if(n->op != OBLOCK) // OBLOCK is handled above in a special way. 420 racewalklist(n->list, init); 421 racewalknode(&n->ntest, &n->ntest->ninit, 0, 0); 422 racewalknode(&n->nincr, &n->nincr->ninit, 0, 0); 423 racewalklist(n->nbody, nil); 424 racewalklist(n->nelse, nil); 425 racewalklist(n->rlist, nil); 426 *np = n; 427 } 428 429 static int 430 isartificial(Node *n) 431 { 432 // compiler-emitted artificial things that we do not want to instrument, 433 // cant' possibly participate in a data race. 434 if(n->op == ONAME && n->sym != S && n->sym->name != nil) { 435 if(strcmp(n->sym->name, "_") == 0) 436 return 1; 437 // autotmp's are always local 438 if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0) 439 return 1; 440 // statictmp's are read-only 441 if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0) 442 return 1; 443 // go.itab is accessed only by the compiler and runtime (assume safe) 444 if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0) 445 return 1; 446 } 447 return 0; 448 } 449 450 static int 451 callinstr(Node **np, NodeList **init, int wr, int skip) 452 { 453 Node *f, *b, *n; 454 Type *t; 455 int class, hascalls; 456 457 n = *np; 458 //print("callinstr for %+N [ %O ] etype=%E class=%d\n", 459 // n, n->op, n->type ? n->type->etype : -1, n->class); 460 461 if(skip || n->type == T || n->type->etype >= TIDEAL) 462 return 0; 463 t = n->type; 464 if(isartificial(n)) 465 return 0; 466 467 b = basenod(n); 468 // it skips e.g. stores to ... parameter array 469 if(isartificial(b)) 470 return 0; 471 class = b->class; 472 // BUG: we _may_ want to instrument PAUTO sometimes 473 // e.g. if we've got a local variable/method receiver 474 // that has got a pointer inside. Whether it points to 475 // the heap or not is impossible to know at compile time 476 if((class&PHEAP) || class == PPARAMREF || class == PEXTERN 477 || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) { 478 hascalls = 0; 479 foreach(n, hascallspred, &hascalls); 480 if(hascalls) { 481 n = detachexpr(n, init); 482 *np = n; 483 } 484 n = treecopy(n); 485 makeaddable(n); 486 if(t->etype == TSTRUCT || isfixedarray(t)) { 487 f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n), 488 nodintconst(t->width)); 489 } else 490 f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n)); 491 *init = list(*init, f); 492 return 1; 493 } 494 return 0; 495 } 496 497 // makeaddable returns a node whose memory location is the 498 // same as n, but which is addressable in the Go language 499 // sense. 500 // This is different from functions like cheapexpr that may make 501 // a copy of their argument. 502 static void 503 makeaddable(Node *n) 504 { 505 // The arguments to uintptraddr technically have an address but 506 // may not be addressable in the Go sense: for example, in the case 507 // of T(v).Field where T is a struct type and v is 508 // an addressable value. 509 switch(n->op) { 510 case OINDEX: 511 if(isfixedarray(n->left->type)) 512 makeaddable(n->left); 513 break; 514 case ODOT: 515 case OXDOT: 516 // Turn T(v).Field into v.Field 517 if(n->left->op == OCONVNOP) 518 n->left = n->left->left; 519 makeaddable(n->left); 520 break; 521 case ODOTPTR: 522 default: 523 // nothing to do 524 break; 525 } 526 } 527 528 static Node* 529 uintptraddr(Node *n) 530 { 531 Node *r; 532 533 r = nod(OADDR, n, N); 534 r->bounded = 1; 535 r = conv(r, types[TUNSAFEPTR]); 536 r = conv(r, types[TUINTPTR]); 537 return r; 538 } 539 540 // basenod returns the simplest child node of n pointing to the same 541 // memory area. 542 static Node* 543 basenod(Node *n) 544 { 545 for(;;) { 546 if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) { 547 n = n->left; 548 continue; 549 } 550 if(n->op == OINDEX && isfixedarray(n->type)) { 551 n = n->left; 552 continue; 553 } 554 break; 555 } 556 return n; 557 } 558 559 static Node* 560 detachexpr(Node *n, NodeList **init) 561 { 562 Node *addr, *as, *ind, *l; 563 564 addr = nod(OADDR, n, N); 565 l = temp(ptrto(n->type)); 566 as = nod(OAS, l, addr); 567 typecheck(&as, Etop); 568 walkexpr(&as, init); 569 *init = list(*init, as); 570 ind = nod(OIND, l, N); 571 typecheck(&ind, Erv); 572 walkexpr(&ind, init); 573 return ind; 574 } 575 576 static void 577 foreachnode(Node *n, void(*f)(Node*, void*), void *c) 578 { 579 if(n) 580 f(n, c); 581 } 582 583 static void 584 foreachlist(NodeList *l, void(*f)(Node*, void*), void *c) 585 { 586 for(; l; l = l->next) 587 foreachnode(l->n, f, c); 588 } 589 590 static void 591 foreach(Node *n, void(*f)(Node*, void*), void *c) 592 { 593 foreachlist(n->ninit, f, c); 594 foreachnode(n->left, f, c); 595 foreachnode(n->right, f, c); 596 foreachlist(n->list, f, c); 597 foreachnode(n->ntest, f, c); 598 foreachnode(n->nincr, f, c); 599 foreachlist(n->nbody, f, c); 600 foreachlist(n->nelse, f, c); 601 foreachlist(n->rlist, f, c); 602 } 603 604 static void 605 hascallspred(Node *n, void *c) 606 { 607 switch(n->op) { 608 case OCALL: 609 case OCALLFUNC: 610 case OCALLMETH: 611 case OCALLINTER: 612 (*(int*)c)++; 613 } 614 } 615 616 // appendinit is like addinit in subr.c 617 // but appends rather than prepends. 618 static void 619 appendinit(Node **np, NodeList *init) 620 { 621 Node *n; 622 623 if(init == nil) 624 return; 625 626 n = *np; 627 switch(n->op) { 628 case ONAME: 629 case OLITERAL: 630 // There may be multiple refs to this node; 631 // introduce OCONVNOP to hold init list. 632 n = nod(OCONVNOP, n, N); 633 n->type = n->left->type; 634 n->typecheck = 1; 635 *np = n; 636 break; 637 } 638 n->ninit = concat(n->ninit, init); 639 n->ullman = UINF; 640 } 641