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