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 	"cmd/compile/internal/types"
      9 	"cmd/internal/src"
     10 	"fmt"
     11 	"strings"
     12 )
     13 
     14 // The instrument pass modifies the code tree for instrumentation.
     15 //
     16 // For flag_race it modifies the function as follows:
     17 //
     18 // 1. It inserts a call to racefuncenterfp at the beginning of each function.
     19 // 2. It inserts a call to racefuncexit at the end of each function.
     20 // 3. It inserts a call to raceread before each memory read.
     21 // 4. It inserts a call to racewrite before each memory write.
     22 //
     23 // For flag_msan:
     24 //
     25 // 1. It inserts a call to msanread before each memory read.
     26 // 2. It inserts a call to msanwrite before each memory write.
     27 //
     28 // The rewriting is not yet complete. Certain nodes are not rewritten
     29 // but should be.
     30 
     31 // TODO(dvyukov): do not instrument initialization as writes:
     32 // a := make([]int, 10)
     33 
     34 // Do not instrument the following packages at all,
     35 // at best instrumentation would cause infinite recursion.
     36 var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"}
     37 
     38 // Only insert racefuncenterfp/racefuncexit into the following packages.
     39 // Memory accesses in the packages are either uninteresting or will cause false positives.
     40 var norace_inst_pkgs = []string{"sync", "sync/atomic"}
     41 
     42 func ispkgin(pkgs []string) bool {
     43 	if myimportpath != "" {
     44 		for _, p := range pkgs {
     45 			if myimportpath == p {
     46 				return true
     47 			}
     48 		}
     49 	}
     50 
     51 	return false
     52 }
     53 
     54 func instrument(fn *Node) {
     55 	if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 {
     56 		return
     57 	}
     58 
     59 	if !flag_race || !ispkgin(norace_inst_pkgs) {
     60 		instrumentlist(fn.Nbody, nil)
     61 
     62 		// nothing interesting for race detector in fn->enter
     63 		instrumentlist(fn.Func.Exit, nil)
     64 	}
     65 
     66 	if flag_race {
     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 := *nodfp
     71 		nodpc.Type = types.Types[TUINTPTR]
     72 		nodpc.Xoffset = int64(-Widthptr)
     73 		savedLineno := lineno
     74 		lineno = src.NoXPos
     75 		nd := mkcall("racefuncenter", nil, nil, &nodpc)
     76 
     77 		fn.Func.Enter.Prepend(nd)
     78 		nd = mkcall("racefuncexit", nil, nil)
     79 		fn.Func.Exit.Append(nd)
     80 		fn.Func.Dcl = append(fn.Func.Dcl, &nodpc)
     81 		lineno = savedLineno
     82 	}
     83 
     84 	if Debug['W'] != 0 {
     85 		s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
     86 		dumplist(s, fn.Nbody)
     87 		s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
     88 		dumplist(s, fn.Func.Enter)
     89 		s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
     90 		dumplist(s, fn.Func.Exit)
     91 	}
     92 }
     93 
     94 func instrumentlist(l Nodes, init *Nodes) {
     95 	s := l.Slice()
     96 	for i := range s {
     97 		var instr Nodes
     98 		instrumentnode(&s[i], &instr, 0, 0)
     99 		if init == nil {
    100 			s[i].Ninit.AppendNodes(&instr)
    101 		} else {
    102 			init.AppendNodes(&instr)
    103 		}
    104 	}
    105 }
    106 
    107 // walkexpr and walkstmt combined
    108 // walks the tree and adds calls to the
    109 // instrumentation code to top-level (statement) nodes' init
    110 func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
    111 	n := *np
    112 
    113 	if n == nil {
    114 		return
    115 	}
    116 
    117 	if Debug['w'] > 1 {
    118 		Dump("instrument-before", n)
    119 	}
    120 	setlineno(n)
    121 	if init == nil {
    122 		Fatalf("instrument: bad init list")
    123 	}
    124 	if init == &n.Ninit {
    125 		// If init == &n->ninit and n->ninit is non-nil,
    126 		// instrumentnode might append it to itself.
    127 		// nil it out and handle it separately before putting it back.
    128 		l := n.Ninit
    129 
    130 		n.Ninit.Set(nil)
    131 		instrumentlist(l, nil)
    132 		instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit
    133 		appendinit(&n, l)
    134 		*np = n
    135 		return
    136 	}
    137 
    138 	instrumentlist(n.Ninit, nil)
    139 
    140 	switch n.Op {
    141 	default:
    142 		Fatalf("instrument: unknown node type %v", n.Op)
    143 
    144 	case OAS, OAS2FUNC:
    145 		instrumentnode(&n.Left, init, 1, 0)
    146 		instrumentnode(&n.Right, init, 0, 0)
    147 
    148 		// can't matter
    149 	case OCFUNC, OVARKILL, OVARLIVE:
    150 
    151 	case OBLOCK:
    152 		ls := n.List.Slice()
    153 		afterCall := false
    154 		for i := range ls {
    155 			op := ls[i].Op
    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 			if afterCall && op == OAS && iscallret(ls[i].Right) {
    162 				continue
    163 			}
    164 			instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
    165 			afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER)
    166 		}
    167 
    168 	case ODEFER:
    169 		instrumentnode(&n.Left, init, 0, 0)
    170 
    171 	case OPROC:
    172 		instrumentnode(&n.Left, init, 0, 0)
    173 
    174 	case OCALLINTER:
    175 		instrumentnode(&n.Left, init, 0, 0)
    176 
    177 	case OCALLFUNC:
    178 		// Note that runtime.typedslicecopy is the only
    179 		// assignment-like function call in the AST at this
    180 		// point (between walk and SSA); since we don't
    181 		// instrument it here, typedslicecopy is manually
    182 		// instrumented in runtime. Calls to the write barrier
    183 		// and typedmemmove are created later by SSA, so those
    184 		// still appear as OAS nodes at this point.
    185 		instrumentnode(&n.Left, init, 0, 0)
    186 
    187 	case ONOT,
    188 		OMINUS,
    189 		OPLUS,
    190 		OREAL,
    191 		OIMAG,
    192 		OCOM:
    193 		instrumentnode(&n.Left, init, wr, 0)
    194 
    195 	case ODOTINTER:
    196 		instrumentnode(&n.Left, init, 0, 0)
    197 
    198 	case ODOT:
    199 		instrumentnode(&n.Left, init, 0, 1)
    200 		callinstr(&n, init, wr, skip)
    201 
    202 	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
    203 		instrumentnode(&n.Left, init, 0, 0)
    204 
    205 		callinstr(&n, init, wr, skip)
    206 
    207 	case OIND: // *p
    208 		instrumentnode(&n.Left, init, 0, 0)
    209 
    210 		callinstr(&n, init, wr, skip)
    211 
    212 	case OSPTR, OLEN, OCAP:
    213 		instrumentnode(&n.Left, init, 0, 0)
    214 		if n.Left.Type.IsMap() {
    215 			n1 := nod(OCONVNOP, n.Left, nil)
    216 			n1.Type = types.NewPtr(types.Types[TUINT8])
    217 			n1 = nod(OIND, n1, nil)
    218 			n1 = typecheck(n1, Erv)
    219 			callinstr(&n1, init, 0, skip)
    220 		}
    221 
    222 	case OLSH,
    223 		ORSH,
    224 		OAND,
    225 		OANDNOT,
    226 		OOR,
    227 		OXOR,
    228 		OSUB,
    229 		OMUL,
    230 		OEQ,
    231 		ONE,
    232 		OLT,
    233 		OLE,
    234 		OGE,
    235 		OGT,
    236 		OADD,
    237 		OCOMPLEX:
    238 		instrumentnode(&n.Left, init, wr, 0)
    239 		instrumentnode(&n.Right, init, wr, 0)
    240 
    241 	case OANDAND, OOROR:
    242 		instrumentnode(&n.Left, init, wr, 0)
    243 
    244 		// walk has ensured the node has moved to a location where
    245 		// side effects are safe.
    246 		// n->right may not be executed,
    247 		// so instrumentation goes to n->right->ninit, not init.
    248 		instrumentnode(&n.Right, &n.Right.Ninit, wr, 0)
    249 
    250 	case ONAME:
    251 		callinstr(&n, init, wr, skip)
    252 
    253 	case OCONV:
    254 		instrumentnode(&n.Left, init, wr, 0)
    255 
    256 	case OCONVNOP:
    257 		instrumentnode(&n.Left, init, wr, 0)
    258 
    259 	case ODIV, OMOD:
    260 		instrumentnode(&n.Left, init, wr, 0)
    261 		instrumentnode(&n.Right, init, wr, 0)
    262 
    263 	case OINDEX:
    264 		if !n.Left.Type.IsArray() {
    265 			instrumentnode(&n.Left, init, 0, 0)
    266 		} else if !islvalue(n.Left) {
    267 			// index of unaddressable array, like Map[k][i].
    268 			instrumentnode(&n.Left, init, wr, 0)
    269 
    270 			instrumentnode(&n.Right, init, 0, 0)
    271 			break
    272 		}
    273 
    274 		instrumentnode(&n.Right, init, 0, 0)
    275 		if !n.Left.Type.IsString() {
    276 			callinstr(&n, init, wr, skip)
    277 		}
    278 
    279 	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
    280 		instrumentnode(&n.Left, init, 0, 0)
    281 		low, high, max := n.SliceBounds()
    282 		instrumentnode(&low, init, 0, 0)
    283 		instrumentnode(&high, init, 0, 0)
    284 		instrumentnode(&max, init, 0, 0)
    285 		n.SetSliceBounds(low, high, max)
    286 
    287 	case OADDR:
    288 		instrumentnode(&n.Left, init, 0, 1)
    289 
    290 		// n->left is Type* which is not interesting.
    291 	case OEFACE:
    292 		instrumentnode(&n.Right, init, 0, 0)
    293 
    294 	case OITAB, OIDATA:
    295 		instrumentnode(&n.Left, init, 0, 0)
    296 
    297 	case OSTRARRAYBYTETMP:
    298 		instrumentnode(&n.Left, init, 0, 0)
    299 
    300 	case OAS2DOTTYPE:
    301 		instrumentnode(&n.Left, init, 1, 0)
    302 		instrumentnode(&n.Right, init, 0, 0)
    303 
    304 	case ODOTTYPE, ODOTTYPE2:
    305 		instrumentnode(&n.Left, init, 0, 0)
    306 
    307 		// should not appear in AST by now
    308 	case OSEND,
    309 		ORECV,
    310 		OCLOSE,
    311 		ONEW,
    312 		OXCASE,
    313 		OCASE,
    314 		OPANIC,
    315 		ORECOVER,
    316 		OCONVIFACE,
    317 		OCMPIFACE,
    318 		OMAKECHAN,
    319 		OMAKEMAP,
    320 		OMAKESLICE,
    321 		OCALL,
    322 		OCOPY,
    323 		OAPPEND,
    324 		ORUNESTR,
    325 		OARRAYBYTESTR,
    326 		OARRAYRUNESTR,
    327 		OSTRARRAYBYTE,
    328 		OSTRARRAYRUNE,
    329 		OINDEXMAP,
    330 		// lowered to call
    331 		OCMPSTR,
    332 		OADDSTR,
    333 		OCALLPART,
    334 		// lowered to PTRLIT
    335 		OCLOSURE,  // lowered to PTRLIT
    336 		ORANGE,    // lowered to ordinary for loop
    337 		OARRAYLIT, // lowered to assignments
    338 		OSLICELIT,
    339 		OMAPLIT,
    340 		OSTRUCTLIT,
    341 		OAS2,
    342 		OAS2RECV,
    343 		OAS2MAPR,
    344 		OASOP:
    345 		Fatalf("instrument: %v must be lowered by now", n.Op)
    346 
    347 	case OGETG:
    348 		Fatalf("instrument: OGETG can happen only in runtime which we don't instrument")
    349 
    350 	case OFOR, OFORUNTIL:
    351 		if n.Left != nil {
    352 			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
    353 		}
    354 		if n.Right != nil {
    355 			instrumentnode(&n.Right, &n.Right.Ninit, 0, 0)
    356 		}
    357 
    358 	case OIF, OSWITCH:
    359 		if n.Left != nil {
    360 			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
    361 		}
    362 
    363 		// just do generic traversal
    364 	case OCALLMETH,
    365 		ORETURN,
    366 		ORETJMP,
    367 		OSELECT,
    368 		OEMPTY,
    369 		OBREAK,
    370 		OCONTINUE,
    371 		OFALL,
    372 		OGOTO,
    373 		OLABEL:
    374 
    375 		// does not require instrumentation
    376 	case OPRINT, // don't bother instrumenting it
    377 		OPRINTN,     // don't bother instrumenting it
    378 		OCHECKNIL,   // always followed by a read.
    379 		OCLOSUREVAR, // immutable pointer to captured variable
    380 		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
    381 		OINDREGSP,   // at this stage, only n(SP) nodes from nodarg
    382 		ODCL,        // declarations (without value) cannot be races
    383 		ODCLCONST,
    384 		ODCLTYPE,
    385 		OTYPE,
    386 		ONONAME,
    387 		OLITERAL,
    388 		OTYPESW: // ignored by code generation, do not instrument.
    389 	}
    390 
    391 	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
    392 		instrumentlist(n.List, init)
    393 	}
    394 	instrumentlist(n.Nbody, nil)
    395 	instrumentlist(n.Rlist, nil)
    396 	*np = n
    397 }
    398 
    399 func isartificial(n *Node) bool {
    400 	// compiler-emitted artificial things that we do not want to instrument,
    401 	// can't possibly participate in a data race.
    402 	// can't be seen by C/C++ and therefore irrelevant for msan.
    403 	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
    404 		if n.Sym.Name == "_" {
    405 			return true
    406 		}
    407 
    408 		// autotmp's are always local
    409 		if n.IsAutoTmp() {
    410 			return true
    411 		}
    412 
    413 		// statictmp's are read-only
    414 		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
    415 			return true
    416 		}
    417 
    418 		// go.itab is accessed only by the compiler and runtime (assume safe)
    419 		if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
    420 			return true
    421 		}
    422 	}
    423 
    424 	return false
    425 }
    426 
    427 func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
    428 	n := *np
    429 
    430 	//fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n",
    431 	//	n, n.Op, n.Type.Etype, n.Class)
    432 
    433 	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
    434 		return false
    435 	}
    436 	t := n.Type
    437 	// dowidth may not have been called for PEXTERN.
    438 	dowidth(t)
    439 	w := t.Width
    440 	if w == BADWIDTH {
    441 		Fatalf("instrument: %v badwidth", t)
    442 	}
    443 	if w == 0 {
    444 		return false // can't race on zero-sized things
    445 	}
    446 	if isartificial(n) {
    447 		return false
    448 	}
    449 
    450 	b := outervalue(n)
    451 
    452 	// it skips e.g. stores to ... parameter array
    453 	if isartificial(b) {
    454 		return false
    455 	}
    456 	class := b.Class()
    457 
    458 	// BUG: we _may_ want to instrument PAUTO sometimes
    459 	// e.g. if we've got a local variable/method receiver
    460 	// that has got a pointer inside. Whether it points to
    461 	// the heap or not is impossible to know at compile time
    462 	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
    463 		hasCalls := false
    464 		inspect(n, func(n *Node) bool {
    465 			switch n.Op {
    466 			case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
    467 				hasCalls = true
    468 			}
    469 			return !hasCalls
    470 		})
    471 		if hasCalls {
    472 			n = detachexpr(n, init)
    473 			*np = n
    474 		}
    475 
    476 		n = treecopy(n, src.NoXPos)
    477 		makeaddable(n)
    478 		var f *Node
    479 		if flag_msan {
    480 			name := "msanread"
    481 			if wr != 0 {
    482 				name = "msanwrite"
    483 			}
    484 			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
    485 		} else if flag_race && t.NumComponents() > 1 {
    486 			// for composite objects we have to write every address
    487 			// because a write might happen to any subobject.
    488 			// composites with only one element don't have subobjects, though.
    489 			name := "racereadrange"
    490 			if wr != 0 {
    491 				name = "racewriterange"
    492 			}
    493 			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
    494 		} else if flag_race {
    495 			// for non-composite objects we can write just the start
    496 			// address, as any write must write the first byte.
    497 			name := "raceread"
    498 			if wr != 0 {
    499 				name = "racewrite"
    500 			}
    501 			f = mkcall(name, nil, init, uintptraddr(n))
    502 		}
    503 
    504 		init.Append(f)
    505 		return true
    506 	}
    507 
    508 	return false
    509 }
    510 
    511 // makeaddable returns a node whose memory location is the
    512 // same as n, but which is addressable in the Go language
    513 // sense.
    514 // This is different from functions like cheapexpr that may make
    515 // a copy of their argument.
    516 func makeaddable(n *Node) {
    517 	// The arguments to uintptraddr technically have an address but
    518 	// may not be addressable in the Go sense: for example, in the case
    519 	// of T(v).Field where T is a struct type and v is
    520 	// an addressable value.
    521 	switch n.Op {
    522 	case OINDEX:
    523 		if n.Left.Type.IsArray() {
    524 			makeaddable(n.Left)
    525 		}
    526 
    527 		// Turn T(v).Field into v.Field
    528 	case ODOT, OXDOT:
    529 		if n.Left.Op == OCONVNOP {
    530 			n.Left = n.Left.Left
    531 		}
    532 		makeaddable(n.Left)
    533 
    534 		// nothing to do
    535 	}
    536 }
    537 
    538 func uintptraddr(n *Node) *Node {
    539 	r := nod(OADDR, n, nil)
    540 	r.SetBounded(true)
    541 	r = conv(r, types.Types[TUNSAFEPTR])
    542 	r = conv(r, types.Types[TUINTPTR])
    543 	return r
    544 }
    545 
    546 func detachexpr(n *Node, init *Nodes) *Node {
    547 	addr := nod(OADDR, n, nil)
    548 	l := temp(types.NewPtr(n.Type))
    549 	as := nod(OAS, l, addr)
    550 	as = typecheck(as, Etop)
    551 	as = walkexpr(as, init)
    552 	init.Append(as)
    553 	ind := nod(OIND, l, nil)
    554 	ind = typecheck(ind, Erv)
    555 	ind = walkexpr(ind, init)
    556 	return ind
    557 }
    558 
    559 // appendinit is like addinit in subr.go
    560 // but appends rather than prepends.
    561 func appendinit(np **Node, init Nodes) {
    562 	if init.Len() == 0 {
    563 		return
    564 	}
    565 
    566 	n := *np
    567 	switch n.Op {
    568 	// There may be multiple refs to this node;
    569 	// introduce OCONVNOP to hold init list.
    570 	case ONAME, OLITERAL:
    571 		n = nod(OCONVNOP, n, nil)
    572 
    573 		n.Type = n.Left.Type
    574 		n.SetTypecheck(1)
    575 		*np = n
    576 	}
    577 
    578 	n.Ninit.AppendNodes(&init)
    579 	n.SetHasCall(true)
    580 }
    581