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