github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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 racefuncenter 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", "runtime/race", "runtime/msan"} 35 36 // Only insert racefuncenter/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.Norace { 54 return 55 } 56 57 if flag_race == 0 || !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 != 0 { 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 := Nod(OXXX, nil, nil) 69 70 *nodpc = *nodfp 71 nodpc.Type = Types[TUINTPTR] 72 nodpc.Xoffset = int64(-Widthptr) 73 nd := mkcall("racefuncenter", nil, nil, nodpc) 74 fn.Func.Enter = concat(list1(nd), fn.Func.Enter) 75 nd = mkcall("racefuncexit", nil, nil) 76 fn.Func.Exit = list(fn.Func.Exit, nd) 77 } 78 79 if Debug['W'] != 0 { 80 s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym) 81 dumplist(s, fn.Nbody) 82 s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym) 83 dumplist(s, fn.Func.Enter) 84 s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym) 85 dumplist(s, fn.Func.Exit) 86 } 87 } 88 89 func instrumentlist(l *NodeList, init **NodeList) { 90 var instr *NodeList 91 92 for ; l != nil; l = l.Next { 93 instr = nil 94 instrumentnode(&l.N, &instr, 0, 0) 95 if init == nil { 96 l.N.Ninit = concat(l.N.Ninit, instr) 97 } else { 98 *init = concat(*init, 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 **NodeList, 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 = 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", Oconv(int(n.Op), 0)) 139 140 case OAS, OASWB, 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: 147 goto ret 148 149 case OBLOCK: 150 var out *NodeList 151 for l := n.List; l != nil; l = l.Next { 152 switch l.N.Op { 153 case OCALLFUNC, OCALLMETH, OCALLINTER: 154 instrumentnode(&l.N, &out, 0, 0) 155 out = list(out, l.N) 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 for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) { 162 l = l.Next 163 out = list(out, l.N) 164 } 165 default: 166 instrumentnode(&l.N, &out, 0, 0) 167 out = list(out, l.N) 168 } 169 } 170 n.List = out 171 goto ret 172 173 case ODEFER: 174 instrumentnode(&n.Left, init, 0, 0) 175 goto ret 176 177 case OPROC: 178 instrumentnode(&n.Left, init, 0, 0) 179 goto ret 180 181 case OCALLINTER: 182 instrumentnode(&n.Left, init, 0, 0) 183 goto ret 184 185 // Instrument dst argument of runtime.writebarrier* calls 186 // as we do not instrument runtime code. 187 // typedslicecopy is instrumented in runtime. 188 case OCALLFUNC: 189 instrumentnode(&n.Left, init, 0, 0) 190 goto ret 191 192 case ONOT, 193 OMINUS, 194 OPLUS, 195 OREAL, 196 OIMAG, 197 OCOM, 198 OSQRT: 199 instrumentnode(&n.Left, init, wr, 0) 200 goto ret 201 202 case ODOTINTER: 203 instrumentnode(&n.Left, init, 0, 0) 204 goto ret 205 206 case ODOT: 207 instrumentnode(&n.Left, init, 0, 1) 208 callinstr(&n, init, wr, skip) 209 goto ret 210 211 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND 212 instrumentnode(&n.Left, init, 0, 0) 213 214 callinstr(&n, init, wr, skip) 215 goto ret 216 217 case OIND: // *p 218 instrumentnode(&n.Left, init, 0, 0) 219 220 callinstr(&n, init, wr, skip) 221 goto ret 222 223 case OSPTR, OLEN, OCAP: 224 instrumentnode(&n.Left, init, 0, 0) 225 if Istype(n.Left.Type, TMAP) { 226 n1 := Nod(OCONVNOP, n.Left, nil) 227 n1.Type = Ptrto(Types[TUINT8]) 228 n1 = Nod(OIND, n1, nil) 229 typecheck(&n1, Erv) 230 callinstr(&n1, init, 0, skip) 231 } 232 233 goto ret 234 235 case OLSH, 236 ORSH, 237 OLROT, 238 OAND, 239 OANDNOT, 240 OOR, 241 OXOR, 242 OSUB, 243 OMUL, 244 OHMUL, 245 OEQ, 246 ONE, 247 OLT, 248 OLE, 249 OGE, 250 OGT, 251 OADD, 252 OCOMPLEX: 253 instrumentnode(&n.Left, init, wr, 0) 254 instrumentnode(&n.Right, init, wr, 0) 255 goto ret 256 257 case OANDAND, OOROR: 258 instrumentnode(&n.Left, init, wr, 0) 259 260 // walk has ensured the node has moved to a location where 261 // side effects are safe. 262 // n->right may not be executed, 263 // so instrumentation goes to n->right->ninit, not init. 264 instrumentnode(&n.Right, &n.Right.Ninit, wr, 0) 265 266 goto ret 267 268 case ONAME: 269 callinstr(&n, init, wr, skip) 270 goto ret 271 272 case OCONV: 273 instrumentnode(&n.Left, init, wr, 0) 274 goto ret 275 276 case OCONVNOP: 277 instrumentnode(&n.Left, init, wr, 0) 278 goto ret 279 280 case ODIV, OMOD: 281 instrumentnode(&n.Left, init, wr, 0) 282 instrumentnode(&n.Right, init, wr, 0) 283 goto ret 284 285 case OINDEX: 286 if !Isfixedarray(n.Left.Type) { 287 instrumentnode(&n.Left, init, 0, 0) 288 } else if !islvalue(n.Left) { 289 // index of unaddressable array, like Map[k][i]. 290 instrumentnode(&n.Left, init, wr, 0) 291 292 instrumentnode(&n.Right, init, 0, 0) 293 goto ret 294 } 295 296 instrumentnode(&n.Right, init, 0, 0) 297 if n.Left.Type.Etype != TSTRING { 298 callinstr(&n, init, wr, skip) 299 } 300 goto ret 301 302 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR: 303 instrumentnode(&n.Left, init, 0, 0) 304 instrumentnode(&n.Right, init, 0, 0) 305 goto ret 306 307 case OKEY: 308 instrumentnode(&n.Left, init, 0, 0) 309 instrumentnode(&n.Right, init, 0, 0) 310 goto ret 311 312 case OADDR: 313 instrumentnode(&n.Left, init, 0, 1) 314 goto ret 315 316 // n->left is Type* which is not interesting. 317 case OEFACE: 318 instrumentnode(&n.Right, init, 0, 0) 319 320 goto ret 321 322 case OITAB: 323 instrumentnode(&n.Left, init, 0, 0) 324 goto ret 325 326 // should not appear in AST by now 327 case OSEND, 328 ORECV, 329 OCLOSE, 330 ONEW, 331 OXCASE, 332 OXFALL, 333 OCASE, 334 OPANIC, 335 ORECOVER, 336 OCONVIFACE, 337 OCMPIFACE, 338 OMAKECHAN, 339 OMAKEMAP, 340 OMAKESLICE, 341 OCALL, 342 OCOPY, 343 OAPPEND, 344 ORUNESTR, 345 OARRAYBYTESTR, 346 OARRAYRUNESTR, 347 OSTRARRAYBYTE, 348 OSTRARRAYRUNE, 349 OINDEXMAP, 350 // lowered to call 351 OCMPSTR, 352 OADDSTR, 353 ODOTTYPE, 354 ODOTTYPE2, 355 OAS2DOTTYPE, 356 OCALLPART, 357 // lowered to PTRLIT 358 OCLOSURE, // lowered to PTRLIT 359 ORANGE, // lowered to ordinary for loop 360 OARRAYLIT, // lowered to assignments 361 OMAPLIT, 362 OSTRUCTLIT, 363 OAS2, 364 OAS2RECV, 365 OAS2MAPR, 366 OASOP: 367 Yyerror("instrument: %v must be lowered by now", Oconv(int(n.Op), 0)) 368 369 goto ret 370 371 // impossible nodes: only appear in backend. 372 case ORROTC, OEXTEND: 373 Yyerror("instrument: %v cannot exist now", Oconv(int(n.Op), 0)) 374 goto ret 375 376 case OGETG: 377 Yyerror("instrument: OGETG can happen only in runtime which we don't instrument") 378 goto ret 379 380 case OFOR: 381 if n.Left != nil { 382 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0) 383 } 384 if n.Right != nil { 385 instrumentnode(&n.Right, &n.Right.Ninit, 0, 0) 386 } 387 goto ret 388 389 case OIF, OSWITCH: 390 if n.Left != nil { 391 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0) 392 } 393 goto ret 394 395 // just do generic traversal 396 case OCALLMETH, 397 ORETURN, 398 ORETJMP, 399 OSELECT, 400 OEMPTY, 401 OBREAK, 402 OCONTINUE, 403 OFALL, 404 OGOTO, 405 OLABEL: 406 goto ret 407 408 // does not require instrumentation 409 case OPRINT, // don't bother instrumenting it 410 OPRINTN, // don't bother instrumenting it 411 OCHECKNIL, // always followed by a read. 412 OPARAM, // it appears only in fn->exit to copy heap params back 413 OCLOSUREVAR, // immutable pointer to captured variable 414 ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT) 415 OINDREG, // at this stage, only n(SP) nodes from nodarg 416 ODCL, // declarations (without value) cannot be races 417 ODCLCONST, 418 ODCLTYPE, 419 OTYPE, 420 ONONAME, 421 OLITERAL, 422 OTYPESW: // ignored by code generation, do not instrument. 423 goto ret 424 } 425 426 ret: 427 if n.Op != OBLOCK { // OBLOCK is handled above in a special way. 428 instrumentlist(n.List, init) 429 } 430 instrumentlist(n.Nbody, nil) 431 instrumentlist(n.Rlist, nil) 432 *np = n 433 } 434 435 func isartificial(n *Node) bool { 436 // compiler-emitted artificial things that we do not want to instrument, 437 // can't possibly participate in a data race. 438 // can't be seen by C/C++ and therefore irrelevant for msan. 439 if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" { 440 if n.Sym.Name == "_" { 441 return true 442 } 443 444 // autotmp's are always local 445 if strings.HasPrefix(n.Sym.Name, "autotmp_") { 446 return true 447 } 448 449 // statictmp's are read-only 450 if strings.HasPrefix(n.Sym.Name, "statictmp_") { 451 return true 452 } 453 454 // go.itab is accessed only by the compiler and runtime (assume safe) 455 if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" { 456 return true 457 } 458 } 459 460 return false 461 } 462 463 func callinstr(np **Node, init **NodeList, wr int, skip int) bool { 464 n := *np 465 466 //print("callinstr for %+N [ %O ] etype=%E class=%d\n", 467 // n, n->op, n->type ? n->type->etype : -1, n->class); 468 469 if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL { 470 return false 471 } 472 t := n.Type 473 if isartificial(n) { 474 return false 475 } 476 477 b := outervalue(n) 478 479 // it skips e.g. stores to ... parameter array 480 if isartificial(b) { 481 return false 482 } 483 class := b.Class 484 485 // BUG: we _may_ want to instrument PAUTO sometimes 486 // e.g. if we've got a local variable/method receiver 487 // that has got a pointer inside. Whether it points to 488 // the heap or not is impossible to know at compile time 489 if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND { 490 hascalls := 0 491 foreach(n, hascallspred, &hascalls) 492 if hascalls != 0 { 493 n = detachexpr(n, init) 494 *np = n 495 } 496 497 n = treecopy(n, 0) 498 makeaddable(n) 499 var f *Node 500 if flag_msan != 0 { 501 name := "msanread" 502 if wr != 0 { 503 name = "msanwrite" 504 } 505 f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width)) 506 } else if flag_race != 0 && (t.Etype == TSTRUCT || Isfixedarray(t)) { 507 name := "racereadrange" 508 if wr != 0 { 509 name = "racewriterange" 510 } 511 f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width)) 512 } else if flag_race != 0 { 513 name := "raceread" 514 if wr != 0 { 515 name = "racewrite" 516 } 517 f = mkcall(name, nil, init, uintptraddr(n)) 518 } 519 520 *init = list(*init, f) 521 return true 522 } 523 524 return false 525 } 526 527 // makeaddable returns a node whose memory location is the 528 // same as n, but which is addressable in the Go language 529 // sense. 530 // This is different from functions like cheapexpr that may make 531 // a copy of their argument. 532 func makeaddable(n *Node) { 533 // The arguments to uintptraddr technically have an address but 534 // may not be addressable in the Go sense: for example, in the case 535 // of T(v).Field where T is a struct type and v is 536 // an addressable value. 537 switch n.Op { 538 case OINDEX: 539 if Isfixedarray(n.Left.Type) { 540 makeaddable(n.Left) 541 } 542 543 // Turn T(v).Field into v.Field 544 case ODOT, OXDOT: 545 if n.Left.Op == OCONVNOP { 546 n.Left = n.Left.Left 547 } 548 makeaddable(n.Left) 549 550 // nothing to do 551 case ODOTPTR: 552 fallthrough 553 default: 554 break 555 } 556 } 557 558 func uintptraddr(n *Node) *Node { 559 r := Nod(OADDR, n, nil) 560 r.Bounded = true 561 r = conv(r, Types[TUNSAFEPTR]) 562 r = conv(r, Types[TUINTPTR]) 563 return r 564 } 565 566 func detachexpr(n *Node, init **NodeList) *Node { 567 addr := Nod(OADDR, n, nil) 568 l := temp(Ptrto(n.Type)) 569 as := Nod(OAS, l, addr) 570 typecheck(&as, Etop) 571 walkexpr(&as, init) 572 *init = list(*init, as) 573 ind := Nod(OIND, l, nil) 574 typecheck(&ind, Erv) 575 walkexpr(&ind, init) 576 return ind 577 } 578 579 func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) { 580 if n != nil { 581 f(n, c) 582 } 583 } 584 585 func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) { 586 for ; l != nil; l = l.Next { 587 foreachnode(l.N, f, c) 588 } 589 } 590 591 func foreach(n *Node, f func(*Node, interface{}), c interface{}) { 592 foreachlist(n.Ninit, f, c) 593 foreachnode(n.Left, f, c) 594 foreachnode(n.Right, f, c) 595 foreachlist(n.List, f, c) 596 foreachlist(n.Nbody, f, c) 597 foreachlist(n.Rlist, f, c) 598 } 599 600 func hascallspred(n *Node, c interface{}) { 601 switch n.Op { 602 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER: 603 (*c.(*int))++ 604 } 605 } 606 607 // appendinit is like addinit in subr.go 608 // but appends rather than prepends. 609 func appendinit(np **Node, init *NodeList) { 610 if init == nil { 611 return 612 } 613 614 n := *np 615 switch n.Op { 616 // There may be multiple refs to this node; 617 // introduce OCONVNOP to hold init list. 618 case ONAME, OLITERAL: 619 n = Nod(OCONVNOP, n, nil) 620 621 n.Type = n.Left.Type 622 n.Typecheck = 1 623 *np = n 624 } 625 626 n.Ninit = concat(n.Ninit, init) 627 n.Ullman = UINF 628 }