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