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