github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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  	if isartificial(n) {
   466  		return false
   467  	}
   468  
   469  	b := outervalue(n)
   470  
   471  	// it skips e.g. stores to ... parameter array
   472  	if isartificial(b) {
   473  		return false
   474  	}
   475  	class := b.Class
   476  
   477  	// BUG: we _may_ want to instrument PAUTO sometimes
   478  	// e.g. if we've got a local variable/method receiver
   479  	// that has got a pointer inside. Whether it points to
   480  	// the heap or not is impossible to know at compile time
   481  	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
   482  		hascalls := 0
   483  		foreach(n, hascallspred, &hascalls)
   484  		if hascalls != 0 {
   485  			n = detachexpr(n, init)
   486  			*np = n
   487  		}
   488  
   489  		n = treecopy(n, src.NoXPos)
   490  		makeaddable(n)
   491  		var f *Node
   492  		if flag_msan {
   493  			name := "msanread"
   494  			if wr != 0 {
   495  				name = "msanwrite"
   496  			}
   497  			// dowidth may not have been called for PEXTERN.
   498  			dowidth(t)
   499  			w := t.Width
   500  			if w == BADWIDTH {
   501  				Fatalf("instrument: %v badwidth", t)
   502  			}
   503  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   504  		} else if flag_race && (t.IsStruct() || t.IsArray()) {
   505  			name := "racereadrange"
   506  			if wr != 0 {
   507  				name = "racewriterange"
   508  			}
   509  			// dowidth may not have been called for PEXTERN.
   510  			dowidth(t)
   511  			w := t.Width
   512  			if w == BADWIDTH {
   513  				Fatalf("instrument: %v badwidth", t)
   514  			}
   515  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   516  		} else if flag_race {
   517  			name := "raceread"
   518  			if wr != 0 {
   519  				name = "racewrite"
   520  			}
   521  			f = mkcall(name, nil, init, uintptraddr(n))
   522  		}
   523  
   524  		init.Append(f)
   525  		return true
   526  	}
   527  
   528  	return false
   529  }
   530  
   531  // makeaddable returns a node whose memory location is the
   532  // same as n, but which is addressable in the Go language
   533  // sense.
   534  // This is different from functions like cheapexpr that may make
   535  // a copy of their argument.
   536  func makeaddable(n *Node) {
   537  	// The arguments to uintptraddr technically have an address but
   538  	// may not be addressable in the Go sense: for example, in the case
   539  	// of T(v).Field where T is a struct type and v is
   540  	// an addressable value.
   541  	switch n.Op {
   542  	case OINDEX:
   543  		if n.Left.Type.IsArray() {
   544  			makeaddable(n.Left)
   545  		}
   546  
   547  		// Turn T(v).Field into v.Field
   548  	case ODOT, OXDOT:
   549  		if n.Left.Op == OCONVNOP {
   550  			n.Left = n.Left.Left
   551  		}
   552  		makeaddable(n.Left)
   553  
   554  		// nothing to do
   555  	case ODOTPTR:
   556  		fallthrough
   557  	default:
   558  		break
   559  	}
   560  }
   561  
   562  func uintptraddr(n *Node) *Node {
   563  	r := nod(OADDR, n, nil)
   564  	r.SetBounded(true)
   565  	r = conv(r, types.Types[TUNSAFEPTR])
   566  	r = conv(r, types.Types[TUINTPTR])
   567  	return r
   568  }
   569  
   570  func detachexpr(n *Node, init *Nodes) *Node {
   571  	addr := nod(OADDR, n, nil)
   572  	l := temp(types.NewPtr(n.Type))
   573  	as := nod(OAS, l, addr)
   574  	as = typecheck(as, Etop)
   575  	as = walkexpr(as, init)
   576  	init.Append(as)
   577  	ind := nod(OIND, l, nil)
   578  	ind = typecheck(ind, Erv)
   579  	ind = walkexpr(ind, init)
   580  	return ind
   581  }
   582  
   583  func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
   584  	if n != nil {
   585  		f(n, c)
   586  	}
   587  }
   588  
   589  func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
   590  	for _, n := range l.Slice() {
   591  		foreachnode(n, f, c)
   592  	}
   593  }
   594  
   595  func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
   596  	foreachlist(n.Ninit, f, c)
   597  	foreachnode(n.Left, f, c)
   598  	foreachnode(n.Right, f, c)
   599  	foreachlist(n.List, f, c)
   600  	foreachlist(n.Nbody, f, c)
   601  	foreachlist(n.Rlist, f, c)
   602  }
   603  
   604  func hascallspred(n *Node, c interface{}) {
   605  	switch n.Op {
   606  	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
   607  		(*c.(*int))++
   608  	}
   609  }
   610  
   611  // appendinit is like addinit in subr.go
   612  // but appends rather than prepends.
   613  func appendinit(np **Node, init Nodes) {
   614  	if init.Len() == 0 {
   615  		return
   616  	}
   617  
   618  	n := *np
   619  	switch n.Op {
   620  	// There may be multiple refs to this node;
   621  	// introduce OCONVNOP to hold init list.
   622  	case ONAME, OLITERAL:
   623  		n = nod(OCONVNOP, n, nil)
   624  
   625  		n.Type = n.Left.Type
   626  		n.Typecheck = 1
   627  		*np = n
   628  	}
   629  
   630  	n.Ninit.AppendNodes(&init)
   631  	n.SetHasCall(true)
   632  }