github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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 144 // can't matter 145 case OCFUNC, OVARKILL, OVARLIVE: 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 164 case ODEFER: 165 instrumentnode(&n.Left, init, 0, 0) 166 167 case OPROC: 168 instrumentnode(&n.Left, init, 0, 0) 169 170 case OCALLINTER: 171 instrumentnode(&n.Left, init, 0, 0) 172 173 // Instrument dst argument of runtime.writebarrier* calls 174 // as we do not instrument runtime code. 175 // typedslicecopy is instrumented in runtime. 176 case OCALLFUNC: 177 instrumentnode(&n.Left, init, 0, 0) 178 179 case ONOT, 180 OMINUS, 181 OPLUS, 182 OREAL, 183 OIMAG, 184 OCOM: 185 instrumentnode(&n.Left, init, wr, 0) 186 187 case ODOTINTER: 188 instrumentnode(&n.Left, init, 0, 0) 189 190 case ODOT: 191 instrumentnode(&n.Left, init, 0, 1) 192 callinstr(&n, init, wr, skip) 193 194 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND 195 instrumentnode(&n.Left, init, 0, 0) 196 197 callinstr(&n, init, wr, skip) 198 199 case OIND: // *p 200 instrumentnode(&n.Left, init, 0, 0) 201 202 callinstr(&n, init, wr, skip) 203 204 case OSPTR, OLEN, OCAP: 205 instrumentnode(&n.Left, init, 0, 0) 206 if n.Left.Type.IsMap() { 207 n1 := nod(OCONVNOP, n.Left, nil) 208 n1.Type = types.NewPtr(types.Types[TUINT8]) 209 n1 = nod(OIND, n1, nil) 210 n1 = typecheck(n1, Erv) 211 callinstr(&n1, init, 0, skip) 212 } 213 214 case OLSH, 215 ORSH, 216 OAND, 217 OANDNOT, 218 OOR, 219 OXOR, 220 OSUB, 221 OMUL, 222 OEQ, 223 ONE, 224 OLT, 225 OLE, 226 OGE, 227 OGT, 228 OADD, 229 OCOMPLEX: 230 instrumentnode(&n.Left, init, wr, 0) 231 instrumentnode(&n.Right, init, wr, 0) 232 233 case OANDAND, OOROR: 234 instrumentnode(&n.Left, init, wr, 0) 235 236 // walk has ensured the node has moved to a location where 237 // side effects are safe. 238 // n->right may not be executed, 239 // so instrumentation goes to n->right->ninit, not init. 240 instrumentnode(&n.Right, &n.Right.Ninit, wr, 0) 241 242 case ONAME: 243 callinstr(&n, init, wr, skip) 244 245 case OCONV: 246 instrumentnode(&n.Left, init, wr, 0) 247 248 case OCONVNOP: 249 instrumentnode(&n.Left, init, wr, 0) 250 251 case ODIV, OMOD: 252 instrumentnode(&n.Left, init, wr, 0) 253 instrumentnode(&n.Right, init, wr, 0) 254 255 case OINDEX: 256 if !n.Left.Type.IsArray() { 257 instrumentnode(&n.Left, init, 0, 0) 258 } else if !islvalue(n.Left) { 259 // index of unaddressable array, like Map[k][i]. 260 instrumentnode(&n.Left, init, wr, 0) 261 262 instrumentnode(&n.Right, init, 0, 0) 263 break 264 } 265 266 instrumentnode(&n.Right, init, 0, 0) 267 if !n.Left.Type.IsString() { 268 callinstr(&n, init, wr, skip) 269 } 270 271 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR: 272 instrumentnode(&n.Left, init, 0, 0) 273 low, high, max := n.SliceBounds() 274 instrumentnode(&low, init, 0, 0) 275 instrumentnode(&high, init, 0, 0) 276 instrumentnode(&max, init, 0, 0) 277 n.SetSliceBounds(low, high, max) 278 279 case OADDR: 280 instrumentnode(&n.Left, init, 0, 1) 281 282 // n->left is Type* which is not interesting. 283 case OEFACE: 284 instrumentnode(&n.Right, init, 0, 0) 285 286 case OITAB, OIDATA: 287 instrumentnode(&n.Left, init, 0, 0) 288 289 case OSTRARRAYBYTETMP: 290 instrumentnode(&n.Left, init, 0, 0) 291 292 case OAS2DOTTYPE: 293 instrumentnode(&n.Left, init, 1, 0) 294 instrumentnode(&n.Right, init, 0, 0) 295 296 case ODOTTYPE, ODOTTYPE2: 297 instrumentnode(&n.Left, init, 0, 0) 298 299 // should not appear in AST by now 300 case OSEND, 301 ORECV, 302 OCLOSE, 303 ONEW, 304 OXCASE, 305 OCASE, 306 OPANIC, 307 ORECOVER, 308 OCONVIFACE, 309 OCMPIFACE, 310 OMAKECHAN, 311 OMAKEMAP, 312 OMAKESLICE, 313 OCALL, 314 OCOPY, 315 OAPPEND, 316 ORUNESTR, 317 OARRAYBYTESTR, 318 OARRAYRUNESTR, 319 OSTRARRAYBYTE, 320 OSTRARRAYRUNE, 321 OINDEXMAP, 322 // lowered to call 323 OCMPSTR, 324 OADDSTR, 325 OCALLPART, 326 // lowered to PTRLIT 327 OCLOSURE, // lowered to PTRLIT 328 ORANGE, // lowered to ordinary for loop 329 OARRAYLIT, // lowered to assignments 330 OSLICELIT, 331 OMAPLIT, 332 OSTRUCTLIT, 333 OAS2, 334 OAS2RECV, 335 OAS2MAPR, 336 OASOP: 337 Fatalf("instrument: %v must be lowered by now", n.Op) 338 339 case OGETG: 340 Fatalf("instrument: OGETG can happen only in runtime which we don't instrument") 341 342 case OFOR, OFORUNTIL: 343 if n.Left != nil { 344 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0) 345 } 346 if n.Right != nil { 347 instrumentnode(&n.Right, &n.Right.Ninit, 0, 0) 348 } 349 350 case OIF, OSWITCH: 351 if n.Left != nil { 352 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0) 353 } 354 355 // just do generic traversal 356 case OCALLMETH, 357 ORETURN, 358 ORETJMP, 359 OSELECT, 360 OEMPTY, 361 OBREAK, 362 OCONTINUE, 363 OFALL, 364 OGOTO, 365 OLABEL: 366 367 // does not require instrumentation 368 case OPRINT, // don't bother instrumenting it 369 OPRINTN, // don't bother instrumenting it 370 OCHECKNIL, // always followed by a read. 371 OCLOSUREVAR, // immutable pointer to captured variable 372 ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT) 373 OINDREGSP, // at this stage, only n(SP) nodes from nodarg 374 ODCL, // declarations (without value) cannot be races 375 ODCLCONST, 376 ODCLTYPE, 377 OTYPE, 378 ONONAME, 379 OLITERAL, 380 OTYPESW: // ignored by code generation, do not instrument. 381 } 382 383 if n.Op != OBLOCK { // OBLOCK is handled above in a special way. 384 instrumentlist(n.List, init) 385 } 386 instrumentlist(n.Nbody, nil) 387 instrumentlist(n.Rlist, nil) 388 *np = n 389 } 390 391 func isartificial(n *Node) bool { 392 // compiler-emitted artificial things that we do not want to instrument, 393 // can't possibly participate in a data race. 394 // can't be seen by C/C++ and therefore irrelevant for msan. 395 if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" { 396 if n.Sym.Name == "_" { 397 return true 398 } 399 400 // autotmp's are always local 401 if n.IsAutoTmp() { 402 return true 403 } 404 405 // statictmp's are read-only 406 if strings.HasPrefix(n.Sym.Name, "statictmp_") { 407 return true 408 } 409 410 // go.itab is accessed only by the compiler and runtime (assume safe) 411 if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" { 412 return true 413 } 414 } 415 416 return false 417 } 418 419 func callinstr(np **Node, init *Nodes, wr int, skip int) bool { 420 n := *np 421 422 //fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n", 423 // n, n.Op, n.Type.Etype, n.Class) 424 425 if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL { 426 return false 427 } 428 t := n.Type 429 // dowidth may not have been called for PEXTERN. 430 dowidth(t) 431 w := t.Width 432 if w == BADWIDTH { 433 Fatalf("instrument: %v badwidth", t) 434 } 435 if w == 0 { 436 return false // can't race on zero-sized things 437 } 438 if isartificial(n) { 439 return false 440 } 441 442 b := outervalue(n) 443 444 // it skips e.g. stores to ... parameter array 445 if isartificial(b) { 446 return false 447 } 448 class := b.Class() 449 450 // BUG: we _may_ want to instrument PAUTO sometimes 451 // e.g. if we've got a local variable/method receiver 452 // that has got a pointer inside. Whether it points to 453 // the heap or not is impossible to know at compile time 454 if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { 455 hascalls := 0 456 foreach(n, hascallspred, &hascalls) 457 if hascalls != 0 { 458 n = detachexpr(n, init) 459 *np = n 460 } 461 462 n = treecopy(n, src.NoXPos) 463 makeaddable(n) 464 var f *Node 465 if flag_msan { 466 name := "msanread" 467 if wr != 0 { 468 name = "msanwrite" 469 } 470 f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w)) 471 } else if flag_race && t.NumComponents() > 1 { 472 // for composite objects we have to write every address 473 // because a write might happen to any subobject. 474 // composites with only one element don't have subobjects, though. 475 name := "racereadrange" 476 if wr != 0 { 477 name = "racewriterange" 478 } 479 f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w)) 480 } else if flag_race { 481 // for non-composite objects we can write just the start 482 // address, as any write must write the first byte. 483 name := "raceread" 484 if wr != 0 { 485 name = "racewrite" 486 } 487 f = mkcall(name, nil, init, uintptraddr(n)) 488 } 489 490 init.Append(f) 491 return true 492 } 493 494 return false 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 func makeaddable(n *Node) { 503 // The arguments to uintptraddr technically have an address but 504 // may not be addressable in the Go sense: for example, in the case 505 // of T(v).Field where T is a struct type and v is 506 // an addressable value. 507 switch n.Op { 508 case OINDEX: 509 if n.Left.Type.IsArray() { 510 makeaddable(n.Left) 511 } 512 513 // Turn T(v).Field into v.Field 514 case ODOT, OXDOT: 515 if n.Left.Op == OCONVNOP { 516 n.Left = n.Left.Left 517 } 518 makeaddable(n.Left) 519 520 // nothing to do 521 } 522 } 523 524 func uintptraddr(n *Node) *Node { 525 r := nod(OADDR, n, nil) 526 r.SetBounded(true) 527 r = conv(r, types.Types[TUNSAFEPTR]) 528 r = conv(r, types.Types[TUINTPTR]) 529 return r 530 } 531 532 func detachexpr(n *Node, init *Nodes) *Node { 533 addr := nod(OADDR, n, nil) 534 l := temp(types.NewPtr(n.Type)) 535 as := nod(OAS, l, addr) 536 as = typecheck(as, Etop) 537 as = walkexpr(as, init) 538 init.Append(as) 539 ind := nod(OIND, l, nil) 540 ind = typecheck(ind, Erv) 541 ind = walkexpr(ind, init) 542 return ind 543 } 544 545 func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) { 546 if n != nil { 547 f(n, c) 548 } 549 } 550 551 func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) { 552 for _, n := range l.Slice() { 553 foreachnode(n, f, c) 554 } 555 } 556 557 func foreach(n *Node, f func(*Node, interface{}), c interface{}) { 558 foreachlist(n.Ninit, f, c) 559 foreachnode(n.Left, f, c) 560 foreachnode(n.Right, f, c) 561 foreachlist(n.List, f, c) 562 foreachlist(n.Nbody, f, c) 563 foreachlist(n.Rlist, f, c) 564 } 565 566 func hascallspred(n *Node, c interface{}) { 567 switch n.Op { 568 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER: 569 (*c.(*int))++ 570 } 571 } 572 573 // appendinit is like addinit in subr.go 574 // but appends rather than prepends. 575 func appendinit(np **Node, init Nodes) { 576 if init.Len() == 0 { 577 return 578 } 579 580 n := *np 581 switch n.Op { 582 // There may be multiple refs to this node; 583 // introduce OCONVNOP to hold init list. 584 case ONAME, OLITERAL: 585 n = nod(OCONVNOP, n, nil) 586 587 n.Type = n.Left.Type 588 n.SetTypecheck(1) 589 *np = n 590 } 591 592 n.Ninit.AppendNodes(&init) 593 n.SetHasCall(true) 594 }