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