github.com/Filosottile/go@v0.0.0-20170906193555-dbed9972d994/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/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  		nd := mkcall("racefuncenter", nil, nil, &nodpc)
    74  		fn.Func.Enter.Prepend(nd)
    75  		nd = mkcall("racefuncexit", nil, nil)
    76  		fn.Func.Exit.Append(nd)
    77  		fn.Func.Dcl = append(fn.Func.Dcl, &nodpc)
    78  	}
    79  
    80  	if Debug['W'] != 0 {
    81  		s := fmt.Sprintf("after instrument %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 instrumentlist(l Nodes, init *Nodes) {
    91  	s := l.Slice()
    92  	for i := range s {
    93  		var instr Nodes
    94  		instrumentnode(&s[i], &instr, 0, 0)
    95  		if init == nil {
    96  			s[i].Ninit.AppendNodes(&instr)
    97  		} else {
    98  			init.AppendNodes(&instr)
    99  		}
   100  	}
   101  }
   102  
   103  // walkexpr and walkstmt combined
   104  // walks the tree and adds calls to the
   105  // instrumentation code to top-level (statement) nodes' init
   106  func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
   107  	n := *np
   108  
   109  	if n == nil {
   110  		return
   111  	}
   112  
   113  	if Debug['w'] > 1 {
   114  		Dump("instrument-before", n)
   115  	}
   116  	setlineno(n)
   117  	if init == nil {
   118  		Fatalf("instrument: bad init list")
   119  	}
   120  	if init == &n.Ninit {
   121  		// If init == &n->ninit and n->ninit is non-nil,
   122  		// instrumentnode might append it to itself.
   123  		// nil it out and handle it separately before putting it back.
   124  		l := n.Ninit
   125  
   126  		n.Ninit.Set(nil)
   127  		instrumentlist(l, nil)
   128  		instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit
   129  		appendinit(&n, l)
   130  		*np = n
   131  		return
   132  	}
   133  
   134  	instrumentlist(n.Ninit, nil)
   135  
   136  	switch n.Op {
   137  	default:
   138  		Fatalf("instrument: unknown node type %v", n.Op)
   139  
   140  	case OAS, OAS2FUNC:
   141  		instrumentnode(&n.Left, init, 1, 0)
   142  		instrumentnode(&n.Right, init, 0, 0)
   143  		goto ret
   144  
   145  		// can't matter
   146  	case OCFUNC, OVARKILL, OVARLIVE:
   147  		goto ret
   148  
   149  	case OBLOCK:
   150  		ls := n.List.Slice()
   151  		afterCall := false
   152  		for i := range ls {
   153  			op := ls[i].Op
   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  			if afterCall && op == OAS && iscallret(ls[i].Right) {
   160  				continue
   161  			}
   162  			instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
   163  			afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER)
   164  		}
   165  		goto ret
   166  
   167  	case ODEFER:
   168  		instrumentnode(&n.Left, init, 0, 0)
   169  		goto ret
   170  
   171  	case OPROC:
   172  		instrumentnode(&n.Left, init, 0, 0)
   173  		goto ret
   174  
   175  	case OCALLINTER:
   176  		instrumentnode(&n.Left, init, 0, 0)
   177  		goto ret
   178  
   179  	// Instrument dst argument of runtime.writebarrier* calls
   180  	// as we do not instrument runtime code.
   181  	// typedslicecopy is instrumented in runtime.
   182  	case OCALLFUNC:
   183  		instrumentnode(&n.Left, init, 0, 0)
   184  		goto ret
   185  
   186  	case ONOT,
   187  		OMINUS,
   188  		OPLUS,
   189  		OREAL,
   190  		OIMAG,
   191  		OCOM:
   192  		instrumentnode(&n.Left, init, wr, 0)
   193  		goto ret
   194  
   195  	case ODOTINTER:
   196  		instrumentnode(&n.Left, init, 0, 0)
   197  		goto ret
   198  
   199  	case ODOT:
   200  		instrumentnode(&n.Left, init, 0, 1)
   201  		callinstr(&n, init, wr, skip)
   202  		goto ret
   203  
   204  	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
   205  		instrumentnode(&n.Left, init, 0, 0)
   206  
   207  		callinstr(&n, init, wr, skip)
   208  		goto ret
   209  
   210  	case OIND: // *p
   211  		instrumentnode(&n.Left, init, 0, 0)
   212  
   213  		callinstr(&n, init, wr, skip)
   214  		goto ret
   215  
   216  	case OSPTR, OLEN, OCAP:
   217  		instrumentnode(&n.Left, init, 0, 0)
   218  		if n.Left.Type.IsMap() {
   219  			n1 := nod(OCONVNOP, n.Left, nil)
   220  			n1.Type = types.NewPtr(types.Types[TUINT8])
   221  			n1 = nod(OIND, n1, nil)
   222  			n1 = typecheck(n1, Erv)
   223  			callinstr(&n1, init, 0, skip)
   224  		}
   225  
   226  		goto ret
   227  
   228  	case OLSH,
   229  		ORSH,
   230  		OAND,
   231  		OANDNOT,
   232  		OOR,
   233  		OXOR,
   234  		OSUB,
   235  		OMUL,
   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  		Fatalf("instrument: %v must be lowered by now", n.Op)
   369  
   370  	case OGETG:
   371  		Fatalf("instrument: OGETG can happen only in runtime which we don't instrument")
   372  
   373  	case OFOR, OFORUNTIL:
   374  		if n.Left != nil {
   375  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   376  		}
   377  		if n.Right != nil {
   378  			instrumentnode(&n.Right, &n.Right.Ninit, 0, 0)
   379  		}
   380  		goto ret
   381  
   382  	case OIF, OSWITCH:
   383  		if n.Left != nil {
   384  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   385  		}
   386  		goto ret
   387  
   388  		// just do generic traversal
   389  	case OCALLMETH,
   390  		ORETURN,
   391  		ORETJMP,
   392  		OSELECT,
   393  		OEMPTY,
   394  		OBREAK,
   395  		OCONTINUE,
   396  		OFALL,
   397  		OGOTO,
   398  		OLABEL:
   399  		goto ret
   400  
   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  		OCLOSUREVAR, // immutable pointer to captured variable
   406  		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
   407  		OINDREGSP,   // at this stage, only n(SP) nodes from nodarg
   408  		ODCL,        // declarations (without value) cannot be races
   409  		ODCLCONST,
   410  		ODCLTYPE,
   411  		OTYPE,
   412  		ONONAME,
   413  		OLITERAL,
   414  		OTYPESW: // ignored by code generation, do not instrument.
   415  		goto ret
   416  	}
   417  
   418  ret:
   419  	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
   420  		instrumentlist(n.List, init)
   421  	}
   422  	instrumentlist(n.Nbody, nil)
   423  	instrumentlist(n.Rlist, nil)
   424  	*np = n
   425  }
   426  
   427  func isartificial(n *Node) bool {
   428  	// compiler-emitted artificial things that we do not want to instrument,
   429  	// can't possibly participate in a data race.
   430  	// can't be seen by C/C++ and therefore irrelevant for msan.
   431  	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
   432  		if n.Sym.Name == "_" {
   433  			return true
   434  		}
   435  
   436  		// autotmp's are always local
   437  		if n.IsAutoTmp() {
   438  			return true
   439  		}
   440  
   441  		// statictmp's are read-only
   442  		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
   443  			return true
   444  		}
   445  
   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" {
   448  			return true
   449  		}
   450  	}
   451  
   452  	return false
   453  }
   454  
   455  func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
   456  	n := *np
   457  
   458  	//fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n",
   459  	//	n, n.Op, n.Type.Etype, n.Class)
   460  
   461  	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
   462  		return false
   463  	}
   464  	t := n.Type
   465  	// dowidth may not have been called for PEXTERN.
   466  	dowidth(t)
   467  	w := t.Width
   468  	if w == BADWIDTH {
   469  		Fatalf("instrument: %v badwidth", t)
   470  	}
   471  	if w == 0 {
   472  		return false // can't race on zero-sized things
   473  	}
   474  	if isartificial(n) {
   475  		return false
   476  	}
   477  
   478  	b := outervalue(n)
   479  
   480  	// it skips e.g. stores to ... parameter array
   481  	if isartificial(b) {
   482  		return false
   483  	}
   484  	class := b.Class()
   485  
   486  	// BUG: we _may_ want to instrument PAUTO sometimes
   487  	// e.g. if we've got a local variable/method receiver
   488  	// that has got a pointer inside. Whether it points to
   489  	// the heap or not is impossible to know at compile time
   490  	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
   491  		hascalls := 0
   492  		foreach(n, hascallspred, &hascalls)
   493  		if hascalls != 0 {
   494  			n = detachexpr(n, init)
   495  			*np = n
   496  		}
   497  
   498  		n = treecopy(n, src.NoXPos)
   499  		makeaddable(n)
   500  		var f *Node
   501  		if flag_msan {
   502  			name := "msanread"
   503  			if wr != 0 {
   504  				name = "msanwrite"
   505  			}
   506  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   507  		} else if flag_race && t.NumComponents() > 1 {
   508  			// for composite objects we have to write every address
   509  			// because a write might happen to any subobject.
   510  			// composites with only one element don't have subobjects, though.
   511  			name := "racereadrange"
   512  			if wr != 0 {
   513  				name = "racewriterange"
   514  			}
   515  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   516  		} else if flag_race {
   517  			// for non-composite objects we can write just the start
   518  			// address, as any write must write the first byte.
   519  			name := "raceread"
   520  			if wr != 0 {
   521  				name = "racewrite"
   522  			}
   523  			f = mkcall(name, nil, init, uintptraddr(n))
   524  		}
   525  
   526  		init.Append(f)
   527  		return true
   528  	}
   529  
   530  	return false
   531  }
   532  
   533  // makeaddable returns a node whose memory location is the
   534  // same as n, but which is addressable in the Go language
   535  // sense.
   536  // This is different from functions like cheapexpr that may make
   537  // a copy of their argument.
   538  func makeaddable(n *Node) {
   539  	// The arguments to uintptraddr technically have an address but
   540  	// may not be addressable in the Go sense: for example, in the case
   541  	// of T(v).Field where T is a struct type and v is
   542  	// an addressable value.
   543  	switch n.Op {
   544  	case OINDEX:
   545  		if n.Left.Type.IsArray() {
   546  			makeaddable(n.Left)
   547  		}
   548  
   549  		// Turn T(v).Field into v.Field
   550  	case ODOT, OXDOT:
   551  		if n.Left.Op == OCONVNOP {
   552  			n.Left = n.Left.Left
   553  		}
   554  		makeaddable(n.Left)
   555  
   556  		// nothing to do
   557  	case ODOTPTR:
   558  		fallthrough
   559  	default:
   560  		break
   561  	}
   562  }
   563  
   564  func uintptraddr(n *Node) *Node {
   565  	r := nod(OADDR, n, nil)
   566  	r.SetBounded(true)
   567  	r = conv(r, types.Types[TUNSAFEPTR])
   568  	r = conv(r, types.Types[TUINTPTR])
   569  	return r
   570  }
   571  
   572  func detachexpr(n *Node, init *Nodes) *Node {
   573  	addr := nod(OADDR, n, nil)
   574  	l := temp(types.NewPtr(n.Type))
   575  	as := nod(OAS, l, addr)
   576  	as = typecheck(as, Etop)
   577  	as = walkexpr(as, init)
   578  	init.Append(as)
   579  	ind := nod(OIND, l, nil)
   580  	ind = typecheck(ind, Erv)
   581  	ind = walkexpr(ind, init)
   582  	return ind
   583  }
   584  
   585  func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
   586  	if n != nil {
   587  		f(n, c)
   588  	}
   589  }
   590  
   591  func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
   592  	for _, n := range l.Slice() {
   593  		foreachnode(n, f, c)
   594  	}
   595  }
   596  
   597  func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
   598  	foreachlist(n.Ninit, f, c)
   599  	foreachnode(n.Left, f, c)
   600  	foreachnode(n.Right, f, c)
   601  	foreachlist(n.List, f, c)
   602  	foreachlist(n.Nbody, f, c)
   603  	foreachlist(n.Rlist, f, c)
   604  }
   605  
   606  func hascallspred(n *Node, c interface{}) {
   607  	switch n.Op {
   608  	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
   609  		(*c.(*int))++
   610  	}
   611  }
   612  
   613  // appendinit is like addinit in subr.go
   614  // but appends rather than prepends.
   615  func appendinit(np **Node, init Nodes) {
   616  	if init.Len() == 0 {
   617  		return
   618  	}
   619  
   620  	n := *np
   621  	switch n.Op {
   622  	// There may be multiple refs to this node;
   623  	// introduce OCONVNOP to hold init list.
   624  	case ONAME, OLITERAL:
   625  		n = nod(OCONVNOP, n, nil)
   626  
   627  		n.Type = n.Left.Type
   628  		n.SetTypecheck(1)
   629  		*np = n
   630  	}
   631  
   632  	n.Ninit.AppendNodes(&init)
   633  	n.SetHasCall(true)
   634  }