github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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/internal/src"
     9  	"fmt"
    10  	"strings"
    11  )
    12  
    13  // The instrument pass modifies the code tree for instrumentation.
    14  //
    15  // For flag_race it modifies the function as follows:
    16  //
    17  // 1. It inserts a call to racefuncenterfp at the beginning of each function.
    18  // 2. It inserts a call to racefuncexit at the end of each function.
    19  // 3. It inserts a call to raceread before each memory read.
    20  // 4. It inserts a call to racewrite before each memory write.
    21  //
    22  // For flag_msan:
    23  //
    24  // 1. It inserts a call to msanread before each memory read.
    25  // 2. It inserts a call to msanwrite before each memory write.
    26  //
    27  // The rewriting is not yet complete. Certain nodes are not rewritten
    28  // but should be.
    29  
    30  // TODO(dvyukov): do not instrument initialization as writes:
    31  // a := make([]int, 10)
    32  
    33  // Do not instrument the following packages at all,
    34  // at best instrumentation would cause infinite recursion.
    35  var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"}
    36  
    37  // Only insert racefuncenterfp/racefuncexit into the following packages.
    38  // Memory accesses in the packages are either uninteresting or will cause false positives.
    39  var norace_inst_pkgs = []string{"sync", "sync/atomic"}
    40  
    41  func ispkgin(pkgs []string) bool {
    42  	if myimportpath != "" {
    43  		for _, p := range pkgs {
    44  			if myimportpath == p {
    45  				return true
    46  			}
    47  		}
    48  	}
    49  
    50  	return false
    51  }
    52  
    53  func instrument(fn *Node) {
    54  	if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 {
    55  		return
    56  	}
    57  
    58  	if !flag_race || !ispkgin(norace_inst_pkgs) {
    59  		instrumentlist(fn.Nbody, nil)
    60  
    61  		// nothing interesting for race detector in fn->enter
    62  		instrumentlist(fn.Func.Exit, nil)
    63  	}
    64  
    65  	if flag_race {
    66  		// nodpc is the PC of the caller as extracted by
    67  		// getcallerpc. We use -widthptr(FP) for x86.
    68  		// BUG: this will not work on arm.
    69  		nodpc := *nodfp
    70  		nodpc.Type = Types[TUINTPTR]
    71  		nodpc.Xoffset = int64(-Widthptr)
    72  		nd := mkcall("racefuncenter", nil, nil, &nodpc)
    73  		fn.Func.Enter.Prepend(nd)
    74  		nd = mkcall("racefuncexit", nil, nil)
    75  		fn.Func.Exit.Append(nd)
    76  		fn.Func.Dcl = append(fn.Func.Dcl, &nodpc)
    77  	}
    78  
    79  	if Debug['W'] != 0 {
    80  		s := fmt.Sprintf("after instrument %v", fn.Func.Nname.Sym)
    81  		dumplist(s, fn.Nbody)
    82  		s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
    83  		dumplist(s, fn.Func.Enter)
    84  		s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
    85  		dumplist(s, fn.Func.Exit)
    86  	}
    87  }
    88  
    89  func instrumentlist(l Nodes, init *Nodes) {
    90  	s := l.Slice()
    91  	for i := range s {
    92  		var instr Nodes
    93  		instrumentnode(&s[i], &instr, 0, 0)
    94  		if init == nil {
    95  			s[i].Ninit.AppendNodes(&instr)
    96  		} else {
    97  			init.AppendNodes(&instr)
    98  		}
    99  	}
   100  }
   101  
   102  // walkexpr and walkstmt combined
   103  // walks the tree and adds calls to the
   104  // instrumentation code to top-level (statement) nodes' init
   105  func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
   106  	n := *np
   107  
   108  	if n == nil {
   109  		return
   110  	}
   111  
   112  	if Debug['w'] > 1 {
   113  		Dump("instrument-before", n)
   114  	}
   115  	setlineno(n)
   116  	if init == nil {
   117  		Fatalf("instrument: bad init list")
   118  	}
   119  	if init == &n.Ninit {
   120  		// If init == &n->ninit and n->ninit is non-nil,
   121  		// instrumentnode might append it to itself.
   122  		// nil it out and handle it separately before putting it back.
   123  		l := n.Ninit
   124  
   125  		n.Ninit.Set(nil)
   126  		instrumentlist(l, nil)
   127  		instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit
   128  		appendinit(&n, l)
   129  		*np = n
   130  		return
   131  	}
   132  
   133  	instrumentlist(n.Ninit, nil)
   134  
   135  	switch n.Op {
   136  	default:
   137  		Fatalf("instrument: unknown node type %v", n.Op)
   138  
   139  	case OAS, OAS2FUNC:
   140  		instrumentnode(&n.Left, init, 1, 0)
   141  		instrumentnode(&n.Right, init, 0, 0)
   142  		goto ret
   143  
   144  		// can't matter
   145  	case OCFUNC, OVARKILL, OVARLIVE:
   146  		goto ret
   147  
   148  	case OBLOCK:
   149  		ls := n.List.Slice()
   150  		afterCall := false
   151  		for i := range ls {
   152  			op := ls[i].Op
   153  			// Scan past OAS nodes copying results off stack.
   154  			// Those must not be instrumented, because the
   155  			// instrumentation calls will smash the results.
   156  			// The assignments are to temporaries, so they cannot
   157  			// be involved in races and need not be instrumented.
   158  			if afterCall && op == OAS && iscallret(ls[i].Right) {
   159  				continue
   160  			}
   161  			instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
   162  			afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER)
   163  		}
   164  		goto ret
   165  
   166  	case ODEFER:
   167  		instrumentnode(&n.Left, init, 0, 0)
   168  		goto ret
   169  
   170  	case OPROC:
   171  		instrumentnode(&n.Left, init, 0, 0)
   172  		goto ret
   173  
   174  	case OCALLINTER:
   175  		instrumentnode(&n.Left, init, 0, 0)
   176  		goto ret
   177  
   178  	// Instrument dst argument of runtime.writebarrier* calls
   179  	// as we do not instrument runtime code.
   180  	// typedslicecopy is instrumented in runtime.
   181  	case OCALLFUNC:
   182  		instrumentnode(&n.Left, init, 0, 0)
   183  		goto ret
   184  
   185  	case ONOT,
   186  		OMINUS,
   187  		OPLUS,
   188  		OREAL,
   189  		OIMAG,
   190  		OCOM:
   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  		OAND,
   230  		OANDNOT,
   231  		OOR,
   232  		OXOR,
   233  		OSUB,
   234  		OMUL,
   235  		OHMUL,
   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  		yyerror("instrument: %v must be lowered by now", n.Op)
   369  
   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, src.NoXPos)
   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  }