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