github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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  	"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  func isforkfunc(fn *Node) bool {
    46  	// Special case for syscall.forkAndExecInChild.
    47  	// In the child, this function must not acquire any locks, because
    48  	// they might have been locked at the time of the fork.  This means
    49  	// no rescheduling, no malloc calls, and no new stack segments.
    50  	// Race instrumentation does all of the above.
    51  	return myimportpath != "" && myimportpath == "syscall" && fn.Nname.Sym.Name == "forkAndExecInChild"
    52  }
    53  
    54  func racewalk(fn *Node) {
    55  	if ispkgin(omit_pkgs) || isforkfunc(fn) {
    56  		return
    57  	}
    58  
    59  	if !ispkgin(noinst_pkgs) {
    60  		racewalklist(fn.Nbody, nil)
    61  
    62  		// nothing interesting for race detector in fn->enter
    63  		racewalklist(fn.Func.Exit, nil)
    64  	}
    65  
    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 := Nod(OXXX, nil, nil)
    70  
    71  	*nodpc = *nodfp
    72  	nodpc.Type = Types[TUINTPTR]
    73  	nodpc.Xoffset = int64(-Widthptr)
    74  	nd := mkcall("racefuncenter", nil, nil, nodpc)
    75  	fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
    76  	nd = mkcall("racefuncexit", nil, nil)
    77  	fn.Func.Exit = list(fn.Func.Exit, nd)
    78  
    79  	if Debug['W'] != 0 {
    80  		s := fmt.Sprintf("after racewalk %v", Sconv(fn.Nname.Sym, 0))
    81  		dumplist(s, fn.Nbody)
    82  		s = fmt.Sprintf("enter %v", Sconv(fn.Nname.Sym, 0))
    83  		dumplist(s, fn.Func.Enter)
    84  		s = fmt.Sprintf("exit %v", Sconv(fn.Nname.Sym, 0))
    85  		dumplist(s, fn.Func.Exit)
    86  	}
    87  }
    88  
    89  func racewalklist(l *NodeList, init **NodeList) {
    90  	var instr *NodeList
    91  
    92  	for ; l != nil; l = l.Next {
    93  		instr = nil
    94  		racewalknode(&l.N, &instr, 0, 0)
    95  		if init == nil {
    96  			l.N.Ninit = concat(l.N.Ninit, instr)
    97  		} else {
    98  			*init = concat(*init, 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 racewalknode(np **Node, init **NodeList, wr int, skip int) {
   107  	n := *np
   108  
   109  	if n == nil {
   110  		return
   111  	}
   112  
   113  	if Debug['w'] > 1 {
   114  		Dump("racewalk-before", n)
   115  	}
   116  	setlineno(n)
   117  	if init == nil {
   118  		Fatal("racewalk: bad init list")
   119  	}
   120  	if init == &n.Ninit {
   121  		// If init == &n->ninit and n->ninit is non-nil,
   122  		// racewalknode 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 = nil
   127  		racewalklist(l, nil)
   128  		racewalknode(&n, &l, wr, skip) // recurse with nil n->ninit
   129  		appendinit(&n, l)
   130  		*np = n
   131  		return
   132  	}
   133  
   134  	racewalklist(n.Ninit, nil)
   135  
   136  	switch n.Op {
   137  	default:
   138  		Fatal("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
   139  
   140  	case OAS, OAS2FUNC:
   141  		racewalknode(&n.Left, init, 1, 0)
   142  		racewalknode(&n.Right, init, 0, 0)
   143  		goto ret
   144  
   145  		// can't matter
   146  	case OCFUNC, OVARKILL:
   147  		goto ret
   148  
   149  	case OBLOCK:
   150  		if n.List == nil {
   151  			goto ret
   152  		}
   153  
   154  		switch n.List.N.Op {
   155  		// Blocks are used for multiple return function calls.
   156  		// x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]}
   157  		// We don't want to instrument between the statements because it will
   158  		// smash the results.
   159  		case OCALLFUNC, OCALLMETH, OCALLINTER:
   160  			racewalknode(&n.List.N, &n.List.N.Ninit, 0, 0)
   161  
   162  			var fini *NodeList
   163  			racewalklist(n.List.Next, &fini)
   164  			n.List = concat(n.List, fini)
   165  
   166  			// Ordinary block, for loop initialization or inlined bodies.
   167  		default:
   168  			racewalklist(n.List, nil)
   169  		}
   170  
   171  		goto ret
   172  
   173  	case ODEFER:
   174  		racewalknode(&n.Left, init, 0, 0)
   175  		goto ret
   176  
   177  	case OPROC:
   178  		racewalknode(&n.Left, init, 0, 0)
   179  		goto ret
   180  
   181  	case OCALLINTER:
   182  		racewalknode(&n.Left, init, 0, 0)
   183  		goto ret
   184  
   185  		// Instrument dst argument of runtime.writebarrier* calls
   186  	// as we do not instrument runtime code.
   187  	// typedslicecopy is instrumented in runtime.
   188  	case OCALLFUNC:
   189  		if n.Left.Sym != nil && n.Left.Sym.Pkg == Runtimepkg && (strings.HasPrefix(n.Left.Sym.Name, "writebarrier") || n.Left.Sym.Name == "typedmemmove") {
   190  			// Find the dst argument.
   191  			// The list can be reordered, so it's not necessary just the first or the second element.
   192  			var l *NodeList
   193  			for l = n.List; l != nil; l = l.Next {
   194  				if n.Left.Sym.Name == "typedmemmove" {
   195  					if l.N.Left.Xoffset == int64(Widthptr) {
   196  						break
   197  					}
   198  				} else {
   199  					if l.N.Left.Xoffset == 0 {
   200  						break
   201  					}
   202  				}
   203  			}
   204  
   205  			if l == nil {
   206  				Fatal("racewalk: writebarrier no arg")
   207  			}
   208  			if l.N.Right.Op != OADDR {
   209  				Fatal("racewalk: writebarrier bad arg")
   210  			}
   211  			callinstr(&l.N.Right.Left, init, 1, 0)
   212  		}
   213  
   214  		racewalknode(&n.Left, init, 0, 0)
   215  		goto ret
   216  
   217  	case ONOT,
   218  		OMINUS,
   219  		OPLUS,
   220  		OREAL,
   221  		OIMAG,
   222  		OCOM,
   223  		OSQRT:
   224  		racewalknode(&n.Left, init, wr, 0)
   225  		goto ret
   226  
   227  	case ODOTINTER:
   228  		racewalknode(&n.Left, init, 0, 0)
   229  		goto ret
   230  
   231  	case ODOT:
   232  		racewalknode(&n.Left, init, 0, 1)
   233  		callinstr(&n, init, wr, skip)
   234  		goto ret
   235  
   236  	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
   237  		racewalknode(&n.Left, init, 0, 0)
   238  
   239  		callinstr(&n, init, wr, skip)
   240  		goto ret
   241  
   242  	case OIND: // *p
   243  		racewalknode(&n.Left, init, 0, 0)
   244  
   245  		callinstr(&n, init, wr, skip)
   246  		goto ret
   247  
   248  	case OSPTR, OLEN, OCAP:
   249  		racewalknode(&n.Left, init, 0, 0)
   250  		if Istype(n.Left.Type, TMAP) {
   251  			n1 := Nod(OCONVNOP, n.Left, nil)
   252  			n1.Type = Ptrto(Types[TUINT8])
   253  			n1 = Nod(OIND, n1, nil)
   254  			typecheck(&n1, Erv)
   255  			callinstr(&n1, init, 0, skip)
   256  		}
   257  
   258  		goto ret
   259  
   260  	case OLSH,
   261  		ORSH,
   262  		OLROT,
   263  		OAND,
   264  		OANDNOT,
   265  		OOR,
   266  		OXOR,
   267  		OSUB,
   268  		OMUL,
   269  		OHMUL,
   270  		OEQ,
   271  		ONE,
   272  		OLT,
   273  		OLE,
   274  		OGE,
   275  		OGT,
   276  		OADD,
   277  		OCOMPLEX:
   278  		racewalknode(&n.Left, init, wr, 0)
   279  		racewalknode(&n.Right, init, wr, 0)
   280  		goto ret
   281  
   282  	case OANDAND, OOROR:
   283  		racewalknode(&n.Left, init, wr, 0)
   284  
   285  		// walk has ensured the node has moved to a location where
   286  		// side effects are safe.
   287  		// n->right may not be executed,
   288  		// so instrumentation goes to n->right->ninit, not init.
   289  		racewalknode(&n.Right, &n.Right.Ninit, wr, 0)
   290  
   291  		goto ret
   292  
   293  	case ONAME:
   294  		callinstr(&n, init, wr, skip)
   295  		goto ret
   296  
   297  	case OCONV:
   298  		racewalknode(&n.Left, init, wr, 0)
   299  		goto ret
   300  
   301  	case OCONVNOP:
   302  		racewalknode(&n.Left, init, wr, 0)
   303  		goto ret
   304  
   305  	case ODIV, OMOD:
   306  		racewalknode(&n.Left, init, wr, 0)
   307  		racewalknode(&n.Right, init, wr, 0)
   308  		goto ret
   309  
   310  	case OINDEX:
   311  		if !Isfixedarray(n.Left.Type) {
   312  			racewalknode(&n.Left, init, 0, 0)
   313  		} else if !islvalue(n.Left) {
   314  			// index of unaddressable array, like Map[k][i].
   315  			racewalknode(&n.Left, init, wr, 0)
   316  
   317  			racewalknode(&n.Right, init, 0, 0)
   318  			goto ret
   319  		}
   320  
   321  		racewalknode(&n.Right, init, 0, 0)
   322  		if n.Left.Type.Etype != TSTRING {
   323  			callinstr(&n, init, wr, skip)
   324  		}
   325  		goto ret
   326  
   327  		// Seems to only lead to double instrumentation.
   328  	//racewalknode(&n->left, init, 0, 0);
   329  	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
   330  		goto ret
   331  
   332  	case OADDR:
   333  		racewalknode(&n.Left, init, 0, 1)
   334  		goto ret
   335  
   336  		// n->left is Type* which is not interesting.
   337  	case OEFACE:
   338  		racewalknode(&n.Right, init, 0, 0)
   339  
   340  		goto ret
   341  
   342  	case OITAB:
   343  		racewalknode(&n.Left, init, 0, 0)
   344  		goto ret
   345  
   346  		// should not appear in AST by now
   347  	case OSEND,
   348  		ORECV,
   349  		OCLOSE,
   350  		ONEW,
   351  		OXCASE,
   352  		OXFALL,
   353  		OCASE,
   354  		OPANIC,
   355  		ORECOVER,
   356  		OCONVIFACE,
   357  		OCMPIFACE,
   358  		OMAKECHAN,
   359  		OMAKEMAP,
   360  		OMAKESLICE,
   361  		OCALL,
   362  		OCOPY,
   363  		OAPPEND,
   364  		ORUNESTR,
   365  		OARRAYBYTESTR,
   366  		OARRAYRUNESTR,
   367  		OSTRARRAYBYTE,
   368  		OSTRARRAYRUNE,
   369  		OINDEXMAP,
   370  		// lowered to call
   371  		OCMPSTR,
   372  		OADDSTR,
   373  		ODOTTYPE,
   374  		ODOTTYPE2,
   375  		OAS2DOTTYPE,
   376  		OCALLPART,
   377  		// lowered to PTRLIT
   378  		OCLOSURE,  // lowered to PTRLIT
   379  		ORANGE,    // lowered to ordinary for loop
   380  		OARRAYLIT, // lowered to assignments
   381  		OMAPLIT,
   382  		OSTRUCTLIT,
   383  		OAS2,
   384  		OAS2RECV,
   385  		OAS2MAPR,
   386  		OASOP:
   387  		Yyerror("racewalk: %v must be lowered by now", Oconv(int(n.Op), 0))
   388  
   389  		goto ret
   390  
   391  		// impossible nodes: only appear in backend.
   392  	case ORROTC, OEXTEND:
   393  		Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
   394  		goto ret
   395  
   396  	case OGETG:
   397  		Yyerror("racewalk: OGETG can happen only in runtime which we don't instrument")
   398  		goto ret
   399  
   400  		// just do generic traversal
   401  	case OFOR,
   402  		OIF,
   403  		OCALLMETH,
   404  		ORETURN,
   405  		ORETJMP,
   406  		OSWITCH,
   407  		OSELECT,
   408  		OEMPTY,
   409  		OBREAK,
   410  		OCONTINUE,
   411  		OFALL,
   412  		OGOTO,
   413  		OLABEL:
   414  		goto ret
   415  
   416  		// does not require instrumentation
   417  	case OPRINT, // don't bother instrumenting it
   418  		OPRINTN,     // don't bother instrumenting it
   419  		OCHECKNIL,   // always followed by a read.
   420  		OPARAM,      // it appears only in fn->exit to copy heap params back
   421  		OCLOSUREVAR, // immutable pointer to captured variable
   422  		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
   423  		OINDREG,     // at this stage, only n(SP) nodes from nodarg
   424  		ODCL,        // declarations (without value) cannot be races
   425  		ODCLCONST,
   426  		ODCLTYPE,
   427  		OTYPE,
   428  		ONONAME,
   429  		OLITERAL,
   430  		OSLICESTR, // always preceded by bounds checking, avoid double instrumentation.
   431  		OTYPESW:   // ignored by code generation, do not instrument.
   432  		goto ret
   433  	}
   434  
   435  ret:
   436  	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
   437  		racewalklist(n.List, init)
   438  	}
   439  	if n.Ntest != nil {
   440  		racewalknode(&n.Ntest, &n.Ntest.Ninit, 0, 0)
   441  	}
   442  	if n.Nincr != nil {
   443  		racewalknode(&n.Nincr, &n.Nincr.Ninit, 0, 0)
   444  	}
   445  	racewalklist(n.Nbody, nil)
   446  	racewalklist(n.Nelse, nil)
   447  	racewalklist(n.Rlist, nil)
   448  	*np = n
   449  }
   450  
   451  func isartificial(n *Node) bool {
   452  	// compiler-emitted artificial things that we do not want to instrument,
   453  	// cant' possibly participate in a data race.
   454  	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
   455  		if n.Sym.Name == "_" {
   456  			return true
   457  		}
   458  
   459  		// autotmp's are always local
   460  		if strings.HasPrefix(n.Sym.Name, "autotmp_") {
   461  			return true
   462  		}
   463  
   464  		// statictmp's are read-only
   465  		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
   466  			return true
   467  		}
   468  
   469  		// go.itab is accessed only by the compiler and runtime (assume safe)
   470  		if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
   471  			return true
   472  		}
   473  	}
   474  
   475  	return false
   476  }
   477  
   478  func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
   479  	n := *np
   480  
   481  	//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
   482  	//	  n, n->op, n->type ? n->type->etype : -1, n->class);
   483  
   484  	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
   485  		return false
   486  	}
   487  	t := n.Type
   488  	if isartificial(n) {
   489  		return false
   490  	}
   491  
   492  	b := outervalue(n)
   493  
   494  	// it skips e.g. stores to ... parameter array
   495  	if isartificial(b) {
   496  		return false
   497  	}
   498  	class := b.Class
   499  
   500  	// BUG: we _may_ want to instrument PAUTO sometimes
   501  	// e.g. if we've got a local variable/method receiver
   502  	// that has got a pointer inside. Whether it points to
   503  	// the heap or not is impossible to know at compile time
   504  	if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
   505  		hascalls := 0
   506  		foreach(n, hascallspred, &hascalls)
   507  		if hascalls != 0 {
   508  			n = detachexpr(n, init)
   509  			*np = n
   510  		}
   511  
   512  		n = treecopy(n)
   513  		makeaddable(n)
   514  		var f *Node
   515  		if t.Etype == TSTRUCT || Isfixedarray(t) {
   516  			name := "racereadrange"
   517  			if wr != 0 {
   518  				name = "racewriterange"
   519  			}
   520  			f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
   521  		} else {
   522  			name := "raceread"
   523  			if wr != 0 {
   524  				name = "racewrite"
   525  			}
   526  			f = mkcall(name, nil, init, uintptraddr(n))
   527  		}
   528  
   529  		*init = list(*init, f)
   530  		return true
   531  	}
   532  
   533  	return false
   534  }
   535  
   536  // makeaddable returns a node whose memory location is the
   537  // same as n, but which is addressable in the Go language
   538  // sense.
   539  // This is different from functions like cheapexpr that may make
   540  // a copy of their argument.
   541  func makeaddable(n *Node) {
   542  	// The arguments to uintptraddr technically have an address but
   543  	// may not be addressable in the Go sense: for example, in the case
   544  	// of T(v).Field where T is a struct type and v is
   545  	// an addressable value.
   546  	switch n.Op {
   547  	case OINDEX:
   548  		if Isfixedarray(n.Left.Type) {
   549  			makeaddable(n.Left)
   550  		}
   551  
   552  		// Turn T(v).Field into v.Field
   553  	case ODOT, OXDOT:
   554  		if n.Left.Op == OCONVNOP {
   555  			n.Left = n.Left.Left
   556  		}
   557  		makeaddable(n.Left)
   558  
   559  		// nothing to do
   560  	case ODOTPTR:
   561  		fallthrough
   562  	default:
   563  		break
   564  	}
   565  }
   566  
   567  func uintptraddr(n *Node) *Node {
   568  	r := Nod(OADDR, n, nil)
   569  	r.Bounded = true
   570  	r = conv(r, Types[TUNSAFEPTR])
   571  	r = conv(r, Types[TUINTPTR])
   572  	return r
   573  }
   574  
   575  func detachexpr(n *Node, init **NodeList) *Node {
   576  	addr := Nod(OADDR, n, nil)
   577  	l := temp(Ptrto(n.Type))
   578  	as := Nod(OAS, l, addr)
   579  	typecheck(&as, Etop)
   580  	walkexpr(&as, init)
   581  	*init = list(*init, as)
   582  	ind := Nod(OIND, l, nil)
   583  	typecheck(&ind, Erv)
   584  	walkexpr(&ind, init)
   585  	return ind
   586  }
   587  
   588  func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
   589  	if n != nil {
   590  		f(n, c)
   591  	}
   592  }
   593  
   594  func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
   595  	for ; l != nil; l = l.Next {
   596  		foreachnode(l.N, f, c)
   597  	}
   598  }
   599  
   600  func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
   601  	foreachlist(n.Ninit, f, c)
   602  	foreachnode(n.Left, f, c)
   603  	foreachnode(n.Right, f, c)
   604  	foreachlist(n.List, f, c)
   605  	foreachnode(n.Ntest, f, c)
   606  	foreachnode(n.Nincr, f, c)
   607  	foreachlist(n.Nbody, f, c)
   608  	foreachlist(n.Nelse, 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 *NodeList) {
   622  	if init == nil {
   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 = concat(n.Ninit, init)
   639  	n.Ullman = UINF
   640  }