github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 OSPTR:
   242  	case OLEN:
   243  	case OCAP:
   244  		racewalknode(&n->left, init, 0, 0);
   245  		if(istype(n->left->type, TMAP)) {
   246  			n1 = nod(OCONVNOP, n->left, N);
   247  			n1->type = ptrto(types[TUINT8]);
   248  			n1 = nod(OIND, n1, N);
   249  			typecheck(&n1, Erv);
   250  			callinstr(&n1, init, 0, skip);
   251  		}
   252  		goto ret;
   253  
   254  	case OLSH:
   255  	case ORSH:
   256  	case OLROT:
   257  	case OAND:
   258  	case OANDNOT:
   259  	case OOR:
   260  	case OXOR:
   261  	case OSUB:
   262  	case OMUL:
   263  	case OHMUL:
   264  	case OEQ:
   265  	case ONE:
   266  	case OLT:
   267  	case OLE:
   268  	case OGE:
   269  	case OGT:
   270  	case OADD:
   271  	case OCOMPLEX:
   272  		racewalknode(&n->left, init, wr, 0);
   273  		racewalknode(&n->right, init, wr, 0);
   274  		goto ret;
   275  
   276  	case OANDAND:
   277  	case OOROR:
   278  		racewalknode(&n->left, init, wr, 0);
   279  		// walk has ensured the node has moved to a location where
   280  		// side effects are safe.
   281  		// n->right may not be executed,
   282  		// so instrumentation goes to n->right->ninit, not init.
   283  		racewalknode(&n->right, &n->right->ninit, wr, 0);
   284  		goto ret;
   285  
   286  	case ONAME:
   287  		callinstr(&n, init, wr, skip);
   288  		goto ret;
   289  
   290  	case OCONV:
   291  		racewalknode(&n->left, init, wr, 0);
   292  		goto ret;
   293  
   294  	case OCONVNOP:
   295  		racewalknode(&n->left, init, wr, 0);
   296  		goto ret;
   297  
   298  	case ODIV:
   299  	case OMOD:
   300  		racewalknode(&n->left, init, wr, 0);
   301  		racewalknode(&n->right, init, wr, 0);
   302  		goto ret;
   303  
   304  	case OINDEX:
   305  		if(!isfixedarray(n->left->type))
   306  			racewalknode(&n->left, init, 0, 0);
   307  		else if(!islvalue(n->left)) {
   308  			// index of unaddressable array, like Map[k][i].
   309  			racewalknode(&n->left, init, wr, 0);
   310  			racewalknode(&n->right, init, 0, 0);
   311  			goto ret;
   312  		}
   313  		racewalknode(&n->right, init, 0, 0);
   314  		if(n->left->type->etype != TSTRING)
   315  			callinstr(&n, init, wr, skip);
   316  		goto ret;
   317  
   318  	case OSLICE:
   319  	case OSLICEARR:
   320  	case OSLICE3:
   321  	case OSLICE3ARR:
   322  		// Seems to only lead to double instrumentation.
   323  		//racewalknode(&n->left, init, 0, 0);
   324  		goto ret;
   325  
   326  	case OADDR:
   327  		racewalknode(&n->left, init, 0, 1);
   328  		goto ret;
   329  
   330  	case OEFACE:
   331  		racewalknode(&n->left, init, 0, 0);
   332  		racewalknode(&n->right, init, 0, 0);
   333  		goto ret;
   334  
   335  	case OITAB:
   336  		racewalknode(&n->left, init, 0, 0);
   337  		goto ret;
   338  
   339  	// should not appear in AST by now
   340  	case OSEND:
   341  	case ORECV:
   342  	case OCLOSE:
   343  	case ONEW:
   344  	case OXCASE:
   345  	case OXFALL:
   346  	case OCASE:
   347  	case OPANIC:
   348  	case ORECOVER:
   349  	case OCONVIFACE:
   350  	case OCMPIFACE:
   351  	case OMAKECHAN:
   352  	case OMAKEMAP:
   353  	case OMAKESLICE:
   354  	case OCALL:
   355  	case OCOPY:
   356  	case OAPPEND:
   357  	case ORUNESTR:
   358  	case OARRAYBYTESTR:
   359  	case OARRAYRUNESTR:
   360  	case OSTRARRAYBYTE:
   361  	case OSTRARRAYRUNE:
   362  	case OINDEXMAP:  // lowered to call
   363  	case OCMPSTR:
   364  	case OADDSTR:
   365  	case ODOTTYPE:
   366  	case ODOTTYPE2:
   367  	case OAS2DOTTYPE:
   368  	case OCALLPART: // lowered to PTRLIT
   369  	case OCLOSURE:  // lowered to PTRLIT
   370  	case ORANGE:    // lowered to ordinary for loop
   371  	case OARRAYLIT: // lowered to assignments
   372  	case OMAPLIT:
   373  	case OSTRUCTLIT:
   374  		yyerror("racewalk: %O must be lowered by now", n->op);
   375  		goto ret;
   376  
   377  	// impossible nodes: only appear in backend.
   378  	case ORROTC:
   379  	case OEXTEND:
   380  		yyerror("racewalk: %O cannot exist now", n->op);
   381  		goto ret;
   382  
   383  	// just do generic traversal
   384  	case OFOR:
   385  	case OIF:
   386  	case OCALLMETH:
   387  	case ORETURN:
   388  	case ORETJMP:
   389  	case OSWITCH:
   390  	case OSELECT:
   391  	case OEMPTY:
   392  	case OBREAK:
   393  	case OCONTINUE:
   394  	case OFALL:
   395  	case OGOTO:
   396  	case OLABEL:
   397  		goto ret;
   398  
   399  	// does not require instrumentation
   400  	case OPRINT:     // don't bother instrumenting it
   401  	case OPRINTN:    // don't bother instrumenting it
   402  	case OCHECKNIL: // always followed by a read.
   403  	case OPARAM:     // it appears only in fn->exit to copy heap params back
   404  	case OCLOSUREVAR:// immutable pointer to captured variable
   405  	case ODOTMETH:   // either part of CALLMETH or CALLPART (lowered to PTRLIT)
   406  	case OINDREG:    // at this stage, only n(SP) nodes from nodarg
   407  	case ODCL:       // declarations (without value) cannot be races
   408  	case ODCLCONST:
   409  	case ODCLTYPE:
   410  	case OTYPE:
   411  	case ONONAME:
   412  	case OLITERAL:
   413  	case OSLICESTR:  // always preceded by bounds checking, avoid double instrumentation.
   414  	case OTYPESW:    // ignored by code generation, do not instrument.
   415  		goto ret;
   416  	}
   417  
   418  ret:
   419  	if(n->op != OBLOCK)  // OBLOCK is handled above in a special way.
   420  		racewalklist(n->list, init);
   421  	racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
   422  	racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
   423  	racewalklist(n->nbody, nil);
   424  	racewalklist(n->nelse, nil);
   425  	racewalklist(n->rlist, nil);
   426  	*np = n;
   427  }
   428  
   429  static int
   430  isartificial(Node *n)
   431  {
   432  	// compiler-emitted artificial things that we do not want to instrument,
   433  	// cant' possibly participate in a data race.
   434  	if(n->op == ONAME && n->sym != S && n->sym->name != nil) {
   435  		if(strcmp(n->sym->name, "_") == 0)
   436  			return 1;
   437  		// autotmp's are always local
   438  		if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0)
   439  			return 1;
   440  		// statictmp's are read-only
   441  		if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0)
   442  			return 1;
   443  		// go.itab is accessed only by the compiler and runtime (assume safe)
   444  		if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0)
   445  			return 1;
   446  	}
   447  	return 0;
   448  }
   449  
   450  static int
   451  callinstr(Node **np, NodeList **init, int wr, int skip)
   452  {
   453  	Node *f, *b, *n;
   454  	Type *t;
   455  	int class, hascalls;
   456  
   457  	n = *np;
   458  	//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
   459  	//	  n, n->op, n->type ? n->type->etype : -1, n->class);
   460  
   461  	if(skip || n->type == T || n->type->etype >= TIDEAL)
   462  		return 0;
   463  	t = n->type;
   464  	if(isartificial(n))
   465  		return 0;
   466  
   467  	b = basenod(n);
   468  	// it skips e.g. stores to ... parameter array
   469  	if(isartificial(b))
   470  		return 0;
   471  	class = b->class;
   472  	// BUG: we _may_ want to instrument PAUTO sometimes
   473  	// e.g. if we've got a local variable/method receiver
   474  	// that has got a pointer inside. Whether it points to
   475  	// the heap or not is impossible to know at compile time
   476  	if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
   477  		|| b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
   478  		hascalls = 0;
   479  		foreach(n, hascallspred, &hascalls);
   480  		if(hascalls) {
   481  			n = detachexpr(n, init);
   482  			*np = n;
   483  		}
   484  		n = treecopy(n);
   485  		makeaddable(n);
   486  		if(t->etype == TSTRUCT || isfixedarray(t)) {
   487  			f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n),
   488  					nodintconst(t->width));
   489  		} else
   490  			f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
   491  		*init = list(*init, f);
   492  		return 1;
   493  	}
   494  	return 0;
   495  }
   496  
   497  // makeaddable returns a node whose memory location is the
   498  // same as n, but which is addressable in the Go language
   499  // sense.
   500  // This is different from functions like cheapexpr that may make
   501  // a copy of their argument.
   502  static void
   503  makeaddable(Node *n)
   504  {
   505  	// The arguments to uintptraddr technically have an address but
   506  	// may not be addressable in the Go sense: for example, in the case
   507  	// of T(v).Field where T is a struct type and v is
   508  	// an addressable value.
   509  	switch(n->op) {
   510  	case OINDEX:
   511  		if(isfixedarray(n->left->type))
   512  			makeaddable(n->left);
   513  		break;
   514  	case ODOT:
   515  	case OXDOT:
   516  		// Turn T(v).Field into v.Field
   517  		if(n->left->op == OCONVNOP)
   518  			n->left = n->left->left;
   519  		makeaddable(n->left);
   520  		break;
   521  	case ODOTPTR:
   522  	default:
   523  		// nothing to do
   524  		break;
   525  	}
   526  }
   527  
   528  static Node*
   529  uintptraddr(Node *n)
   530  {
   531  	Node *r;
   532  
   533  	r = nod(OADDR, n, N);
   534  	r->bounded = 1;
   535  	r = conv(r, types[TUNSAFEPTR]);
   536  	r = conv(r, types[TUINTPTR]);
   537  	return r;
   538  }
   539  
   540  // basenod returns the simplest child node of n pointing to the same
   541  // memory area.
   542  static Node*
   543  basenod(Node *n)
   544  {
   545  	for(;;) {
   546  		if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) {
   547  			n = n->left;
   548  			continue;
   549  		}
   550  		if(n->op == OINDEX && isfixedarray(n->type)) {
   551  			n = n->left;
   552  			continue;
   553  		}
   554  		break;
   555  	}
   556  	return n;
   557  }
   558  
   559  static Node*
   560  detachexpr(Node *n, NodeList **init)
   561  {
   562  	Node *addr, *as, *ind, *l;
   563  
   564  	addr = nod(OADDR, n, N);
   565  	l = temp(ptrto(n->type));
   566  	as = nod(OAS, l, addr);
   567  	typecheck(&as, Etop);
   568  	walkexpr(&as, init);
   569  	*init = list(*init, as);
   570  	ind = nod(OIND, l, N);
   571  	typecheck(&ind, Erv);
   572  	walkexpr(&ind, init);
   573  	return ind;
   574  }
   575  
   576  static void
   577  foreachnode(Node *n, void(*f)(Node*, void*), void *c)
   578  {
   579  	if(n)
   580  		f(n, c);
   581  }
   582  
   583  static void
   584  foreachlist(NodeList *l, void(*f)(Node*, void*), void *c)
   585  {
   586  	for(; l; l = l->next)
   587  		foreachnode(l->n, f, c);
   588  }
   589  
   590  static void
   591  foreach(Node *n, void(*f)(Node*, void*), void *c)
   592  {
   593  	foreachlist(n->ninit, f, c);
   594  	foreachnode(n->left, f, c);
   595  	foreachnode(n->right, f, c);
   596  	foreachlist(n->list, f, c);
   597  	foreachnode(n->ntest, f, c);
   598  	foreachnode(n->nincr, f, c);
   599  	foreachlist(n->nbody, f, c);
   600  	foreachlist(n->nelse, f, c);
   601  	foreachlist(n->rlist, f, c);
   602  }
   603  
   604  static void
   605  hascallspred(Node *n, void *c)
   606  {
   607  	switch(n->op) {
   608  	case OCALL:
   609  	case OCALLFUNC:
   610  	case OCALLMETH:
   611  	case OCALLINTER:
   612  		(*(int*)c)++;
   613  	}
   614  }
   615  
   616  // appendinit is like addinit in subr.c
   617  // but appends rather than prepends.
   618  static void
   619  appendinit(Node **np, NodeList *init)
   620  {
   621  	Node *n;
   622  
   623  	if(init == nil)
   624  		return;
   625  
   626  	n = *np;
   627  	switch(n->op) {
   628  	case ONAME:
   629  	case OLITERAL:
   630  		// There may be multiple refs to this node;
   631  		// introduce OCONVNOP to hold init list.
   632  		n = nod(OCONVNOP, n, N);
   633  		n->type = n->left->type;
   634  		n->typecheck = 1;
   635  		*np = n;
   636  		break;
   637  	}
   638  	n->ninit = concat(n->ninit, init);
   639  	n->ullman = UINF;
   640  }
   641