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