github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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  
   144  		// can't matter
   145  	case OCFUNC, OVARKILL, OVARLIVE:
   146  
   147  	case OBLOCK:
   148  		ls := n.List.Slice()
   149  		afterCall := false
   150  		for i := range ls {
   151  			op := ls[i].Op
   152  			// Scan past OAS nodes copying results off stack.
   153  			// Those must not be instrumented, because the
   154  			// instrumentation calls will smash the results.
   155  			// The assignments are to temporaries, so they cannot
   156  			// be involved in races and need not be instrumented.
   157  			if afterCall && op == OAS && iscallret(ls[i].Right) {
   158  				continue
   159  			}
   160  			instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
   161  			afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER)
   162  		}
   163  
   164  	case ODEFER:
   165  		instrumentnode(&n.Left, init, 0, 0)
   166  
   167  	case OPROC:
   168  		instrumentnode(&n.Left, init, 0, 0)
   169  
   170  	case OCALLINTER:
   171  		instrumentnode(&n.Left, init, 0, 0)
   172  
   173  	// Instrument dst argument of runtime.writebarrier* calls
   174  	// as we do not instrument runtime code.
   175  	// typedslicecopy is instrumented in runtime.
   176  	case OCALLFUNC:
   177  		instrumentnode(&n.Left, init, 0, 0)
   178  
   179  	case ONOT,
   180  		OMINUS,
   181  		OPLUS,
   182  		OREAL,
   183  		OIMAG,
   184  		OCOM:
   185  		instrumentnode(&n.Left, init, wr, 0)
   186  
   187  	case ODOTINTER:
   188  		instrumentnode(&n.Left, init, 0, 0)
   189  
   190  	case ODOT:
   191  		instrumentnode(&n.Left, init, 0, 1)
   192  		callinstr(&n, init, wr, skip)
   193  
   194  	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
   195  		instrumentnode(&n.Left, init, 0, 0)
   196  
   197  		callinstr(&n, init, wr, skip)
   198  
   199  	case OIND: // *p
   200  		instrumentnode(&n.Left, init, 0, 0)
   201  
   202  		callinstr(&n, init, wr, skip)
   203  
   204  	case OSPTR, OLEN, OCAP:
   205  		instrumentnode(&n.Left, init, 0, 0)
   206  		if n.Left.Type.IsMap() {
   207  			n1 := nod(OCONVNOP, n.Left, nil)
   208  			n1.Type = types.NewPtr(types.Types[TUINT8])
   209  			n1 = nod(OIND, n1, nil)
   210  			n1 = typecheck(n1, Erv)
   211  			callinstr(&n1, init, 0, skip)
   212  		}
   213  
   214  	case OLSH,
   215  		ORSH,
   216  		OAND,
   217  		OANDNOT,
   218  		OOR,
   219  		OXOR,
   220  		OSUB,
   221  		OMUL,
   222  		OEQ,
   223  		ONE,
   224  		OLT,
   225  		OLE,
   226  		OGE,
   227  		OGT,
   228  		OADD,
   229  		OCOMPLEX:
   230  		instrumentnode(&n.Left, init, wr, 0)
   231  		instrumentnode(&n.Right, init, wr, 0)
   232  
   233  	case OANDAND, OOROR:
   234  		instrumentnode(&n.Left, init, wr, 0)
   235  
   236  		// walk has ensured the node has moved to a location where
   237  		// side effects are safe.
   238  		// n->right may not be executed,
   239  		// so instrumentation goes to n->right->ninit, not init.
   240  		instrumentnode(&n.Right, &n.Right.Ninit, wr, 0)
   241  
   242  	case ONAME:
   243  		callinstr(&n, init, wr, skip)
   244  
   245  	case OCONV:
   246  		instrumentnode(&n.Left, init, wr, 0)
   247  
   248  	case OCONVNOP:
   249  		instrumentnode(&n.Left, init, wr, 0)
   250  
   251  	case ODIV, OMOD:
   252  		instrumentnode(&n.Left, init, wr, 0)
   253  		instrumentnode(&n.Right, init, wr, 0)
   254  
   255  	case OINDEX:
   256  		if !n.Left.Type.IsArray() {
   257  			instrumentnode(&n.Left, init, 0, 0)
   258  		} else if !islvalue(n.Left) {
   259  			// index of unaddressable array, like Map[k][i].
   260  			instrumentnode(&n.Left, init, wr, 0)
   261  
   262  			instrumentnode(&n.Right, init, 0, 0)
   263  			break
   264  		}
   265  
   266  		instrumentnode(&n.Right, init, 0, 0)
   267  		if !n.Left.Type.IsString() {
   268  			callinstr(&n, init, wr, skip)
   269  		}
   270  
   271  	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
   272  		instrumentnode(&n.Left, init, 0, 0)
   273  		low, high, max := n.SliceBounds()
   274  		instrumentnode(&low, init, 0, 0)
   275  		instrumentnode(&high, init, 0, 0)
   276  		instrumentnode(&max, init, 0, 0)
   277  		n.SetSliceBounds(low, high, max)
   278  
   279  	case OADDR:
   280  		instrumentnode(&n.Left, init, 0, 1)
   281  
   282  		// n->left is Type* which is not interesting.
   283  	case OEFACE:
   284  		instrumentnode(&n.Right, init, 0, 0)
   285  
   286  	case OITAB, OIDATA:
   287  		instrumentnode(&n.Left, init, 0, 0)
   288  
   289  	case OSTRARRAYBYTETMP:
   290  		instrumentnode(&n.Left, init, 0, 0)
   291  
   292  	case OAS2DOTTYPE:
   293  		instrumentnode(&n.Left, init, 1, 0)
   294  		instrumentnode(&n.Right, init, 0, 0)
   295  
   296  	case ODOTTYPE, ODOTTYPE2:
   297  		instrumentnode(&n.Left, init, 0, 0)
   298  
   299  		// should not appear in AST by now
   300  	case OSEND,
   301  		ORECV,
   302  		OCLOSE,
   303  		ONEW,
   304  		OXCASE,
   305  		OCASE,
   306  		OPANIC,
   307  		ORECOVER,
   308  		OCONVIFACE,
   309  		OCMPIFACE,
   310  		OMAKECHAN,
   311  		OMAKEMAP,
   312  		OMAKESLICE,
   313  		OCALL,
   314  		OCOPY,
   315  		OAPPEND,
   316  		ORUNESTR,
   317  		OARRAYBYTESTR,
   318  		OARRAYRUNESTR,
   319  		OSTRARRAYBYTE,
   320  		OSTRARRAYRUNE,
   321  		OINDEXMAP,
   322  		// lowered to call
   323  		OCMPSTR,
   324  		OADDSTR,
   325  		OCALLPART,
   326  		// lowered to PTRLIT
   327  		OCLOSURE,  // lowered to PTRLIT
   328  		ORANGE,    // lowered to ordinary for loop
   329  		OARRAYLIT, // lowered to assignments
   330  		OSLICELIT,
   331  		OMAPLIT,
   332  		OSTRUCTLIT,
   333  		OAS2,
   334  		OAS2RECV,
   335  		OAS2MAPR,
   336  		OASOP:
   337  		Fatalf("instrument: %v must be lowered by now", n.Op)
   338  
   339  	case OGETG:
   340  		Fatalf("instrument: OGETG can happen only in runtime which we don't instrument")
   341  
   342  	case OFOR, OFORUNTIL:
   343  		if n.Left != nil {
   344  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   345  		}
   346  		if n.Right != nil {
   347  			instrumentnode(&n.Right, &n.Right.Ninit, 0, 0)
   348  		}
   349  
   350  	case OIF, OSWITCH:
   351  		if n.Left != nil {
   352  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   353  		}
   354  
   355  		// just do generic traversal
   356  	case OCALLMETH,
   357  		ORETURN,
   358  		ORETJMP,
   359  		OSELECT,
   360  		OEMPTY,
   361  		OBREAK,
   362  		OCONTINUE,
   363  		OFALL,
   364  		OGOTO,
   365  		OLABEL:
   366  
   367  		// does not require instrumentation
   368  	case OPRINT, // don't bother instrumenting it
   369  		OPRINTN,     // don't bother instrumenting it
   370  		OCHECKNIL,   // always followed by a read.
   371  		OCLOSUREVAR, // immutable pointer to captured variable
   372  		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
   373  		OINDREGSP,   // at this stage, only n(SP) nodes from nodarg
   374  		ODCL,        // declarations (without value) cannot be races
   375  		ODCLCONST,
   376  		ODCLTYPE,
   377  		OTYPE,
   378  		ONONAME,
   379  		OLITERAL,
   380  		OTYPESW: // ignored by code generation, do not instrument.
   381  	}
   382  
   383  	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
   384  		instrumentlist(n.List, init)
   385  	}
   386  	instrumentlist(n.Nbody, nil)
   387  	instrumentlist(n.Rlist, nil)
   388  	*np = n
   389  }
   390  
   391  func isartificial(n *Node) bool {
   392  	// compiler-emitted artificial things that we do not want to instrument,
   393  	// can't possibly participate in a data race.
   394  	// can't be seen by C/C++ and therefore irrelevant for msan.
   395  	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
   396  		if n.Sym.Name == "_" {
   397  			return true
   398  		}
   399  
   400  		// autotmp's are always local
   401  		if n.IsAutoTmp() {
   402  			return true
   403  		}
   404  
   405  		// statictmp's are read-only
   406  		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
   407  			return true
   408  		}
   409  
   410  		// go.itab is accessed only by the compiler and runtime (assume safe)
   411  		if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
   412  			return true
   413  		}
   414  	}
   415  
   416  	return false
   417  }
   418  
   419  func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
   420  	n := *np
   421  
   422  	//fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n",
   423  	//	n, n.Op, n.Type.Etype, n.Class)
   424  
   425  	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
   426  		return false
   427  	}
   428  	t := n.Type
   429  	// dowidth may not have been called for PEXTERN.
   430  	dowidth(t)
   431  	w := t.Width
   432  	if w == BADWIDTH {
   433  		Fatalf("instrument: %v badwidth", t)
   434  	}
   435  	if w == 0 {
   436  		return false // can't race on zero-sized things
   437  	}
   438  	if isartificial(n) {
   439  		return false
   440  	}
   441  
   442  	b := outervalue(n)
   443  
   444  	// it skips e.g. stores to ... parameter array
   445  	if isartificial(b) {
   446  		return false
   447  	}
   448  	class := b.Class()
   449  
   450  	// BUG: we _may_ want to instrument PAUTO sometimes
   451  	// e.g. if we've got a local variable/method receiver
   452  	// that has got a pointer inside. Whether it points to
   453  	// the heap or not is impossible to know at compile time
   454  	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
   455  		hascalls := 0
   456  		foreach(n, hascallspred, &hascalls)
   457  		if hascalls != 0 {
   458  			n = detachexpr(n, init)
   459  			*np = n
   460  		}
   461  
   462  		n = treecopy(n, src.NoXPos)
   463  		makeaddable(n)
   464  		var f *Node
   465  		if flag_msan {
   466  			name := "msanread"
   467  			if wr != 0 {
   468  				name = "msanwrite"
   469  			}
   470  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   471  		} else if flag_race && t.NumComponents() > 1 {
   472  			// for composite objects we have to write every address
   473  			// because a write might happen to any subobject.
   474  			// composites with only one element don't have subobjects, though.
   475  			name := "racereadrange"
   476  			if wr != 0 {
   477  				name = "racewriterange"
   478  			}
   479  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   480  		} else if flag_race {
   481  			// for non-composite objects we can write just the start
   482  			// address, as any write must write the first byte.
   483  			name := "raceread"
   484  			if wr != 0 {
   485  				name = "racewrite"
   486  			}
   487  			f = mkcall(name, nil, init, uintptraddr(n))
   488  		}
   489  
   490  		init.Append(f)
   491  		return true
   492  	}
   493  
   494  	return false
   495  }
   496  
   497  // makeaddable returns a node whose memory location is the
   498  // same as n, but which is addressable in the Go language
   499  // sense.
   500  // This is different from functions like cheapexpr that may make
   501  // a copy of their argument.
   502  func makeaddable(n *Node) {
   503  	// The arguments to uintptraddr technically have an address but
   504  	// may not be addressable in the Go sense: for example, in the case
   505  	// of T(v).Field where T is a struct type and v is
   506  	// an addressable value.
   507  	switch n.Op {
   508  	case OINDEX:
   509  		if n.Left.Type.IsArray() {
   510  			makeaddable(n.Left)
   511  		}
   512  
   513  		// Turn T(v).Field into v.Field
   514  	case ODOT, OXDOT:
   515  		if n.Left.Op == OCONVNOP {
   516  			n.Left = n.Left.Left
   517  		}
   518  		makeaddable(n.Left)
   519  
   520  		// nothing to do
   521  	}
   522  }
   523  
   524  func uintptraddr(n *Node) *Node {
   525  	r := nod(OADDR, n, nil)
   526  	r.SetBounded(true)
   527  	r = conv(r, types.Types[TUNSAFEPTR])
   528  	r = conv(r, types.Types[TUINTPTR])
   529  	return r
   530  }
   531  
   532  func detachexpr(n *Node, init *Nodes) *Node {
   533  	addr := nod(OADDR, n, nil)
   534  	l := temp(types.NewPtr(n.Type))
   535  	as := nod(OAS, l, addr)
   536  	as = typecheck(as, Etop)
   537  	as = walkexpr(as, init)
   538  	init.Append(as)
   539  	ind := nod(OIND, l, nil)
   540  	ind = typecheck(ind, Erv)
   541  	ind = walkexpr(ind, init)
   542  	return ind
   543  }
   544  
   545  func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
   546  	if n != nil {
   547  		f(n, c)
   548  	}
   549  }
   550  
   551  func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
   552  	for _, n := range l.Slice() {
   553  		foreachnode(n, f, c)
   554  	}
   555  }
   556  
   557  func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
   558  	foreachlist(n.Ninit, f, c)
   559  	foreachnode(n.Left, f, c)
   560  	foreachnode(n.Right, f, c)
   561  	foreachlist(n.List, f, c)
   562  	foreachlist(n.Nbody, f, c)
   563  	foreachlist(n.Rlist, f, c)
   564  }
   565  
   566  func hascallspred(n *Node, c interface{}) {
   567  	switch n.Op {
   568  	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
   569  		(*c.(*int))++
   570  	}
   571  }
   572  
   573  // appendinit is like addinit in subr.go
   574  // but appends rather than prepends.
   575  func appendinit(np **Node, init Nodes) {
   576  	if init.Len() == 0 {
   577  		return
   578  	}
   579  
   580  	n := *np
   581  	switch n.Op {
   582  	// There may be multiple refs to this node;
   583  	// introduce OCONVNOP to hold init list.
   584  	case ONAME, OLITERAL:
   585  		n = nod(OCONVNOP, n, nil)
   586  
   587  		n.Type = n.Left.Type
   588  		n.SetTypecheck(1)
   589  		*np = n
   590  	}
   591  
   592  	n.Ninit.AppendNodes(&init)
   593  	n.SetHasCall(true)
   594  }