github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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/internal/src" 9 "fmt" 10 "strings" 11 ) 12 13 // The instrument pass modifies the code tree for instrumentation. 14 // 15 // For flag_race it modifies the function as follows: 16 // 17 // 1. It inserts a call to racefuncenterfp at the beginning of each function. 18 // 2. It inserts a call to racefuncexit at the end of each function. 19 // 3. It inserts a call to raceread before each memory read. 20 // 4. It inserts a call to racewrite before each memory write. 21 // 22 // For flag_msan: 23 // 24 // 1. It inserts a call to msanread before each memory read. 25 // 2. It inserts a call to msanwrite before each memory write. 26 // 27 // The rewriting is not yet complete. Certain nodes are not rewritten 28 // but should be. 29 30 // TODO(dvyukov): do not instrument initialization as writes: 31 // a := make([]int, 10) 32 33 // Do not instrument the following packages at all, 34 // at best instrumentation would cause infinite recursion. 35 var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"} 36 37 // Only insert racefuncenterfp/racefuncexit into the following packages. 38 // Memory accesses in the packages are either uninteresting or will cause false positives. 39 var norace_inst_pkgs = []string{"sync", "sync/atomic"} 40 41 func ispkgin(pkgs []string) bool { 42 if myimportpath != "" { 43 for _, p := range pkgs { 44 if myimportpath == p { 45 return true 46 } 47 } 48 } 49 50 return false 51 } 52 53 func instrument(fn *Node) { 54 if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 { 55 return 56 } 57 58 if !flag_race || !ispkgin(norace_inst_pkgs) { 59 instrumentlist(fn.Nbody, nil) 60 61 // nothing interesting for race detector in fn->enter 62 instrumentlist(fn.Func.Exit, nil) 63 } 64 65 if flag_race { 66 // nodpc is the PC of the caller as extracted by 67 // getcallerpc. We use -widthptr(FP) for x86. 68 // BUG: this will not work on arm. 69 nodpc := *nodfp 70 nodpc.Type = Types[TUINTPTR] 71 nodpc.Xoffset = int64(-Widthptr) 72 nd := mkcall("racefuncenter", nil, nil, &nodpc) 73 fn.Func.Enter.Prepend(nd) 74 nd = mkcall("racefuncexit", nil, nil) 75 fn.Func.Exit.Append(nd) 76 fn.Func.Dcl = append(fn.Func.Dcl, &nodpc) 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 Nodes, init *Nodes) { 90 s := l.Slice() 91 for i := range s { 92 var instr Nodes 93 instrumentnode(&s[i], &instr, 0, 0) 94 if init == nil { 95 s[i].Ninit.AppendNodes(&instr) 96 } else { 97 init.AppendNodes(&instr) 98 } 99 } 100 } 101 102 // walkexpr and walkstmt combined 103 // walks the tree and adds calls to the 104 // instrumentation code to top-level (statement) nodes' init 105 func instrumentnode(np **Node, init *Nodes, wr int, skip int) { 106 n := *np 107 108 if n == nil { 109 return 110 } 111 112 if Debug['w'] > 1 { 113 Dump("instrument-before", n) 114 } 115 setlineno(n) 116 if init == nil { 117 Fatalf("instrument: bad init list") 118 } 119 if init == &n.Ninit { 120 // If init == &n->ninit and n->ninit is non-nil, 121 // instrumentnode might append it to itself. 122 // nil it out and handle it separately before putting it back. 123 l := n.Ninit 124 125 n.Ninit.Set(nil) 126 instrumentlist(l, nil) 127 instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit 128 appendinit(&n, l) 129 *np = n 130 return 131 } 132 133 instrumentlist(n.Ninit, nil) 134 135 switch n.Op { 136 default: 137 Fatalf("instrument: unknown node type %v", n.Op) 138 139 case OAS, OASWB, OAS2FUNC: 140 instrumentnode(&n.Left, init, 1, 0) 141 instrumentnode(&n.Right, init, 0, 0) 142 goto ret 143 144 // can't matter 145 case OCFUNC, OVARKILL, OVARLIVE: 146 goto ret 147 148 case OBLOCK: 149 ls := n.List.Slice() 150 afterCall := false 151 for i := range ls { 152 op := ls[i].Op 153 // Scan past OAS nodes copying results off stack. 154 // Those must not be instrumented, because the 155 // instrumentation calls will smash the results. 156 // The assignments are to temporaries, so they cannot 157 // be involved in races and need not be instrumented. 158 if afterCall && op == OAS && iscallret(ls[i].Right) { 159 continue 160 } 161 instrumentnode(&ls[i], &ls[i].Ninit, 0, 0) 162 afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER) 163 } 164 goto ret 165 166 case ODEFER: 167 instrumentnode(&n.Left, init, 0, 0) 168 goto ret 169 170 case OPROC: 171 instrumentnode(&n.Left, init, 0, 0) 172 goto ret 173 174 case OCALLINTER: 175 instrumentnode(&n.Left, init, 0, 0) 176 goto ret 177 178 // Instrument dst argument of runtime.writebarrier* calls 179 // as we do not instrument runtime code. 180 // typedslicecopy is instrumented in runtime. 181 case OCALLFUNC: 182 instrumentnode(&n.Left, init, 0, 0) 183 goto ret 184 185 case ONOT, 186 OMINUS, 187 OPLUS, 188 OREAL, 189 OIMAG, 190 OCOM: 191 instrumentnode(&n.Left, init, wr, 0) 192 goto ret 193 194 case ODOTINTER: 195 instrumentnode(&n.Left, init, 0, 0) 196 goto ret 197 198 case ODOT: 199 instrumentnode(&n.Left, init, 0, 1) 200 callinstr(&n, init, wr, skip) 201 goto ret 202 203 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND 204 instrumentnode(&n.Left, init, 0, 0) 205 206 callinstr(&n, init, wr, skip) 207 goto ret 208 209 case OIND: // *p 210 instrumentnode(&n.Left, init, 0, 0) 211 212 callinstr(&n, init, wr, skip) 213 goto ret 214 215 case OSPTR, OLEN, OCAP: 216 instrumentnode(&n.Left, init, 0, 0) 217 if n.Left.Type.IsMap() { 218 n1 := nod(OCONVNOP, n.Left, nil) 219 n1.Type = ptrto(Types[TUINT8]) 220 n1 = nod(OIND, n1, nil) 221 n1 = typecheck(n1, Erv) 222 callinstr(&n1, init, 0, skip) 223 } 224 225 goto ret 226 227 case OLSH, 228 ORSH, 229 OAND, 230 OANDNOT, 231 OOR, 232 OXOR, 233 OSUB, 234 OMUL, 235 OHMUL, 236 OEQ, 237 ONE, 238 OLT, 239 OLE, 240 OGE, 241 OGT, 242 OADD, 243 OCOMPLEX: 244 instrumentnode(&n.Left, init, wr, 0) 245 instrumentnode(&n.Right, init, wr, 0) 246 goto ret 247 248 case OANDAND, OOROR: 249 instrumentnode(&n.Left, init, wr, 0) 250 251 // walk has ensured the node has moved to a location where 252 // side effects are safe. 253 // n->right may not be executed, 254 // so instrumentation goes to n->right->ninit, not init. 255 instrumentnode(&n.Right, &n.Right.Ninit, wr, 0) 256 257 goto ret 258 259 case ONAME: 260 callinstr(&n, init, wr, skip) 261 goto ret 262 263 case OCONV: 264 instrumentnode(&n.Left, init, wr, 0) 265 goto ret 266 267 case OCONVNOP: 268 instrumentnode(&n.Left, init, wr, 0) 269 goto ret 270 271 case ODIV, OMOD: 272 instrumentnode(&n.Left, init, wr, 0) 273 instrumentnode(&n.Right, init, wr, 0) 274 goto ret 275 276 case OINDEX: 277 if !n.Left.Type.IsArray() { 278 instrumentnode(&n.Left, init, 0, 0) 279 } else if !islvalue(n.Left) { 280 // index of unaddressable array, like Map[k][i]. 281 instrumentnode(&n.Left, init, wr, 0) 282 283 instrumentnode(&n.Right, init, 0, 0) 284 goto ret 285 } 286 287 instrumentnode(&n.Right, init, 0, 0) 288 if !n.Left.Type.IsString() { 289 callinstr(&n, init, wr, skip) 290 } 291 goto ret 292 293 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR: 294 instrumentnode(&n.Left, init, 0, 0) 295 low, high, max := n.SliceBounds() 296 instrumentnode(&low, init, 0, 0) 297 instrumentnode(&high, init, 0, 0) 298 instrumentnode(&max, init, 0, 0) 299 n.SetSliceBounds(low, high, max) 300 goto ret 301 302 case OADDR: 303 instrumentnode(&n.Left, init, 0, 1) 304 goto ret 305 306 // n->left is Type* which is not interesting. 307 case OEFACE: 308 instrumentnode(&n.Right, init, 0, 0) 309 310 goto ret 311 312 case OITAB, OIDATA: 313 instrumentnode(&n.Left, init, 0, 0) 314 goto ret 315 316 case OSTRARRAYBYTETMP: 317 instrumentnode(&n.Left, init, 0, 0) 318 goto ret 319 320 case OAS2DOTTYPE: 321 instrumentnode(&n.Left, init, 1, 0) 322 instrumentnode(&n.Right, init, 0, 0) 323 goto ret 324 325 case ODOTTYPE, ODOTTYPE2: 326 instrumentnode(&n.Left, init, 0, 0) 327 goto ret 328 329 // should not appear in AST by now 330 case OSEND, 331 ORECV, 332 OCLOSE, 333 ONEW, 334 OXCASE, 335 OXFALL, 336 OCASE, 337 OPANIC, 338 ORECOVER, 339 OCONVIFACE, 340 OCMPIFACE, 341 OMAKECHAN, 342 OMAKEMAP, 343 OMAKESLICE, 344 OCALL, 345 OCOPY, 346 OAPPEND, 347 ORUNESTR, 348 OARRAYBYTESTR, 349 OARRAYRUNESTR, 350 OSTRARRAYBYTE, 351 OSTRARRAYRUNE, 352 OINDEXMAP, 353 // lowered to call 354 OCMPSTR, 355 OADDSTR, 356 OCALLPART, 357 // lowered to PTRLIT 358 OCLOSURE, // lowered to PTRLIT 359 ORANGE, // lowered to ordinary for loop 360 OARRAYLIT, // lowered to assignments 361 OSLICELIT, 362 OMAPLIT, 363 OSTRUCTLIT, 364 OAS2, 365 OAS2RECV, 366 OAS2MAPR, 367 OASOP: 368 yyerror("instrument: %v must be lowered by now", n.Op) 369 370 goto ret 371 372 // impossible nodes: only appear in backend. 373 case ORROTC, OEXTEND: 374 yyerror("instrument: %v cannot exist now", n.Op) 375 goto ret 376 377 case OGETG: 378 yyerror("instrument: OGETG can happen only in runtime which we don't instrument") 379 goto ret 380 381 case OFOR: 382 if n.Left != nil { 383 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0) 384 } 385 if n.Right != nil { 386 instrumentnode(&n.Right, &n.Right.Ninit, 0, 0) 387 } 388 goto ret 389 390 case OIF, OSWITCH: 391 if n.Left != nil { 392 instrumentnode(&n.Left, &n.Left.Ninit, 0, 0) 393 } 394 goto ret 395 396 // just do generic traversal 397 case OCALLMETH, 398 ORETURN, 399 ORETJMP, 400 OSELECT, 401 OEMPTY, 402 OBREAK, 403 OCONTINUE, 404 OFALL, 405 OGOTO, 406 OLABEL: 407 goto ret 408 409 // does not require instrumentation 410 case OPRINT, // don't bother instrumenting it 411 OPRINTN, // don't bother instrumenting it 412 OCHECKNIL, // always followed by a read. 413 OCLOSUREVAR, // immutable pointer to captured variable 414 ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT) 415 OINDREGSP, // 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 n.IsAutoTmp() { 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 *Nodes, wr int, skip int) bool { 464 n := *np 465 466 //fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n", 467 // n, n.Op, n.Type.Etype, 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 == PAUTOHEAP || 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, src.NoXPos) 498 makeaddable(n) 499 var f *Node 500 if flag_msan { 501 name := "msanread" 502 if wr != 0 { 503 name = "msanwrite" 504 } 505 // dowidth may not have been called for PEXTERN. 506 dowidth(t) 507 w := t.Width 508 if w == BADWIDTH { 509 Fatalf("instrument: %v badwidth", t) 510 } 511 f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w)) 512 } else if flag_race && (t.IsStruct() || t.IsArray()) { 513 name := "racereadrange" 514 if wr != 0 { 515 name = "racewriterange" 516 } 517 // dowidth may not have been called for PEXTERN. 518 dowidth(t) 519 w := t.Width 520 if w == BADWIDTH { 521 Fatalf("instrument: %v badwidth", t) 522 } 523 f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w)) 524 } else if flag_race { 525 name := "raceread" 526 if wr != 0 { 527 name = "racewrite" 528 } 529 f = mkcall(name, nil, init, uintptraddr(n)) 530 } 531 532 init.Append(f) 533 return true 534 } 535 536 return false 537 } 538 539 // makeaddable returns a node whose memory location is the 540 // same as n, but which is addressable in the Go language 541 // sense. 542 // This is different from functions like cheapexpr that may make 543 // a copy of their argument. 544 func makeaddable(n *Node) { 545 // The arguments to uintptraddr technically have an address but 546 // may not be addressable in the Go sense: for example, in the case 547 // of T(v).Field where T is a struct type and v is 548 // an addressable value. 549 switch n.Op { 550 case OINDEX: 551 if n.Left.Type.IsArray() { 552 makeaddable(n.Left) 553 } 554 555 // Turn T(v).Field into v.Field 556 case ODOT, OXDOT: 557 if n.Left.Op == OCONVNOP { 558 n.Left = n.Left.Left 559 } 560 makeaddable(n.Left) 561 562 // nothing to do 563 case ODOTPTR: 564 fallthrough 565 default: 566 break 567 } 568 } 569 570 func uintptraddr(n *Node) *Node { 571 r := nod(OADDR, n, nil) 572 r.Bounded = true 573 r = conv(r, Types[TUNSAFEPTR]) 574 r = conv(r, Types[TUINTPTR]) 575 return r 576 } 577 578 func detachexpr(n *Node, init *Nodes) *Node { 579 addr := nod(OADDR, n, nil) 580 l := temp(ptrto(n.Type)) 581 as := nod(OAS, l, addr) 582 as = typecheck(as, Etop) 583 as = walkexpr(as, init) 584 init.Append(as) 585 ind := nod(OIND, l, nil) 586 ind = typecheck(ind, Erv) 587 ind = walkexpr(ind, init) 588 return ind 589 } 590 591 func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) { 592 if n != nil { 593 f(n, c) 594 } 595 } 596 597 func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) { 598 for _, n := range l.Slice() { 599 foreachnode(n, f, c) 600 } 601 } 602 603 func foreach(n *Node, f func(*Node, interface{}), c interface{}) { 604 foreachlist(n.Ninit, f, c) 605 foreachnode(n.Left, f, c) 606 foreachnode(n.Right, f, c) 607 foreachlist(n.List, f, c) 608 foreachlist(n.Nbody, f, c) 609 foreachlist(n.Rlist, f, c) 610 } 611 612 func hascallspred(n *Node, c interface{}) { 613 switch n.Op { 614 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER: 615 (*c.(*int))++ 616 } 617 } 618 619 // appendinit is like addinit in subr.go 620 // but appends rather than prepends. 621 func appendinit(np **Node, init Nodes) { 622 if init.Len() == 0 { 623 return 624 } 625 626 n := *np 627 switch n.Op { 628 // There may be multiple refs to this node; 629 // introduce OCONVNOP to hold init list. 630 case ONAME, OLITERAL: 631 n = nod(OCONVNOP, n, nil) 632 633 n.Type = n.Left.Type 634 n.Typecheck = 1 635 *np = n 636 } 637 638 n.Ninit.AppendNodes(&init) 639 n.Ullman = UINF 640 }