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