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