github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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  	"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 _, p := range pkgs {
    36  			if myimportpath == p {
    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  		Fatalf("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  		Fatalf("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  }