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