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.
12 // The racewalk pass modifies the code tree for the function as follows:
14 // 1. It inserts a call to racefuncenterfp at the beginning of each function.
15 // 2. It inserts a call to racefuncexit at the end of each function.
16 // 3. It inserts a call to raceread before each memory read.
17 // 4. It inserts a call to racewrite before each memory write.
19 // The rewriting is not yet complete. Certain nodes are not rewritten
22 // TODO(dvyukov): do not instrument initialization as writes:
23 // a := make([]int, 10)
25 // Do not instrument the following packages at all,
26 // at best instrumentation would cause infinite recursion.
27 var omit_pkgs = []string{"runtime", "runtime/race"}
29 // Only insert racefuncenterfp/racefuncexit into the following packages.
30 // Memory accesses in the packages are either uninteresting or will cause false positives.
31 var noinst_pkgs = []string{"sync", "sync/atomic"}
33 func ispkgin(pkgs []string) bool {
34 if myimportpath != "" {
35 for _, p := range pkgs {
36 if myimportpath == p {
45 // TODO(rsc): Remove. Put //go:norace on forkAndExecInChild instead.
46 func isforkfunc(fn *Node) bool {
47 // Special case for syscall.forkAndExecInChild.
48 // In the child, this function must not acquire any locks, because
49 // they might have been locked at the time of the fork. This means
50 // no rescheduling, no malloc calls, and no new stack segments.
51 // Race instrumentation does all of the above.
52 return myimportpath != "" && myimportpath == "syscall" && fn.Func.Nname.Sym.Name == "forkAndExecInChild"
55 func racewalk(fn *Node) {
56 if ispkgin(omit_pkgs) || isforkfunc(fn) || fn.Func.Norace {
60 if !ispkgin(noinst_pkgs) {
61 racewalklist(fn.Nbody, nil)
63 // nothing interesting for race detector in fn->enter
64 racewalklist(fn.Func.Exit, nil)
67 nd := mkcall("racefuncenterfp", nil, nil, Nod(OADDR, nodfp, nil))
68 fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
69 nd = mkcall("racefuncexit", nil, nil)
70 fn.Func.Exit = list(fn.Func.Exit, nd)
73 s := fmt.Sprintf("after racewalk %v", fn.Func.Nname.Sym)
75 s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
76 dumplist(s, fn.Func.Enter)
77 s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
78 dumplist(s, fn.Func.Exit)
82 func racewalklist(l *NodeList, init **NodeList) {
85 for ; l != nil; l = l.Next {
87 racewalknode(&l.N, &instr, 0, 0)
89 l.N.Ninit = concat(l.N.Ninit, instr)
91 *init = concat(*init, instr)
96 // walkexpr and walkstmt combined
97 // walks the tree and adds calls to the
98 // instrumentation code to top-level (statement) nodes' init
99 func racewalknode(np **Node, init **NodeList, wr int, skip int) {
107 Dump("racewalk-before", n)
111 Fatalf("racewalk: bad init list")
113 if init == &n.Ninit {
114 // If init == &n->ninit and n->ninit is non-nil,
115 // racewalknode might append it to itself.
116 // nil it out and handle it separately before putting it back.
121 racewalknode(&n, &l, wr, skip) // recurse with nil n->ninit
127 racewalklist(n.Ninit, nil)
131 Fatalf("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
133 case OAS, OASWB, OAS2FUNC:
134 racewalknode(&n.Left, init, 1, 0)
135 racewalknode(&n.Right, init, 0, 0)
139 case OCFUNC, OVARKILL:
144 for l := n.List; l != nil; l = l.Next {
146 case OCALLFUNC, OCALLMETH, OCALLINTER:
147 racewalknode(&l.N, &out, 0, 0)
149 // Scan past OAS nodes copying results off stack.
150 // Those must not be instrumented, because the
151 // instrumentation calls will smash the results.
152 // The assignments are to temporaries, so they cannot
153 // be involved in races and need not be instrumented.
154 for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
159 racewalknode(&l.N, &out, 0, 0)
167 racewalknode(&n.Left, init, 0, 0)
171 racewalknode(&n.Left, init, 0, 0)
175 racewalknode(&n.Left, init, 0, 0)
178 // Instrument dst argument of runtime.writebarrier* calls
179 // as we do not instrument runtime code.
180 // typedslicecopy is instrumented in runtime.
182 racewalknode(&n.Left, init, 0, 0)
192 racewalknode(&n.Left, init, wr, 0)
196 racewalknode(&n.Left, init, 0, 0)
200 racewalknode(&n.Left, init, 0, 1)
201 callinstr(&n, init, wr, skip)
204 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
205 racewalknode(&n.Left, init, 0, 0)
207 callinstr(&n, init, wr, skip)
211 racewalknode(&n.Left, init, 0, 0)
213 callinstr(&n, init, wr, skip)
216 case OSPTR, OLEN, OCAP:
217 racewalknode(&n.Left, init, 0, 0)
218 if Istype(n.Left.Type, TMAP) {
219 n1 := Nod(OCONVNOP, n.Left, nil)
220 n1.Type = Ptrto(Types[TUINT8])
221 n1 = Nod(OIND, n1, nil)
223 callinstr(&n1, init, 0, skip)
246 racewalknode(&n.Left, init, wr, 0)
247 racewalknode(&n.Right, init, wr, 0)
251 racewalknode(&n.Left, init, wr, 0)
253 // walk has ensured the node has moved to a location where
254 // side effects are safe.
255 // n->right may not be executed,
256 // so instrumentation goes to n->right->ninit, not init.
257 racewalknode(&n.Right, &n.Right.Ninit, wr, 0)
262 callinstr(&n, init, wr, skip)
266 racewalknode(&n.Left, init, wr, 0)
270 racewalknode(&n.Left, init, wr, 0)
274 racewalknode(&n.Left, init, wr, 0)
275 racewalknode(&n.Right, init, wr, 0)
279 if !Isfixedarray(n.Left.Type) {
280 racewalknode(&n.Left, init, 0, 0)
281 } else if !islvalue(n.Left) {
282 // index of unaddressable array, like Map[k][i].
283 racewalknode(&n.Left, init, wr, 0)
285 racewalknode(&n.Right, init, 0, 0)
289 racewalknode(&n.Right, init, 0, 0)
290 if n.Left.Type.Etype != TSTRING {
291 callinstr(&n, init, wr, skip)
295 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
296 racewalknode(&n.Left, init, 0, 0)
297 racewalknode(&n.Right, init, 0, 0)
301 racewalknode(&n.Left, init, 0, 0)
302 racewalknode(&n.Right, init, 0, 0)
306 racewalknode(&n.Left, init, 0, 1)
309 // n->left is Type* which is not interesting.
311 racewalknode(&n.Right, init, 0, 0)
316 racewalknode(&n.Left, init, 0, 0)
319 // should not appear in AST by now
351 OCLOSURE, // lowered to PTRLIT
352 ORANGE, // lowered to ordinary for loop
353 OARRAYLIT, // lowered to assignments
360 Yyerror("racewalk: %v must be lowered by now", Oconv(int(n.Op), 0))
364 // impossible nodes: only appear in backend.
365 case ORROTC, OEXTEND:
366 Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
370 Yyerror("racewalk: OGETG can happen only in runtime which we don't instrument")
375 racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
378 racewalknode(&n.Right, &n.Right.Ninit, 0, 0)
384 racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
388 // just do generic traversal
401 // does not require instrumentation
402 case OPRINT, // don't bother instrumenting it
403 OPRINTN, // don't bother instrumenting it
404 OCHECKNIL, // always followed by a read.
405 OPARAM, // it appears only in fn->exit to copy heap params back
406 OCLOSUREVAR, // immutable pointer to captured variable
407 ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
408 OINDREG, // at this stage, only n(SP) nodes from nodarg
409 ODCL, // declarations (without value) cannot be races
415 OTYPESW: // ignored by code generation, do not instrument.
420 if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
421 racewalklist(n.List, init)
423 racewalklist(n.Nbody, nil)
424 racewalklist(n.Rlist, nil)
428 func isartificial(n *Node) bool {
429 // compiler-emitted artificial things that we do not want to instrument,
430 // cant' possibly participate in a data race.
431 if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
432 if n.Sym.Name == "_" {
436 // autotmp's are always local
437 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
441 // statictmp's are read-only
442 if strings.HasPrefix(n.Sym.Name, "statictmp_") {
446 // go.itab is accessed only by the compiler and runtime (assume safe)
447 if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
455 func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
458 //print("callinstr for %+N [ %O ] etype=%E class=%d\n",
459 // n, n->op, n->type ? n->type->etype : -1, n->class);
461 if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
471 // it skips e.g. stores to ... parameter array
477 // BUG: we _may_ want to instrument PAUTO sometimes
478 // e.g. if we've got a local variable/method receiver
479 // that has got a pointer inside. Whether it points to
480 // the heap or not is impossible to know at compile time
481 if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
483 foreach(n, hascallspred, &hascalls)
485 n = detachexpr(n, init)
492 if t.Etype == TSTRUCT || Isfixedarray(t) {
493 name := "racereadrange"
495 name = "racewriterange"
497 f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
503 f = mkcall(name, nil, init, uintptraddr(n))
506 *init = list(*init, f)
513 // makeaddable returns a node whose memory location is the
514 // same as n, but which is addressable in the Go language
516 // This is different from functions like cheapexpr that may make
517 // a copy of their argument.
518 func makeaddable(n *Node) {
519 // The arguments to uintptraddr technically have an address but
520 // may not be addressable in the Go sense: for example, in the case
521 // of T(v).Field where T is a struct type and v is
522 // an addressable value.
525 if Isfixedarray(n.Left.Type) {
529 // Turn T(v).Field into v.Field
531 if n.Left.Op == OCONVNOP {
544 func uintptraddr(n *Node) *Node {
545 r := Nod(OADDR, n, nil)
547 r = conv(r, Types[TUNSAFEPTR])
548 r = conv(r, Types[TUINTPTR])
552 func detachexpr(n *Node, init **NodeList) *Node {
553 addr := Nod(OADDR, n, nil)
554 l := temp(Ptrto(n.Type))
555 as := Nod(OAS, l, addr)
558 *init = list(*init, as)
559 ind := Nod(OIND, l, nil)
565 func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
571 func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
572 for ; l != nil; l = l.Next {
573 foreachnode(l.N, f, c)
577 func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
578 foreachlist(n.Ninit, f, c)
579 foreachnode(n.Left, f, c)
580 foreachnode(n.Right, f, c)
581 foreachlist(n.List, f, c)
582 foreachlist(n.Nbody, f, c)
583 foreachlist(n.Rlist, f, c)
586 func hascallspred(n *Node, c interface{}) {
588 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
593 // appendinit is like addinit in subr.go
594 // but appends rather than prepends.
595 func appendinit(np **Node, init *NodeList) {
602 // There may be multiple refs to this node;
603 // introduce OCONVNOP to hold init list.
604 case ONAME, OLITERAL:
605 n = Nod(OCONVNOP, n, nil)
612 n.Ninit = concat(n.Ninit, init)