Home | History | Annotate | Download | only in gc
      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 racewalk pass modifies the code tree for the function as follows:
     13 //
     14 // 1. It inserts a call to racefuncenter 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.
     18 //
     19 // The rewriting is not yet complete. Certain nodes are not rewritten
     20 // but should be.
     21 
     22 // TODO(dvyukov): do not instrument initialization as writes:
     23 // a := make([]int, 10)
     24 
     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"}
     28 
     29 // Only insert racefuncenter/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"}
     32 
     33 func ispkgin(pkgs []string) bool {
     34 	if myimportpath != "" {
     35 		for i := 0; i < len(pkgs); i++ {
     36 			if myimportpath == pkgs[i] {
     37 				return true
     38 			}
     39 		}
     40 	}
     41 
     42 	return false
     43 }
     44 
     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"
     53 }
     54 
     55 func racewalk(fn *Node) {
     56 	if ispkgin(omit_pkgs) || isforkfunc(fn) || fn.Func.Norace {
     57 		return
     58 	}
     59 
     60 	if !ispkgin(noinst_pkgs) {
     61 		racewalklist(fn.Nbody, nil)
     62 
     63 		// nothing interesting for race detector in fn->enter
     64 		racewalklist(fn.Func.Exit, nil)
     65 	}
     66 
     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 := Nod(OXXX, nil, nil)
     71 
     72 	*nodpc = *nodfp
     73 	nodpc.Type = Types[TUINTPTR]
     74 	nodpc.Xoffset = int64(-Widthptr)
     75 	nd := mkcall("racefuncenter", nil, nil, nodpc)
     76 	fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
     77 	nd = mkcall("racefuncexit", nil, nil)
     78 	fn.Func.Exit = list(fn.Func.Exit, nd)
     79 
     80 	if Debug['W'] != 0 {
     81 		s := fmt.Sprintf("after racewalk %v", fn.Func.Nname.Sym)
     82 		dumplist(s, fn.Nbody)
     83 		s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
     84 		dumplist(s, fn.Func.Enter)
     85 		s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
     86 		dumplist(s, fn.Func.Exit)
     87 	}
     88 }
     89 
     90 func racewalklist(l *NodeList, init **NodeList) {
     91 	var instr *NodeList
     92 
     93 	for ; l != nil; l = l.Next {
     94 		instr = nil
     95 		racewalknode(&l.N, &instr, 0, 0)
     96 		if init == nil {
     97 			l.N.Ninit = concat(l.N.Ninit, instr)
     98 		} else {
     99 			*init = concat(*init, instr)
    100 		}
    101 	}
    102 }
    103 
    104 // walkexpr and walkstmt combined
    105 // walks the tree and adds calls to the
    106 // instrumentation code to top-level (statement) nodes' init
    107 func racewalknode(np **Node, init **NodeList, wr int, skip int) {
    108 	n := *np
    109 
    110 	if n == nil {
    111 		return
    112 	}
    113 
    114 	if Debug['w'] > 1 {
    115 		Dump("racewalk-before", n)
    116 	}
    117 	setlineno(n)
    118 	if init == nil {
    119 		Fatal("racewalk: bad init list")
    120 	}
    121 	if init == &n.Ninit {
    122 		// If init == &n->ninit and n->ninit is non-nil,
    123 		// racewalknode might append it to itself.
    124 		// nil it out and handle it separately before putting it back.
    125 		l := n.Ninit
    126 
    127 		n.Ninit = nil
    128 		racewalklist(l, nil)
    129 		racewalknode(&n, &l, wr, skip) // recurse with nil n->ninit
    130 		appendinit(&n, l)
    131 		*np = n
    132 		return
    133 	}
    134 
    135 	racewalklist(n.Ninit, nil)
    136 
    137 	switch n.Op {
    138 	default:
    139 		Fatal("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
    140 
    141 	case OAS, OASWB, OAS2FUNC:
    142 		racewalknode(&n.Left, init, 1, 0)
    143 		racewalknode(&n.Right, init, 0, 0)
    144 		goto ret
    145 
    146 		// can't matter
    147 	case OCFUNC, OVARKILL:
    148 		goto ret
    149 
    150 	case OBLOCK:
    151 		var out *NodeList
    152 		for l := n.List; l != nil; l = l.Next {
    153 			switch l.N.Op {
    154 			case OCALLFUNC, OCALLMETH, OCALLINTER:
    155 				racewalknode(&l.N, &out, 0, 0)
    156 				out = list(out, l.N)
    157 				// Scan past OAS nodes copying results off stack.
    158 				// Those must not be instrumented, because the
    159 				// instrumentation calls will smash the results.
    160 				// The assignments are to temporaries, so they cannot
    161 				// be involved in races and need not be instrumented.
    162 				for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
    163 					l = l.Next
    164 					out = list(out, l.N)
    165 				}
    166 			default:
    167 				racewalknode(&l.N, &out, 0, 0)
    168 				out = list(out, l.N)
    169 			}
    170 		}
    171 		n.List = out
    172 		goto ret
    173 
    174 	case ODEFER:
    175 		racewalknode(&n.Left, init, 0, 0)
    176 		goto ret
    177 
    178 	case OPROC:
    179 		racewalknode(&n.Left, init, 0, 0)
    180 		goto ret
    181 
    182 	case OCALLINTER:
    183 		racewalknode(&n.Left, init, 0, 0)
    184 		goto ret
    185 
    186 		// Instrument dst argument of runtime.writebarrier* calls
    187 	// as we do not instrument runtime code.
    188 	// typedslicecopy is instrumented in runtime.
    189 	case OCALLFUNC:
    190 		racewalknode(&n.Left, init, 0, 0)
    191 		goto ret
    192 
    193 	case ONOT,
    194 		OMINUS,
    195 		OPLUS,
    196 		OREAL,
    197 		OIMAG,
    198 		OCOM,
    199 		OSQRT:
    200 		racewalknode(&n.Left, init, wr, 0)
    201 		goto ret
    202 
    203 	case ODOTINTER:
    204 		racewalknode(&n.Left, init, 0, 0)
    205 		goto ret
    206 
    207 	case ODOT:
    208 		racewalknode(&n.Left, init, 0, 1)
    209 		callinstr(&n, init, wr, skip)
    210 		goto ret
    211 
    212 	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
    213 		racewalknode(&n.Left, init, 0, 0)
    214 
    215 		callinstr(&n, init, wr, skip)
    216 		goto ret
    217 
    218 	case OIND: // *p
    219 		racewalknode(&n.Left, init, 0, 0)
    220 
    221 		callinstr(&n, init, wr, skip)
    222 		goto ret
    223 
    224 	case OSPTR, OLEN, OCAP:
    225 		racewalknode(&n.Left, init, 0, 0)
    226 		if Istype(n.Left.Type, TMAP) {
    227 			n1 := Nod(OCONVNOP, n.Left, nil)
    228 			n1.Type = Ptrto(Types[TUINT8])
    229 			n1 = Nod(OIND, n1, nil)
    230 			typecheck(&n1, Erv)
    231 			callinstr(&n1, init, 0, skip)
    232 		}
    233 
    234 		goto ret
    235 
    236 	case OLSH,
    237 		ORSH,
    238 		OLROT,
    239 		OAND,
    240 		OANDNOT,
    241 		OOR,
    242 		OXOR,
    243 		OSUB,
    244 		OMUL,
    245 		OHMUL,
    246 		OEQ,
    247 		ONE,
    248 		OLT,
    249 		OLE,
    250 		OGE,
    251 		OGT,
    252 		OADD,
    253 		OCOMPLEX:
    254 		racewalknode(&n.Left, init, wr, 0)
    255 		racewalknode(&n.Right, init, wr, 0)
    256 		goto ret
    257 
    258 	case OANDAND, OOROR:
    259 		racewalknode(&n.Left, init, wr, 0)
    260 
    261 		// walk has ensured the node has moved to a location where
    262 		// side effects are safe.
    263 		// n->right may not be executed,
    264 		// so instrumentation goes to n->right->ninit, not init.
    265 		racewalknode(&n.Right, &n.Right.Ninit, wr, 0)
    266 
    267 		goto ret
    268 
    269 	case ONAME:
    270 		callinstr(&n, init, wr, skip)
    271 		goto ret
    272 
    273 	case OCONV:
    274 		racewalknode(&n.Left, init, wr, 0)
    275 		goto ret
    276 
    277 	case OCONVNOP:
    278 		racewalknode(&n.Left, init, wr, 0)
    279 		goto ret
    280 
    281 	case ODIV, OMOD:
    282 		racewalknode(&n.Left, init, wr, 0)
    283 		racewalknode(&n.Right, init, wr, 0)
    284 		goto ret
    285 
    286 	case OINDEX:
    287 		if !Isfixedarray(n.Left.Type) {
    288 			racewalknode(&n.Left, init, 0, 0)
    289 		} else if !islvalue(n.Left) {
    290 			// index of unaddressable array, like Map[k][i].
    291 			racewalknode(&n.Left, init, wr, 0)
    292 
    293 			racewalknode(&n.Right, init, 0, 0)
    294 			goto ret
    295 		}
    296 
    297 		racewalknode(&n.Right, init, 0, 0)
    298 		if n.Left.Type.Etype != TSTRING {
    299 			callinstr(&n, init, wr, skip)
    300 		}
    301 		goto ret
    302 
    303 	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
    304 		racewalknode(&n.Left, init, 0, 0)
    305 		racewalknode(&n.Right, init, 0, 0)
    306 		goto ret
    307 
    308 	case OKEY:
    309 		racewalknode(&n.Left, init, 0, 0)
    310 		racewalknode(&n.Right, init, 0, 0)
    311 		goto ret
    312 
    313 	case OADDR:
    314 		racewalknode(&n.Left, init, 0, 1)
    315 		goto ret
    316 
    317 		// n->left is Type* which is not interesting.
    318 	case OEFACE:
    319 		racewalknode(&n.Right, init, 0, 0)
    320 
    321 		goto ret
    322 
    323 	case OITAB:
    324 		racewalknode(&n.Left, init, 0, 0)
    325 		goto ret
    326 
    327 		// should not appear in AST by now
    328 	case OSEND,
    329 		ORECV,
    330 		OCLOSE,
    331 		ONEW,
    332 		OXCASE,
    333 		OXFALL,
    334 		OCASE,
    335 		OPANIC,
    336 		ORECOVER,
    337 		OCONVIFACE,
    338 		OCMPIFACE,
    339 		OMAKECHAN,
    340 		OMAKEMAP,
    341 		OMAKESLICE,
    342 		OCALL,
    343 		OCOPY,
    344 		OAPPEND,
    345 		ORUNESTR,
    346 		OARRAYBYTESTR,
    347 		OARRAYRUNESTR,
    348 		OSTRARRAYBYTE,
    349 		OSTRARRAYRUNE,
    350 		OINDEXMAP,
    351 		// lowered to call
    352 		OCMPSTR,
    353 		OADDSTR,
    354 		ODOTTYPE,
    355 		ODOTTYPE2,
    356 		OAS2DOTTYPE,
    357 		OCALLPART,
    358 		// lowered to PTRLIT
    359 		OCLOSURE,  // lowered to PTRLIT
    360 		ORANGE,    // lowered to ordinary for loop
    361 		OARRAYLIT, // lowered to assignments
    362 		OMAPLIT,
    363 		OSTRUCTLIT,
    364 		OAS2,
    365 		OAS2RECV,
    366 		OAS2MAPR,
    367 		OASOP:
    368 		Yyerror("racewalk: %v must be lowered by now", Oconv(int(n.Op), 0))
    369 
    370 		goto ret
    371 
    372 		// impossible nodes: only appear in backend.
    373 	case ORROTC, OEXTEND:
    374 		Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
    375 		goto ret
    376 
    377 	case OGETG:
    378 		Yyerror("racewalk: OGETG can happen only in runtime which we don't instrument")
    379 		goto ret
    380 
    381 	case OFOR:
    382 		if n.Left != nil {
    383 			racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
    384 		}
    385 		if n.Right != nil {
    386 			racewalknode(&n.Right, &n.Right.Ninit, 0, 0)
    387 		}
    388 		goto ret
    389 
    390 	case OIF, OSWITCH:
    391 		if n.Left != nil {
    392 			racewalknode(&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 		OPARAM,      // it appears only in fn->exit to copy heap params back
    414 		OCLOSUREVAR, // immutable pointer to captured variable
    415 		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
    416 		OINDREG,     // at this stage, only n(SP) nodes from nodarg
    417 		ODCL,        // declarations (without value) cannot be races
    418 		ODCLCONST,
    419 		ODCLTYPE,
    420 		OTYPE,
    421 		ONONAME,
    422 		OLITERAL,
    423 		OTYPESW: // ignored by code generation, do not instrument.
    424 		goto ret
    425 	}
    426 
    427 ret:
    428 	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
    429 		racewalklist(n.List, init)
    430 	}
    431 	racewalklist(n.Nbody, nil)
    432 	racewalklist(n.Rlist, nil)
    433 	*np = n
    434 }
    435 
    436 func isartificial(n *Node) bool {
    437 	// compiler-emitted artificial things that we do not want to instrument,
    438 	// cant' possibly participate in a data race.
    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 t.Etype == TSTRUCT || Isfixedarray(t) {
    501 			name := "racereadrange"
    502 			if wr != 0 {
    503 				name = "racewriterange"
    504 			}
    505 			f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
    506 		} else {
    507 			name := "raceread"
    508 			if wr != 0 {
    509 				name = "racewrite"
    510 			}
    511 			f = mkcall(name, nil, init, uintptraddr(n))
    512 		}
    513 
    514 		*init = list(*init, f)
    515 		return true
    516 	}
    517 
    518 	return false
    519 }
    520 
    521 // makeaddable returns a node whose memory location is the
    522 // same as n, but which is addressable in the Go language
    523 // sense.
    524 // This is different from functions like cheapexpr that may make
    525 // a copy of their argument.
    526 func makeaddable(n *Node) {
    527 	// The arguments to uintptraddr technically have an address but
    528 	// may not be addressable in the Go sense: for example, in the case
    529 	// of T(v).Field where T is a struct type and v is
    530 	// an addressable value.
    531 	switch n.Op {
    532 	case OINDEX:
    533 		if Isfixedarray(n.Left.Type) {
    534 			makeaddable(n.Left)
    535 		}
    536 
    537 		// Turn T(v).Field into v.Field
    538 	case ODOT, OXDOT:
    539 		if n.Left.Op == OCONVNOP {
    540 			n.Left = n.Left.Left
    541 		}
    542 		makeaddable(n.Left)
    543 
    544 		// nothing to do
    545 	case ODOTPTR:
    546 		fallthrough
    547 	default:
    548 		break
    549 	}
    550 }
    551 
    552 func uintptraddr(n *Node) *Node {
    553 	r := Nod(OADDR, n, nil)
    554 	r.Bounded = true
    555 	r = conv(r, Types[TUNSAFEPTR])
    556 	r = conv(r, Types[TUINTPTR])
    557 	return r
    558 }
    559 
    560 func detachexpr(n *Node, init **NodeList) *Node {
    561 	addr := Nod(OADDR, n, nil)
    562 	l := temp(Ptrto(n.Type))
    563 	as := Nod(OAS, l, addr)
    564 	typecheck(&as, Etop)
    565 	walkexpr(&as, init)
    566 	*init = list(*init, as)
    567 	ind := Nod(OIND, l, nil)
    568 	typecheck(&ind, Erv)
    569 	walkexpr(&ind, init)
    570 	return ind
    571 }
    572 
    573 func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
    574 	if n != nil {
    575 		f(n, c)
    576 	}
    577 }
    578 
    579 func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
    580 	for ; l != nil; l = l.Next {
    581 		foreachnode(l.N, f, c)
    582 	}
    583 }
    584 
    585 func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
    586 	foreachlist(n.Ninit, f, c)
    587 	foreachnode(n.Left, f, c)
    588 	foreachnode(n.Right, f, c)
    589 	foreachlist(n.List, f, c)
    590 	foreachlist(n.Nbody, f, c)
    591 	foreachlist(n.Rlist, f, c)
    592 }
    593 
    594 func hascallspred(n *Node, c interface{}) {
    595 	switch n.Op {
    596 	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
    597 		(*c.(*int))++
    598 	}
    599 }
    600 
    601 // appendinit is like addinit in subr.go
    602 // but appends rather than prepends.
    603 func appendinit(np **Node, init *NodeList) {
    604 	if init == nil {
    605 		return
    606 	}
    607 
    608 	n := *np
    609 	switch n.Op {
    610 	// There may be multiple refs to this node;
    611 	// introduce OCONVNOP to hold init list.
    612 	case ONAME, OLITERAL:
    613 		n = Nod(OCONVNOP, n, nil)
    614 
    615 		n.Type = n.Left.Type
    616 		n.Typecheck = 1
    617 		*np = n
    618 	}
    619 
    620 	n.Ninit = concat(n.Ninit, init)
    621 	n.Ullman = UINF
    622 }
    623