github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 instrument pass modifies the code tree for instrumentation.
    13  //
    14  // For flag_race it modifies the function as follows:
    15  //
    16  // 1. It inserts a call to racefuncenterfp at the beginning of each function.
    17  // 2. It inserts a call to racefuncexit at the end of each function.
    18  // 3. It inserts a call to raceread before each memory read.
    19  // 4. It inserts a call to racewrite before each memory write.
    20  //
    21  // For flag_msan:
    22  //
    23  // 1. It inserts a call to msanread before each memory read.
    24  // 2. It inserts a call to msanwrite before each memory write.
    25  //
    26  // The rewriting is not yet complete. Certain nodes are not rewritten
    27  // but should be.
    28  
    29  // TODO(dvyukov): do not instrument initialization as writes:
    30  // a := make([]int, 10)
    31  
    32  // Do not instrument the following packages at all,
    33  // at best instrumentation would cause infinite recursion.
    34  var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"}
    35  
    36  // Only insert racefuncenterfp/racefuncexit into the following packages.
    37  // Memory accesses in the packages are either uninteresting or will cause false positives.
    38  var norace_inst_pkgs = []string{"sync", "sync/atomic"}
    39  
    40  func ispkgin(pkgs []string) bool {
    41  	if myimportpath != "" {
    42  		for _, p := range pkgs {
    43  			if myimportpath == p {
    44  				return true
    45  			}
    46  		}
    47  	}
    48  
    49  	return false
    50  }
    51  
    52  func instrument(fn *Node) {
    53  	if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 {
    54  		return
    55  	}
    56  
    57  	if !flag_race || !ispkgin(norace_inst_pkgs) {
    58  		instrumentlist(fn.Nbody, nil)
    59  
    60  		// nothing interesting for race detector in fn->enter
    61  		instrumentlist(fn.Func.Exit, nil)
    62  	}
    63  
    64  	if flag_race {
    65  		// nodpc is the PC of the caller as extracted by
    66  		// getcallerpc. We use -widthptr(FP) for x86.
    67  		// BUG: this will not work on arm.
    68  		nodpc := *nodfp
    69  		nodpc.Type = Types[TUINTPTR]
    70  		nodpc.Xoffset = int64(-Widthptr)
    71  		nd := mkcall("racefuncenter", nil, nil, &nodpc)
    72  		fn.Func.Enter.Prepend(nd)
    73  		nd = mkcall("racefuncexit", nil, nil)
    74  		fn.Func.Exit.Append(nd)
    75  		fn.Func.Dcl = append(fn.Func.Dcl, &nodpc)
    76  	}
    77  
    78  	if Debug['W'] != 0 {
    79  		s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
    80  		dumplist(s, fn.Nbody)
    81  		s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
    82  		dumplist(s, fn.Func.Enter)
    83  		s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
    84  		dumplist(s, fn.Func.Exit)
    85  	}
    86  }
    87  
    88  func instrumentlist(l Nodes, init *Nodes) {
    89  	s := l.Slice()
    90  	for i := range s {
    91  		var instr Nodes
    92  		instrumentnode(&s[i], &instr, 0, 0)
    93  		if init == nil {
    94  			s[i].Ninit.AppendNodes(&instr)
    95  		} else {
    96  			init.AppendNodes(&instr)
    97  		}
    98  	}
    99  }
   100  
   101  // walkexpr and walkstmt combined
   102  // walks the tree and adds calls to the
   103  // instrumentation code to top-level (statement) nodes' init
   104  func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
   105  	n := *np
   106  
   107  	if n == nil {
   108  		return
   109  	}
   110  
   111  	if Debug['w'] > 1 {
   112  		Dump("instrument-before", n)
   113  	}
   114  	setlineno(n)
   115  	if init == nil {
   116  		Fatalf("instrument: bad init list")
   117  	}
   118  	if init == &n.Ninit {
   119  		// If init == &n->ninit and n->ninit is non-nil,
   120  		// instrumentnode might append it to itself.
   121  		// nil it out and handle it separately before putting it back.
   122  		l := n.Ninit
   123  
   124  		n.Ninit.Set(nil)
   125  		instrumentlist(l, nil)
   126  		instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit
   127  		appendinit(&n, l)
   128  		*np = n
   129  		return
   130  	}
   131  
   132  	instrumentlist(n.Ninit, nil)
   133  
   134  	switch n.Op {
   135  	default:
   136  		Fatalf("instrument: unknown node type %v", n.Op)
   137  
   138  	case OAS, OASWB, OAS2FUNC:
   139  		instrumentnode(&n.Left, init, 1, 0)
   140  		instrumentnode(&n.Right, init, 0, 0)
   141  		goto ret
   142  
   143  		// can't matter
   144  	case OCFUNC, OVARKILL, OVARLIVE:
   145  		goto ret
   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  		goto ret
   164  
   165  	case ODEFER:
   166  		instrumentnode(&n.Left, init, 0, 0)
   167  		goto ret
   168  
   169  	case OPROC:
   170  		instrumentnode(&n.Left, init, 0, 0)
   171  		goto ret
   172  
   173  	case OCALLINTER:
   174  		instrumentnode(&n.Left, init, 0, 0)
   175  		goto ret
   176  
   177  	// Instrument dst argument of runtime.writebarrier* calls
   178  	// as we do not instrument runtime code.
   179  	// typedslicecopy is instrumented in runtime.
   180  	case OCALLFUNC:
   181  		instrumentnode(&n.Left, init, 0, 0)
   182  		goto ret
   183  
   184  	case ONOT,
   185  		OMINUS,
   186  		OPLUS,
   187  		OREAL,
   188  		OIMAG,
   189  		OCOM,
   190  		OSQRT:
   191  		instrumentnode(&n.Left, init, wr, 0)
   192  		goto ret
   193  
   194  	case ODOTINTER:
   195  		instrumentnode(&n.Left, init, 0, 0)
   196  		goto ret
   197  
   198  	case ODOT:
   199  		instrumentnode(&n.Left, init, 0, 1)
   200  		callinstr(&n, init, wr, skip)
   201  		goto ret
   202  
   203  	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
   204  		instrumentnode(&n.Left, init, 0, 0)
   205  
   206  		callinstr(&n, init, wr, skip)
   207  		goto ret
   208  
   209  	case OIND: // *p
   210  		instrumentnode(&n.Left, init, 0, 0)
   211  
   212  		callinstr(&n, init, wr, skip)
   213  		goto ret
   214  
   215  	case OSPTR, OLEN, OCAP:
   216  		instrumentnode(&n.Left, init, 0, 0)
   217  		if n.Left.Type.IsMap() {
   218  			n1 := nod(OCONVNOP, n.Left, nil)
   219  			n1.Type = ptrto(Types[TUINT8])
   220  			n1 = nod(OIND, n1, nil)
   221  			n1 = typecheck(n1, Erv)
   222  			callinstr(&n1, init, 0, skip)
   223  		}
   224  
   225  		goto ret
   226  
   227  	case OLSH,
   228  		ORSH,
   229  		OLROT,
   230  		OAND,
   231  		OANDNOT,
   232  		OOR,
   233  		OXOR,
   234  		OSUB,
   235  		OMUL,
   236  		OHMUL,
   237  		OEQ,
   238  		ONE,
   239  		OLT,
   240  		OLE,
   241  		OGE,
   242  		OGT,
   243  		OADD,
   244  		OCOMPLEX:
   245  		instrumentnode(&n.Left, init, wr, 0)
   246  		instrumentnode(&n.Right, init, wr, 0)
   247  		goto ret
   248  
   249  	case OANDAND, OOROR:
   250  		instrumentnode(&n.Left, init, wr, 0)
   251  
   252  		// walk has ensured the node has moved to a location where
   253  		// side effects are safe.
   254  		// n->right may not be executed,
   255  		// so instrumentation goes to n->right->ninit, not init.
   256  		instrumentnode(&n.Right, &n.Right.Ninit, wr, 0)
   257  
   258  		goto ret
   259  
   260  	case ONAME:
   261  		callinstr(&n, init, wr, skip)
   262  		goto ret
   263  
   264  	case OCONV:
   265  		instrumentnode(&n.Left, init, wr, 0)
   266  		goto ret
   267  
   268  	case OCONVNOP:
   269  		instrumentnode(&n.Left, init, wr, 0)
   270  		goto ret
   271  
   272  	case ODIV, OMOD:
   273  		instrumentnode(&n.Left, init, wr, 0)
   274  		instrumentnode(&n.Right, init, wr, 0)
   275  		goto ret
   276  
   277  	case OINDEX:
   278  		if !n.Left.Type.IsArray() {
   279  			instrumentnode(&n.Left, init, 0, 0)
   280  		} else if !islvalue(n.Left) {
   281  			// index of unaddressable array, like Map[k][i].
   282  			instrumentnode(&n.Left, init, wr, 0)
   283  
   284  			instrumentnode(&n.Right, init, 0, 0)
   285  			goto ret
   286  		}
   287  
   288  		instrumentnode(&n.Right, init, 0, 0)
   289  		if !n.Left.Type.IsString() {
   290  			callinstr(&n, init, wr, skip)
   291  		}
   292  		goto ret
   293  
   294  	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
   295  		instrumentnode(&n.Left, init, 0, 0)
   296  		low, high, max := n.SliceBounds()
   297  		instrumentnode(&low, init, 0, 0)
   298  		instrumentnode(&high, init, 0, 0)
   299  		instrumentnode(&max, init, 0, 0)
   300  		n.SetSliceBounds(low, high, max)
   301  		goto ret
   302  
   303  	case OADDR:
   304  		instrumentnode(&n.Left, init, 0, 1)
   305  		goto ret
   306  
   307  		// n->left is Type* which is not interesting.
   308  	case OEFACE:
   309  		instrumentnode(&n.Right, init, 0, 0)
   310  
   311  		goto ret
   312  
   313  	case OITAB, OIDATA:
   314  		instrumentnode(&n.Left, init, 0, 0)
   315  		goto ret
   316  
   317  	case OSTRARRAYBYTETMP:
   318  		instrumentnode(&n.Left, init, 0, 0)
   319  		goto ret
   320  
   321  		// should not appear in AST by now
   322  	case OSEND,
   323  		ORECV,
   324  		OCLOSE,
   325  		ONEW,
   326  		OXCASE,
   327  		OXFALL,
   328  		OCASE,
   329  		OPANIC,
   330  		ORECOVER,
   331  		OCONVIFACE,
   332  		OCMPIFACE,
   333  		OMAKECHAN,
   334  		OMAKEMAP,
   335  		OMAKESLICE,
   336  		OCALL,
   337  		OCOPY,
   338  		OAPPEND,
   339  		ORUNESTR,
   340  		OARRAYBYTESTR,
   341  		OARRAYRUNESTR,
   342  		OSTRARRAYBYTE,
   343  		OSTRARRAYRUNE,
   344  		OINDEXMAP,
   345  		// lowered to call
   346  		OCMPSTR,
   347  		OADDSTR,
   348  		ODOTTYPE,
   349  		ODOTTYPE2,
   350  		OAS2DOTTYPE,
   351  		OCALLPART,
   352  		// lowered to PTRLIT
   353  		OCLOSURE,  // lowered to PTRLIT
   354  		ORANGE,    // lowered to ordinary for loop
   355  		OARRAYLIT, // lowered to assignments
   356  		OSLICELIT,
   357  		OMAPLIT,
   358  		OSTRUCTLIT,
   359  		OAS2,
   360  		OAS2RECV,
   361  		OAS2MAPR,
   362  		OASOP:
   363  		yyerror("instrument: %v must be lowered by now", n.Op)
   364  
   365  		goto ret
   366  
   367  		// impossible nodes: only appear in backend.
   368  	case ORROTC, OEXTEND:
   369  		yyerror("instrument: %v cannot exist now", n.Op)
   370  		goto ret
   371  
   372  	case OGETG:
   373  		yyerror("instrument: OGETG can happen only in runtime which we don't instrument")
   374  		goto ret
   375  
   376  	case OFOR:
   377  		if n.Left != nil {
   378  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   379  		}
   380  		if n.Right != nil {
   381  			instrumentnode(&n.Right, &n.Right.Ninit, 0, 0)
   382  		}
   383  		goto ret
   384  
   385  	case OIF, OSWITCH:
   386  		if n.Left != nil {
   387  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   388  		}
   389  		goto ret
   390  
   391  		// just do generic traversal
   392  	case OCALLMETH,
   393  		ORETURN,
   394  		ORETJMP,
   395  		OSELECT,
   396  		OEMPTY,
   397  		OBREAK,
   398  		OCONTINUE,
   399  		OFALL,
   400  		OGOTO,
   401  		OLABEL:
   402  		goto ret
   403  
   404  		// does not require instrumentation
   405  	case OPRINT, // don't bother instrumenting it
   406  		OPRINTN,     // don't bother instrumenting it
   407  		OCHECKNIL,   // always followed by a read.
   408  		OCLOSUREVAR, // immutable pointer to captured variable
   409  		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
   410  		OINDREGSP,   // at this stage, only n(SP) nodes from nodarg
   411  		ODCL,        // declarations (without value) cannot be races
   412  		ODCLCONST,
   413  		ODCLTYPE,
   414  		OTYPE,
   415  		ONONAME,
   416  		OLITERAL,
   417  		OTYPESW: // ignored by code generation, do not instrument.
   418  		goto ret
   419  	}
   420  
   421  ret:
   422  	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
   423  		instrumentlist(n.List, init)
   424  	}
   425  	instrumentlist(n.Nbody, nil)
   426  	instrumentlist(n.Rlist, nil)
   427  	*np = n
   428  }
   429  
   430  func isartificial(n *Node) bool {
   431  	// compiler-emitted artificial things that we do not want to instrument,
   432  	// can't possibly participate in a data race.
   433  	// can't be seen by C/C++ and therefore irrelevant for msan.
   434  	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
   435  		if n.Sym.Name == "_" {
   436  			return true
   437  		}
   438  
   439  		// autotmp's are always local
   440  		if n.IsAutoTmp() {
   441  			return true
   442  		}
   443  
   444  		// statictmp's are read-only
   445  		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
   446  			return true
   447  		}
   448  
   449  		// go.itab is accessed only by the compiler and runtime (assume safe)
   450  		if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
   451  			return true
   452  		}
   453  	}
   454  
   455  	return false
   456  }
   457  
   458  func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
   459  	n := *np
   460  
   461  	//fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n",
   462  	//	n, n.Op, n.Type.Etype, n.Class)
   463  
   464  	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
   465  		return false
   466  	}
   467  	t := n.Type
   468  	if isartificial(n) {
   469  		return false
   470  	}
   471  
   472  	b := outervalue(n)
   473  
   474  	// it skips e.g. stores to ... parameter array
   475  	if isartificial(b) {
   476  		return false
   477  	}
   478  	class := b.Class
   479  
   480  	// BUG: we _may_ want to instrument PAUTO sometimes
   481  	// e.g. if we've got a local variable/method receiver
   482  	// that has got a pointer inside. Whether it points to
   483  	// the heap or not is impossible to know at compile time
   484  	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
   485  		hascalls := 0
   486  		foreach(n, hascallspred, &hascalls)
   487  		if hascalls != 0 {
   488  			n = detachexpr(n, init)
   489  			*np = n
   490  		}
   491  
   492  		n = treecopy(n, 0)
   493  		makeaddable(n)
   494  		var f *Node
   495  		if flag_msan {
   496  			name := "msanread"
   497  			if wr != 0 {
   498  				name = "msanwrite"
   499  			}
   500  			// dowidth may not have been called for PEXTERN.
   501  			dowidth(t)
   502  			w := t.Width
   503  			if w == BADWIDTH {
   504  				Fatalf("instrument: %v badwidth", t)
   505  			}
   506  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   507  		} else if flag_race && (t.IsStruct() || t.IsArray()) {
   508  			name := "racereadrange"
   509  			if wr != 0 {
   510  				name = "racewriterange"
   511  			}
   512  			// dowidth may not have been called for PEXTERN.
   513  			dowidth(t)
   514  			w := t.Width
   515  			if w == BADWIDTH {
   516  				Fatalf("instrument: %v badwidth", t)
   517  			}
   518  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   519  		} else if flag_race {
   520  			name := "raceread"
   521  			if wr != 0 {
   522  				name = "racewrite"
   523  			}
   524  			f = mkcall(name, nil, init, uintptraddr(n))
   525  		}
   526  
   527  		init.Append(f)
   528  		return true
   529  	}
   530  
   531  	return false
   532  }
   533  
   534  // makeaddable returns a node whose memory location is the
   535  // same as n, but which is addressable in the Go language
   536  // sense.
   537  // This is different from functions like cheapexpr that may make
   538  // a copy of their argument.
   539  func makeaddable(n *Node) {
   540  	// The arguments to uintptraddr technically have an address but
   541  	// may not be addressable in the Go sense: for example, in the case
   542  	// of T(v).Field where T is a struct type and v is
   543  	// an addressable value.
   544  	switch n.Op {
   545  	case OINDEX:
   546  		if n.Left.Type.IsArray() {
   547  			makeaddable(n.Left)
   548  		}
   549  
   550  		// Turn T(v).Field into v.Field
   551  	case ODOT, OXDOT:
   552  		if n.Left.Op == OCONVNOP {
   553  			n.Left = n.Left.Left
   554  		}
   555  		makeaddable(n.Left)
   556  
   557  		// nothing to do
   558  	case ODOTPTR:
   559  		fallthrough
   560  	default:
   561  		break
   562  	}
   563  }
   564  
   565  func uintptraddr(n *Node) *Node {
   566  	r := nod(OADDR, n, nil)
   567  	r.Bounded = true
   568  	r = conv(r, Types[TUNSAFEPTR])
   569  	r = conv(r, Types[TUINTPTR])
   570  	return r
   571  }
   572  
   573  func detachexpr(n *Node, init *Nodes) *Node {
   574  	addr := nod(OADDR, n, nil)
   575  	l := temp(ptrto(n.Type))
   576  	as := nod(OAS, l, addr)
   577  	as = typecheck(as, Etop)
   578  	as = walkexpr(as, init)
   579  	init.Append(as)
   580  	ind := nod(OIND, l, nil)
   581  	ind = typecheck(ind, Erv)
   582  	ind = walkexpr(ind, init)
   583  	return ind
   584  }
   585  
   586  func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
   587  	if n != nil {
   588  		f(n, c)
   589  	}
   590  }
   591  
   592  func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
   593  	for _, n := range l.Slice() {
   594  		foreachnode(n, f, c)
   595  	}
   596  }
   597  
   598  func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
   599  	foreachlist(n.Ninit, f, c)
   600  	foreachnode(n.Left, f, c)
   601  	foreachnode(n.Right, f, c)
   602  	foreachlist(n.List, f, c)
   603  	foreachlist(n.Nbody, f, c)
   604  	foreachlist(n.Rlist, f, c)
   605  }
   606  
   607  func hascallspred(n *Node, c interface{}) {
   608  	switch n.Op {
   609  	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
   610  		(*c.(*int))++
   611  	}
   612  }
   613  
   614  // appendinit is like addinit in subr.go
   615  // but appends rather than prepends.
   616  func appendinit(np **Node, init Nodes) {
   617  	if init.Len() == 0 {
   618  		return
   619  	}
   620  
   621  	n := *np
   622  	switch n.Op {
   623  	// There may be multiple refs to this node;
   624  	// introduce OCONVNOP to hold init list.
   625  	case ONAME, OLITERAL:
   626  		n = nod(OCONVNOP, n, nil)
   627  
   628  		n.Type = n.Left.Type
   629  		n.Typecheck = 1
   630  		*np = n
   631  	}
   632  
   633  	n.Ninit.AppendNodes(&init)
   634  	n.Ullman = UINF
   635  }