github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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  		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  }