github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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  	case OAS2DOTTYPE:
   322  		instrumentnode(&n.Left, init, 1, 0)
   323  		instrumentnode(&n.Right, init, 0, 0)
   324  		goto ret
   325  
   326  	case ODOTTYPE, ODOTTYPE2:
   327  		instrumentnode(&n.Left, init, 0, 0)
   328  		goto ret
   329  
   330  		// should not appear in AST by now
   331  	case OSEND,
   332  		ORECV,
   333  		OCLOSE,
   334  		ONEW,
   335  		OXCASE,
   336  		OXFALL,
   337  		OCASE,
   338  		OPANIC,
   339  		ORECOVER,
   340  		OCONVIFACE,
   341  		OCMPIFACE,
   342  		OMAKECHAN,
   343  		OMAKEMAP,
   344  		OMAKESLICE,
   345  		OCALL,
   346  		OCOPY,
   347  		OAPPEND,
   348  		ORUNESTR,
   349  		OARRAYBYTESTR,
   350  		OARRAYRUNESTR,
   351  		OSTRARRAYBYTE,
   352  		OSTRARRAYRUNE,
   353  		OINDEXMAP,
   354  		// lowered to call
   355  		OCMPSTR,
   356  		OADDSTR,
   357  		OCALLPART,
   358  		// lowered to PTRLIT
   359  		OCLOSURE,  // lowered to PTRLIT
   360  		ORANGE,    // lowered to ordinary for loop
   361  		OARRAYLIT, // lowered to assignments
   362  		OSLICELIT,
   363  		OMAPLIT,
   364  		OSTRUCTLIT,
   365  		OAS2,
   366  		OAS2RECV,
   367  		OAS2MAPR,
   368  		OASOP:
   369  		yyerror("instrument: %v must be lowered by now", n.Op)
   370  
   371  		goto ret
   372  
   373  		// impossible nodes: only appear in backend.
   374  	case ORROTC, OEXTEND:
   375  		yyerror("instrument: %v cannot exist now", n.Op)
   376  		goto ret
   377  
   378  	case OGETG:
   379  		yyerror("instrument: OGETG can happen only in runtime which we don't instrument")
   380  		goto ret
   381  
   382  	case OFOR:
   383  		if n.Left != nil {
   384  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   385  		}
   386  		if n.Right != nil {
   387  			instrumentnode(&n.Right, &n.Right.Ninit, 0, 0)
   388  		}
   389  		goto ret
   390  
   391  	case OIF, OSWITCH:
   392  		if n.Left != nil {
   393  			instrumentnode(&n.Left, &n.Left.Ninit, 0, 0)
   394  		}
   395  		goto ret
   396  
   397  		// just do generic traversal
   398  	case OCALLMETH,
   399  		ORETURN,
   400  		ORETJMP,
   401  		OSELECT,
   402  		OEMPTY,
   403  		OBREAK,
   404  		OCONTINUE,
   405  		OFALL,
   406  		OGOTO,
   407  		OLABEL:
   408  		goto ret
   409  
   410  		// does not require instrumentation
   411  	case OPRINT, // don't bother instrumenting it
   412  		OPRINTN,     // don't bother instrumenting it
   413  		OCHECKNIL,   // always followed by a read.
   414  		OCLOSUREVAR, // immutable pointer to captured variable
   415  		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
   416  		OINDREGSP,   // at this stage, only n(SP) nodes from nodarg
   417  		ODCL,        // declarations (without value) cannot be races
   418  		ODCLCONST,
   419  		ODCLTYPE,
   420  		OTYPE,
   421  		ONONAME,
   422  		OLITERAL,
   423  		OTYPESW: // ignored by code generation, do not instrument.
   424  		goto ret
   425  	}
   426  
   427  ret:
   428  	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
   429  		instrumentlist(n.List, init)
   430  	}
   431  	instrumentlist(n.Nbody, nil)
   432  	instrumentlist(n.Rlist, nil)
   433  	*np = n
   434  }
   435  
   436  func isartificial(n *Node) bool {
   437  	// compiler-emitted artificial things that we do not want to instrument,
   438  	// can't possibly participate in a data race.
   439  	// can't be seen by C/C++ and therefore irrelevant for msan.
   440  	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
   441  		if n.Sym.Name == "_" {
   442  			return true
   443  		}
   444  
   445  		// autotmp's are always local
   446  		if n.IsAutoTmp() {
   447  			return true
   448  		}
   449  
   450  		// statictmp's are read-only
   451  		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
   452  			return true
   453  		}
   454  
   455  		// go.itab is accessed only by the compiler and runtime (assume safe)
   456  		if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
   457  			return true
   458  		}
   459  	}
   460  
   461  	return false
   462  }
   463  
   464  func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
   465  	n := *np
   466  
   467  	//fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n",
   468  	//	n, n.Op, n.Type.Etype, n.Class)
   469  
   470  	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
   471  		return false
   472  	}
   473  	t := n.Type
   474  	if isartificial(n) {
   475  		return false
   476  	}
   477  
   478  	b := outervalue(n)
   479  
   480  	// it skips e.g. stores to ... parameter array
   481  	if isartificial(b) {
   482  		return false
   483  	}
   484  	class := b.Class
   485  
   486  	// BUG: we _may_ want to instrument PAUTO sometimes
   487  	// e.g. if we've got a local variable/method receiver
   488  	// that has got a pointer inside. Whether it points to
   489  	// the heap or not is impossible to know at compile time
   490  	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
   491  		hascalls := 0
   492  		foreach(n, hascallspred, &hascalls)
   493  		if hascalls != 0 {
   494  			n = detachexpr(n, init)
   495  			*np = n
   496  		}
   497  
   498  		n = treecopy(n, 0)
   499  		makeaddable(n)
   500  		var f *Node
   501  		if flag_msan {
   502  			name := "msanread"
   503  			if wr != 0 {
   504  				name = "msanwrite"
   505  			}
   506  			// dowidth may not have been called for PEXTERN.
   507  			dowidth(t)
   508  			w := t.Width
   509  			if w == BADWIDTH {
   510  				Fatalf("instrument: %v badwidth", t)
   511  			}
   512  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   513  		} else if flag_race && (t.IsStruct() || t.IsArray()) {
   514  			name := "racereadrange"
   515  			if wr != 0 {
   516  				name = "racewriterange"
   517  			}
   518  			// dowidth may not have been called for PEXTERN.
   519  			dowidth(t)
   520  			w := t.Width
   521  			if w == BADWIDTH {
   522  				Fatalf("instrument: %v badwidth", t)
   523  			}
   524  			f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
   525  		} else if flag_race {
   526  			name := "raceread"
   527  			if wr != 0 {
   528  				name = "racewrite"
   529  			}
   530  			f = mkcall(name, nil, init, uintptraddr(n))
   531  		}
   532  
   533  		init.Append(f)
   534  		return true
   535  	}
   536  
   537  	return false
   538  }
   539  
   540  // makeaddable returns a node whose memory location is the
   541  // same as n, but which is addressable in the Go language
   542  // sense.
   543  // This is different from functions like cheapexpr that may make
   544  // a copy of their argument.
   545  func makeaddable(n *Node) {
   546  	// The arguments to uintptraddr technically have an address but
   547  	// may not be addressable in the Go sense: for example, in the case
   548  	// of T(v).Field where T is a struct type and v is
   549  	// an addressable value.
   550  	switch n.Op {
   551  	case OINDEX:
   552  		if n.Left.Type.IsArray() {
   553  			makeaddable(n.Left)
   554  		}
   555  
   556  		// Turn T(v).Field into v.Field
   557  	case ODOT, OXDOT:
   558  		if n.Left.Op == OCONVNOP {
   559  			n.Left = n.Left.Left
   560  		}
   561  		makeaddable(n.Left)
   562  
   563  		// nothing to do
   564  	case ODOTPTR:
   565  		fallthrough
   566  	default:
   567  		break
   568  	}
   569  }
   570  
   571  func uintptraddr(n *Node) *Node {
   572  	r := nod(OADDR, n, nil)
   573  	r.Bounded = true
   574  	r = conv(r, Types[TUNSAFEPTR])
   575  	r = conv(r, Types[TUINTPTR])
   576  	return r
   577  }
   578  
   579  func detachexpr(n *Node, init *Nodes) *Node {
   580  	addr := nod(OADDR, n, nil)
   581  	l := temp(ptrto(n.Type))
   582  	as := nod(OAS, l, addr)
   583  	as = typecheck(as, Etop)
   584  	as = walkexpr(as, init)
   585  	init.Append(as)
   586  	ind := nod(OIND, l, nil)
   587  	ind = typecheck(ind, Erv)
   588  	ind = walkexpr(ind, init)
   589  	return ind
   590  }
   591  
   592  func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
   593  	if n != nil {
   594  		f(n, c)
   595  	}
   596  }
   597  
   598  func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
   599  	for _, n := range l.Slice() {
   600  		foreachnode(n, f, c)
   601  	}
   602  }
   603  
   604  func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
   605  	foreachlist(n.Ninit, f, c)
   606  	foreachnode(n.Left, f, c)
   607  	foreachnode(n.Right, f, c)
   608  	foreachlist(n.List, f, c)
   609  	foreachlist(n.Nbody, f, c)
   610  	foreachlist(n.Rlist, f, c)
   611  }
   612  
   613  func hascallspred(n *Node, c interface{}) {
   614  	switch n.Op {
   615  	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
   616  		(*c.(*int))++
   617  	}
   618  }
   619  
   620  // appendinit is like addinit in subr.go
   621  // but appends rather than prepends.
   622  func appendinit(np **Node, init Nodes) {
   623  	if init.Len() == 0 {
   624  		return
   625  	}
   626  
   627  	n := *np
   628  	switch n.Op {
   629  	// There may be multiple refs to this node;
   630  	// introduce OCONVNOP to hold init list.
   631  	case ONAME, OLITERAL:
   632  		n = nod(OCONVNOP, n, nil)
   633  
   634  		n.Type = n.Left.Type
   635  		n.Typecheck = 1
   636  		*np = n
   637  	}
   638  
   639  	n.Ninit.AppendNodes(&init)
   640  	n.Ullman = UINF
   641  }