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