github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/gc/esc.c (about) 1 // Copyright 2011 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 // Escape analysis. 6 7 #include <u.h> 8 #include <libc.h> 9 #include "go.h" 10 11 // Run analysis on minimal sets of mutually recursive functions 12 // or single non-recursive functions, bottom up. 13 // 14 // Finding these sets is finding strongly connected components 15 // in the static call graph. The algorithm for doing that is taken 16 // from Sedgewick, Algorithms, Second Edition, p. 482, with two 17 // adaptations. 18 // 19 // First, a hidden closure function (n->curfn != N) cannot be the 20 // root of a connected component. Refusing to use it as a root 21 // forces it into the component of the function in which it appears. 22 // The analysis assumes that closures and the functions in which they 23 // appear are analyzed together, so that the aliasing between their 24 // variables can be modeled more precisely. 25 // 26 // Second, each function becomes two virtual nodes in the graph, 27 // with numbers n and n+1. We record the function's node number as n 28 // but search from node n+1. If the search tells us that the component 29 // number (min) is n+1, we know that this is a trivial component: one function 30 // plus its closures. If the search tells us that the component number is 31 // n, then there was a path from node n+1 back to node n, meaning that 32 // the function set is mutually recursive. The escape analysis can be 33 // more precise when analyzing a single non-recursive function than 34 // when analyzing a set of mutually recursive functions. 35 36 static NodeList *stack; 37 static uint32 visitgen; 38 static uint32 visit(Node*); 39 static uint32 visitcode(Node*, uint32); 40 static uint32 visitcodelist(NodeList*, uint32); 41 42 static void analyze(NodeList*, int); 43 44 enum 45 { 46 EscFuncUnknown = 0, 47 EscFuncPlanned, 48 EscFuncStarted, 49 EscFuncTagged, 50 }; 51 52 void 53 escapes(NodeList *all) 54 { 55 NodeList *l; 56 57 for(l=all; l; l=l->next) 58 l->n->walkgen = 0; 59 60 visitgen = 0; 61 for(l=all; l; l=l->next) 62 if(l->n->op == ODCLFUNC && l->n->curfn == N) 63 visit(l->n); 64 65 for(l=all; l; l=l->next) 66 l->n->walkgen = 0; 67 } 68 69 static uint32 70 visit(Node *n) 71 { 72 uint32 min, recursive; 73 NodeList *l, *block; 74 75 if(n->walkgen > 0) { 76 // already visited 77 return n->walkgen; 78 } 79 80 visitgen++; 81 n->walkgen = visitgen; 82 visitgen++; 83 min = visitgen; 84 85 l = mal(sizeof *l); 86 l->next = stack; 87 l->n = n; 88 stack = l; 89 min = visitcodelist(n->nbody, min); 90 if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) { 91 // This node is the root of a strongly connected component. 92 93 // The original min passed to visitcodelist was n->walkgen+1. 94 // If visitcodelist found its way back to n->walkgen, then this 95 // block is a set of mutually recursive functions. 96 // Otherwise it's just a lone function that does not recurse. 97 recursive = min == n->walkgen; 98 99 // Remove connected component from stack. 100 // Mark walkgen so that future visits return a large number 101 // so as not to affect the caller's min. 102 block = stack; 103 for(l=stack; l->n != n; l=l->next) 104 l->n->walkgen = (uint32)~0U; 105 n->walkgen = (uint32)~0U; 106 stack = l->next; 107 l->next = nil; 108 109 // Run escape analysis on this set of functions. 110 analyze(block, recursive); 111 } 112 113 return min; 114 } 115 116 static uint32 117 visitcodelist(NodeList *l, uint32 min) 118 { 119 for(; l; l=l->next) 120 min = visitcode(l->n, min); 121 return min; 122 } 123 124 static uint32 125 visitcode(Node *n, uint32 min) 126 { 127 Node *fn; 128 uint32 m; 129 130 if(n == N) 131 return min; 132 133 min = visitcodelist(n->ninit, min); 134 min = visitcode(n->left, min); 135 min = visitcode(n->right, min); 136 min = visitcodelist(n->list, min); 137 min = visitcode(n->ntest, min); 138 min = visitcode(n->nincr, min); 139 min = visitcodelist(n->nbody, min); 140 min = visitcodelist(n->nelse, min); 141 min = visitcodelist(n->rlist, min); 142 143 if(n->op == OCALLFUNC || n->op == OCALLMETH) { 144 fn = n->left; 145 if(n->op == OCALLMETH) 146 fn = n->left->right->sym->def; 147 if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn) 148 if((m = visit(fn->defn)) < min) 149 min = m; 150 } 151 152 if(n->op == OCLOSURE) 153 if((m = visit(n->closure)) < min) 154 min = m; 155 156 return min; 157 } 158 159 // An escape analysis pass for a set of functions. 160 // 161 // First escfunc, esc and escassign recurse over the ast of each 162 // function to dig out flow(dst,src) edges between any 163 // pointer-containing nodes and store them in dst->escflowsrc. For 164 // variables assigned to a variable in an outer scope or used as a 165 // return value, they store a flow(theSink, src) edge to a fake node 166 // 'the Sink'. For variables referenced in closures, an edge 167 // flow(closure, &var) is recorded and the flow of a closure itself to 168 // an outer scope is tracked the same way as other variables. 169 // 170 // Then escflood walks the graph starting at theSink and tags all 171 // variables of it can reach an & node as escaping and all function 172 // parameters it can reach as leaking. 173 // 174 // If a value's address is taken but the address does not escape, 175 // then the value can stay on the stack. If the value new(T) does 176 // not escape, then new(T) can be rewritten into a stack allocation. 177 // The same is true of slice literals. 178 // 179 // If optimizations are disabled (-N), this code is not used. 180 // Instead, the compiler assumes that any value whose address 181 // is taken without being immediately dereferenced 182 // needs to be moved to the heap, and new(T) and slice 183 // literals are always real allocations. 184 185 typedef struct EscState EscState; 186 187 static void escfunc(EscState*, Node *func); 188 static void esclist(EscState*, NodeList *l); 189 static void esc(EscState*, Node *n); 190 static void escloopdepthlist(EscState*, NodeList *l); 191 static void escloopdepth(EscState*, Node *n); 192 static void escassign(EscState*, Node *dst, Node *src); 193 static void esccall(EscState*, Node*); 194 static void escflows(EscState*, Node *dst, Node *src); 195 static void escflood(EscState*, Node *dst); 196 static void escwalk(EscState*, int level, Node *dst, Node *src); 197 static void esctag(EscState*, Node *func); 198 199 struct EscState { 200 // Fake node that all 201 // - return values and output variables 202 // - parameters on imported functions not marked 'safe' 203 // - assignments to global variables 204 // flow to. 205 Node theSink; 206 207 NodeList* dsts; // all dst nodes 208 int loopdepth; // for detecting nested loop scopes 209 int pdepth; // for debug printing in recursions. 210 int dstcount, edgecount; // diagnostic 211 NodeList* noesc; // list of possible non-escaping nodes, for printing 212 int recursive; // recursive function or group of mutually recursive functions. 213 }; 214 215 static Strlit *tags[16]; 216 217 static Strlit* 218 mktag(int mask) 219 { 220 Strlit *s; 221 char buf[40]; 222 223 switch(mask&EscMask) { 224 case EscNone: 225 case EscReturn: 226 break; 227 default: 228 fatal("escape mktag"); 229 } 230 231 mask >>= EscBits; 232 233 if(mask < nelem(tags) && tags[mask] != nil) 234 return tags[mask]; 235 236 snprint(buf, sizeof buf, "esc:0x%x", mask); 237 s = strlit(buf); 238 if(mask < nelem(tags)) 239 tags[mask] = s; 240 return s; 241 } 242 243 static int 244 parsetag(Strlit *note) 245 { 246 int em; 247 248 if(note == nil) 249 return EscUnknown; 250 if(strncmp(note->s, "esc:", 4) != 0) 251 return EscUnknown; 252 em = atoi(note->s + 4); 253 if (em == 0) 254 return EscNone; 255 return EscReturn | (em << EscBits); 256 } 257 258 static void 259 analyze(NodeList *all, int recursive) 260 { 261 NodeList *l; 262 EscState es, *e; 263 264 memset(&es, 0, sizeof es); 265 e = &es; 266 e->theSink.op = ONAME; 267 e->theSink.orig = &e->theSink; 268 e->theSink.class = PEXTERN; 269 e->theSink.sym = lookup(".sink"); 270 e->theSink.escloopdepth = -1; 271 e->recursive = recursive; 272 273 for(l=all; l; l=l->next) 274 if(l->n->op == ODCLFUNC) 275 l->n->esc = EscFuncPlanned; 276 277 // flow-analyze functions 278 for(l=all; l; l=l->next) 279 if(l->n->op == ODCLFUNC) 280 escfunc(e, l->n); 281 282 // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount); 283 284 // visit the upstream of each dst, mark address nodes with 285 // addrescapes, mark parameters unsafe 286 for(l = e->dsts; l; l=l->next) 287 escflood(e, l->n); 288 289 // for all top level functions, tag the typenodes corresponding to the param nodes 290 for(l=all; l; l=l->next) 291 if(l->n->op == ODCLFUNC) 292 esctag(e, l->n); 293 294 if(debug['m']) { 295 for(l=e->noesc; l; l=l->next) 296 if(l->n->esc == EscNone) 297 warnl(l->n->lineno, "%S %hN does not escape", 298 (l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S, 299 l->n); 300 } 301 } 302 303 304 static void 305 escfunc(EscState *e, Node *func) 306 { 307 Node *savefn; 308 NodeList *ll; 309 int saveld; 310 311 // print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":""); 312 313 if(func->esc != 1) 314 fatal("repeat escfunc %N", func->nname); 315 func->esc = EscFuncStarted; 316 317 saveld = e->loopdepth; 318 e->loopdepth = 1; 319 savefn = curfn; 320 curfn = func; 321 322 for(ll=curfn->dcl; ll; ll=ll->next) { 323 if(ll->n->op != ONAME) 324 continue; 325 switch (ll->n->class) { 326 case PPARAMOUT: 327 // out params are in a loopdepth between the sink and all local variables 328 ll->n->escloopdepth = 0; 329 break; 330 case PPARAM: 331 if(ll->n->type && !haspointers(ll->n->type)) 332 break; 333 if(curfn->nbody == nil && !curfn->noescape) 334 ll->n->esc = EscHeap; 335 else 336 ll->n->esc = EscNone; // prime for escflood later 337 e->noesc = list(e->noesc, ll->n); 338 ll->n->escloopdepth = 1; 339 break; 340 } 341 } 342 343 // in a mutually recursive group we lose track of the return values 344 if(e->recursive) 345 for(ll=curfn->dcl; ll; ll=ll->next) 346 if(ll->n->op == ONAME && ll->n->class == PPARAMOUT) 347 escflows(e, &e->theSink, ll->n); 348 349 escloopdepthlist(e, curfn->nbody); 350 esclist(e, curfn->nbody); 351 curfn = savefn; 352 e->loopdepth = saveld; 353 } 354 355 // Mark labels that have no backjumps to them as not increasing e->loopdepth. 356 // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat 357 // and set it to one of the following two. Then in esc we'll clear it again. 358 static Label looping; 359 static Label nonlooping; 360 361 static void 362 escloopdepthlist(EscState *e, NodeList *l) 363 { 364 for(; l; l=l->next) 365 escloopdepth(e, l->n); 366 } 367 368 static void 369 escloopdepth(EscState *e, Node *n) 370 { 371 if(n == N) 372 return; 373 374 escloopdepthlist(e, n->ninit); 375 376 switch(n->op) { 377 case OLABEL: 378 if(!n->left || !n->left->sym) 379 fatal("esc:label without label: %+N", n); 380 // Walk will complain about this label being already defined, but that's not until 381 // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc 382 // if(n->left->sym->label != nil) 383 // fatal("escape analysis messed up analyzing label: %+N", n); 384 n->left->sym->label = &nonlooping; 385 break; 386 case OGOTO: 387 if(!n->left || !n->left->sym) 388 fatal("esc:goto without label: %+N", n); 389 // If we come past one that's uninitialized, this must be a (harmless) forward jump 390 // but if it's set to nonlooping the label must have preceded this goto. 391 if(n->left->sym->label == &nonlooping) 392 n->left->sym->label = &looping; 393 break; 394 } 395 396 escloopdepth(e, n->left); 397 escloopdepth(e, n->right); 398 escloopdepthlist(e, n->list); 399 escloopdepth(e, n->ntest); 400 escloopdepth(e, n->nincr); 401 escloopdepthlist(e, n->nbody); 402 escloopdepthlist(e, n->nelse); 403 escloopdepthlist(e, n->rlist); 404 405 } 406 407 static void 408 esclist(EscState *e, NodeList *l) 409 { 410 for(; l; l=l->next) 411 esc(e, l->n); 412 } 413 414 static void 415 esc(EscState *e, Node *n) 416 { 417 int lno; 418 NodeList *ll, *lr; 419 Node *a; 420 421 if(n == N) 422 return; 423 424 lno = setlineno(n); 425 426 if(n->op == OFOR || n->op == ORANGE) 427 e->loopdepth++; 428 429 esc(e, n->left); 430 esc(e, n->right); 431 esc(e, n->ntest); 432 esc(e, n->nincr); 433 esclist(e, n->ninit); 434 esclist(e, n->nbody); 435 esclist(e, n->nelse); 436 esclist(e, n->list); 437 esclist(e, n->rlist); 438 439 if(n->op == OFOR || n->op == ORANGE) 440 e->loopdepth--; 441 442 if(debug['m'] > 1) 443 print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth, 444 (curfn && curfn->nname) ? curfn->nname->sym : S, n); 445 446 switch(n->op) { 447 case ODCL: 448 // Record loop depth at declaration. 449 if(n->left) 450 n->left->escloopdepth = e->loopdepth; 451 break; 452 453 case OLABEL: 454 if(n->left->sym->label == &nonlooping) { 455 if(debug['m'] > 1) 456 print("%L:%N non-looping label\n", lineno, n); 457 } else if(n->left->sym->label == &looping) { 458 if(debug['m'] > 1) 459 print("%L: %N looping label\n", lineno, n); 460 e->loopdepth++; 461 } 462 // See case OLABEL in escloopdepth above 463 // else if(n->left->sym->label == nil) 464 // fatal("escape analysis missed or messed up a label: %+N", n); 465 466 n->left->sym->label = nil; 467 break; 468 469 case ORANGE: 470 // Everything but fixed array is a dereference. 471 if(isfixedarray(n->type) && n->list->next) 472 escassign(e, n->list->next->n, n->right); 473 break; 474 475 case OSWITCH: 476 if(n->ntest && n->ntest->op == OTYPESW) { 477 for(ll=n->list; ll; ll=ll->next) { // cases 478 // ntest->right is the argument of the .(type), 479 // ll->n->nname is the variable per case 480 escassign(e, ll->n->nname, n->ntest->right); 481 } 482 } 483 break; 484 485 case OAS: 486 case OASOP: 487 escassign(e, n->left, n->right); 488 break; 489 490 case OAS2: // x,y = a,b 491 if(count(n->list) == count(n->rlist)) 492 for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) 493 escassign(e, ll->n, lr->n); 494 break; 495 496 case OAS2RECV: // v, ok = <-ch 497 case OAS2MAPR: // v, ok = m[k] 498 case OAS2DOTTYPE: // v, ok = x.(type) 499 escassign(e, n->list->n, n->rlist->n); 500 break; 501 502 case OSEND: // ch <- x 503 escassign(e, &e->theSink, n->right); 504 break; 505 506 case ODEFER: 507 if(e->loopdepth == 1) // top level 508 break; 509 // arguments leak out of scope 510 // TODO: leak to a dummy node instead 511 // fallthrough 512 case OPROC: 513 // go f(x) - f and x escape 514 escassign(e, &e->theSink, n->left->left); 515 escassign(e, &e->theSink, n->left->right); // ODDDARG for call 516 for(ll=n->left->list; ll; ll=ll->next) 517 escassign(e, &e->theSink, ll->n); 518 break; 519 520 case OCALLMETH: 521 case OCALLFUNC: 522 case OCALLINTER: 523 esccall(e, n); 524 break; 525 526 case OAS2FUNC: // x,y = f() 527 // esccall already done on n->rlist->n. tie it's escretval to n->list 528 lr=n->rlist->n->escretval; 529 for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next) 530 escassign(e, ll->n, lr->n); 531 if(lr || ll) 532 fatal("esc oas2func"); 533 break; 534 535 case ORETURN: 536 ll=n->list; 537 if(count(n->list) == 1 && curfn->type->outtuple > 1) { 538 // OAS2FUNC in disguise 539 // esccall already done on n->list->n 540 // tie n->list->n->escretval to curfn->dcl PPARAMOUT's 541 ll = n->list->n->escretval; 542 } 543 544 for(lr = curfn->dcl; lr && ll; lr=lr->next) { 545 if (lr->n->op != ONAME || lr->n->class != PPARAMOUT) 546 continue; 547 escassign(e, lr->n, ll->n); 548 ll = ll->next; 549 } 550 if (ll != nil) 551 fatal("esc return list"); 552 break; 553 554 case OPANIC: 555 // Argument could leak through recover. 556 escassign(e, &e->theSink, n->left); 557 break; 558 559 case OAPPEND: 560 if(!n->isddd) 561 for(ll=n->list->next; ll; ll=ll->next) 562 escassign(e, &e->theSink, ll->n); // lose track of assign to dereference 563 break; 564 565 case OCONV: 566 case OCONVNOP: 567 case OCONVIFACE: 568 escassign(e, n, n->left); 569 break; 570 571 case OARRAYLIT: 572 if(isslice(n->type)) { 573 n->esc = EscNone; // until proven otherwise 574 e->noesc = list(e->noesc, n); 575 n->escloopdepth = e->loopdepth; 576 // Values make it to memory, lose track. 577 for(ll=n->list; ll; ll=ll->next) 578 escassign(e, &e->theSink, ll->n->right); 579 } else { 580 // Link values to array. 581 for(ll=n->list; ll; ll=ll->next) 582 escassign(e, n, ll->n->right); 583 } 584 break; 585 586 case OSTRUCTLIT: 587 // Link values to struct. 588 for(ll=n->list; ll; ll=ll->next) 589 escassign(e, n, ll->n->right); 590 break; 591 592 case OPTRLIT: 593 n->esc = EscNone; // until proven otherwise 594 e->noesc = list(e->noesc, n); 595 n->escloopdepth = e->loopdepth; 596 // Contents make it to memory, lose track. 597 escassign(e, &e->theSink, n->left); 598 break; 599 600 case OCALLPART: 601 n->esc = EscNone; // until proven otherwise 602 e->noesc = list(e->noesc, n); 603 n->escloopdepth = e->loopdepth; 604 // Contents make it to memory, lose track. 605 escassign(e, &e->theSink, n->left); 606 break; 607 608 case OMAPLIT: 609 n->esc = EscNone; // until proven otherwise 610 e->noesc = list(e->noesc, n); 611 n->escloopdepth = e->loopdepth; 612 // Keys and values make it to memory, lose track. 613 for(ll=n->list; ll; ll=ll->next) { 614 escassign(e, &e->theSink, ll->n->left); 615 escassign(e, &e->theSink, ll->n->right); 616 } 617 break; 618 619 case OCLOSURE: 620 // Link addresses of captured variables to closure. 621 for(ll=n->cvars; ll; ll=ll->next) { 622 if(ll->n->op == OXXX) // unnamed out argument; see dcl.c:/^funcargs 623 continue; 624 a = nod(OADDR, ll->n->closure, N); 625 a->lineno = ll->n->lineno; 626 a->escloopdepth = e->loopdepth; 627 typecheck(&a, Erv); 628 escassign(e, n, a); 629 } 630 // fallthrough 631 case OADDR: 632 case OMAKECHAN: 633 case OMAKEMAP: 634 case OMAKESLICE: 635 case ONEW: 636 n->escloopdepth = e->loopdepth; 637 n->esc = EscNone; // until proven otherwise 638 e->noesc = list(e->noesc, n); 639 break; 640 } 641 642 lineno = lno; 643 } 644 645 // Assert that expr somehow gets assigned to dst, if non nil. for 646 // dst==nil, any name node expr still must be marked as being 647 // evaluated in curfn. For expr==nil, dst must still be examined for 648 // evaluations inside it (e.g *f(x) = y) 649 static void 650 escassign(EscState *e, Node *dst, Node *src) 651 { 652 int lno; 653 NodeList *ll; 654 655 if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX) 656 return; 657 658 if(debug['m'] > 1) 659 print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth, 660 (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src); 661 662 setlineno(dst); 663 664 // Analyze lhs of assignment. 665 // Replace dst with e->theSink if we can't track it. 666 switch(dst->op) { 667 default: 668 dump("dst", dst); 669 fatal("escassign: unexpected dst"); 670 671 case OARRAYLIT: 672 case OCLOSURE: 673 case OCONV: 674 case OCONVIFACE: 675 case OCONVNOP: 676 case OMAPLIT: 677 case OSTRUCTLIT: 678 case OCALLPART: 679 break; 680 681 case ONAME: 682 if(dst->class == PEXTERN) 683 dst = &e->theSink; 684 break; 685 case ODOT: // treat "dst.x = src" as "dst = src" 686 escassign(e, dst->left, src); 687 return; 688 case OINDEX: 689 if(isfixedarray(dst->left->type)) { 690 escassign(e, dst->left, src); 691 return; 692 } 693 dst = &e->theSink; // lose track of dereference 694 break; 695 case OIND: 696 case ODOTPTR: 697 dst = &e->theSink; // lose track of dereference 698 break; 699 case OINDEXMAP: 700 // lose track of key and value 701 escassign(e, &e->theSink, dst->right); 702 dst = &e->theSink; 703 break; 704 } 705 706 lno = setlineno(src); 707 e->pdepth++; 708 709 switch(src->op) { 710 case OADDR: // dst = &x 711 case OIND: // dst = *x 712 case ODOTPTR: // dst = (*x).f 713 case ONAME: 714 case OPARAM: 715 case ODDDARG: 716 case OPTRLIT: 717 case OARRAYLIT: 718 case OMAPLIT: 719 case OSTRUCTLIT: 720 case OMAKECHAN: 721 case OMAKEMAP: 722 case OMAKESLICE: 723 case ONEW: 724 case OCLOSURE: 725 case OCALLPART: 726 escflows(e, dst, src); 727 break; 728 729 case OCALLMETH: 730 case OCALLFUNC: 731 case OCALLINTER: 732 // Flowing multiple returns to a single dst happens when 733 // analyzing "go f(g())": here g() flows to sink (issue 4529). 734 for(ll=src->escretval; ll; ll=ll->next) 735 escflows(e, dst, ll->n); 736 break; 737 738 case ODOT: 739 // A non-pointer escaping from a struct does not concern us. 740 if(src->type && !haspointers(src->type)) 741 break; 742 // fallthrough 743 case OCONV: 744 case OCONVIFACE: 745 case OCONVNOP: 746 case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 747 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 748 case ODOTTYPE: 749 case ODOTTYPE2: 750 case OSLICE: 751 case OSLICEARR: 752 case OSLICE3: 753 case OSLICE3ARR: 754 // Conversions, field access, slice all preserve the input value. 755 escassign(e, dst, src->left); 756 break; 757 758 case OAPPEND: 759 // Append returns first argument. 760 escassign(e, dst, src->list->n); 761 break; 762 763 case OINDEX: 764 // Index of array preserves input value. 765 if(isfixedarray(src->left->type)) 766 escassign(e, dst, src->left); 767 break; 768 769 case OADD: 770 case OSUB: 771 case OOR: 772 case OXOR: 773 case OMUL: 774 case ODIV: 775 case OMOD: 776 case OLSH: 777 case ORSH: 778 case OAND: 779 case OANDNOT: 780 case OPLUS: 781 case OMINUS: 782 case OCOM: 783 // Might be pointer arithmetic, in which case 784 // the operands flow into the result. 785 // TODO(rsc): Decide what the story is here. This is unsettling. 786 escassign(e, dst, src->left); 787 escassign(e, dst, src->right); 788 break; 789 } 790 791 e->pdepth--; 792 lineno = lno; 793 } 794 795 static void 796 escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src) 797 { 798 int em; 799 800 em = parsetag(note); 801 802 if(em == EscUnknown) { 803 escassign(e, &e->theSink, src); 804 return; 805 } 806 807 for(em >>= EscBits; em && dsts; em >>= 1, dsts=dsts->next) 808 if(em & 1) 809 escassign(e, dsts->n, src); 810 811 if (em != 0 && dsts == nil) 812 fatal("corrupt esc tag %Z or messed up escretval list\n", note); 813 } 814 815 // This is a bit messier than fortunate, pulled out of esc's big 816 // switch for clarity. We either have the paramnodes, which may be 817 // connected to other things through flows or we have the parameter type 818 // nodes, which may be marked "noescape". Navigating the ast is slightly 819 // different for methods vs plain functions and for imported vs 820 // this-package 821 static void 822 esccall(EscState *e, Node *n) 823 { 824 NodeList *ll, *lr; 825 Node *a, *fn, *src; 826 Type *t, *fntype; 827 char buf[40]; 828 int i; 829 830 fn = N; 831 switch(n->op) { 832 default: 833 fatal("esccall"); 834 835 case OCALLFUNC: 836 fn = n->left; 837 fntype = fn->type; 838 break; 839 840 case OCALLMETH: 841 fn = n->left->right->sym->def; 842 if(fn) 843 fntype = fn->type; 844 else 845 fntype = n->left->type; 846 break; 847 848 case OCALLINTER: 849 fntype = n->left->type; 850 break; 851 } 852 853 ll = n->list; 854 if(n->list != nil && n->list->next == nil) { 855 a = n->list->n; 856 if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()). 857 ll = a->escretval; 858 } 859 860 if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) { 861 // function in same mutually recursive group. Incorporate into flow graph. 862 // print("esc local fn: %N\n", fn->ntype); 863 if(fn->defn->esc == EscFuncUnknown || n->escretval != nil) 864 fatal("graph inconsistency"); 865 866 // set up out list on this call node 867 for(lr=fn->ntype->rlist; lr; lr=lr->next) 868 n->escretval = list(n->escretval, lr->n->left); // type.rlist -> dclfield -> ONAME (PPARAMOUT) 869 870 // Receiver. 871 if(n->op != OCALLFUNC) 872 escassign(e, fn->ntype->left->left, n->left->left); 873 874 for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) { 875 src = ll->n; 876 if(lr->n->isddd && !n->isddd) { 877 // Introduce ODDDARG node to represent ... allocation. 878 src = nod(ODDDARG, N, N); 879 src->escloopdepth = e->loopdepth; 880 src->lineno = n->lineno; 881 src->esc = EscNone; // until we find otherwise 882 e->noesc = list(e->noesc, src); 883 n->right = src; 884 } 885 if(lr->n->left != N) 886 escassign(e, lr->n->left, src); 887 if(src != ll->n) 888 break; 889 } 890 // "..." arguments are untracked 891 for(; ll; ll=ll->next) 892 escassign(e, &e->theSink, ll->n); 893 894 return; 895 } 896 897 // Imported or completely analyzed function. Use the escape tags. 898 if(n->escretval != nil) 899 fatal("esc already decorated call %+N\n", n); 900 901 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 902 i = 0; 903 for(t=getoutargx(fntype)->type; t; t=t->down) { 904 src = nod(ONAME, N, N); 905 snprint(buf, sizeof buf, ".dum%d", i++); 906 src->sym = lookup(buf); 907 src->type = t->type; 908 src->class = PAUTO; 909 src->curfn = curfn; 910 src->escloopdepth = e->loopdepth; 911 src->used = 1; 912 src->lineno = n->lineno; 913 n->escretval = list(n->escretval, src); 914 } 915 916 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); 917 918 // Receiver. 919 if(n->op != OCALLFUNC) 920 escassignfromtag(e, getthisx(fntype)->type->note, n->escretval, n->left->left); 921 922 for(t=getinargx(fntype)->type; ll; ll=ll->next) { 923 src = ll->n; 924 if(t->isddd && !n->isddd) { 925 // Introduce ODDDARG node to represent ... allocation. 926 src = nod(ODDDARG, N, N); 927 src->escloopdepth = e->loopdepth; 928 src->lineno = n->lineno; 929 src->esc = EscNone; // until we find otherwise 930 e->noesc = list(e->noesc, src); 931 n->right = src; 932 } 933 escassignfromtag(e, t->note, n->escretval, src); 934 if(src != ll->n) 935 break; 936 t = t->down; 937 } 938 // "..." arguments are untracked 939 for(; ll; ll=ll->next) 940 escassign(e, &e->theSink, ll->n); 941 } 942 943 // Store the link src->dst in dst, throwing out some quick wins. 944 static void 945 escflows(EscState *e, Node *dst, Node *src) 946 { 947 if(dst == nil || src == nil || dst == src) 948 return; 949 950 // Don't bother building a graph for scalars. 951 if(src->type && !haspointers(src->type)) 952 return; 953 954 if(debug['m']>2) 955 print("%L::flows:: %hN <- %hN\n", lineno, dst, src); 956 957 if(dst->escflowsrc == nil) { 958 e->dsts = list(e->dsts, dst); 959 e->dstcount++; 960 } 961 e->edgecount++; 962 963 dst->escflowsrc = list(dst->escflowsrc, src); 964 } 965 966 // Whenever we hit a reference node, the level goes up by one, and whenever 967 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 968 // finding an OADDR just means we're following the upstream of a dereference, 969 // so this address doesn't leak (yet). 970 // If level == 0, it means the /value/ of this node can reach the root of this flood. 971 // so if this node is an OADDR, it's argument should be marked as escaping iff 972 // it's currfn/e->loopdepth are different from the flood's root. 973 // Once an object has been moved to the heap, all of it's upstream should be considered 974 // escaping to the global scope. 975 static void 976 escflood(EscState *e, Node *dst) 977 { 978 NodeList *l; 979 980 switch(dst->op) { 981 case ONAME: 982 case OCLOSURE: 983 break; 984 default: 985 return; 986 } 987 988 if(debug['m']>1) 989 print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst, 990 (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S, 991 dst->escloopdepth); 992 993 for(l = dst->escflowsrc; l; l=l->next) { 994 walkgen++; 995 escwalk(e, 0, dst, l->n); 996 } 997 } 998 999 // There appear to be some loops in the escape graph, causing 1000 // arbitrary recursion into deeper and deeper levels. 1001 // Cut this off safely by making minLevel sticky: once you 1002 // get that deep, you cannot go down any further but you also 1003 // cannot go up any further. This is a conservative fix. 1004 // Making minLevel smaller (more negative) would handle more 1005 // complex chains of indirections followed by address-of operations, 1006 // at the cost of repeating the traversal once for each additional 1007 // allowed level when a loop is encountered. Using -2 suffices to 1008 // pass all the tests we have written so far, which we assume matches 1009 // the level of complexity we want the escape analysis code to handle. 1010 #define MinLevel (-2) 1011 1012 static void 1013 escwalk(EscState *e, int level, Node *dst, Node *src) 1014 { 1015 NodeList *ll; 1016 int leaks, newlevel; 1017 1018 if(src->walkgen == walkgen && src->esclevel <= level) 1019 return; 1020 src->walkgen = walkgen; 1021 src->esclevel = level; 1022 1023 if(debug['m']>1) 1024 print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n", 1025 level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src, 1026 (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth); 1027 1028 e->pdepth++; 1029 1030 // Input parameter flowing to output parameter? 1031 if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) { 1032 if(src->op == ONAME && src->class == PPARAM && level == 0 && src->curfn == dst->curfn) { 1033 if(src->esc != EscScope && src->esc != EscHeap) { 1034 if(debug['m']) 1035 warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym); 1036 if((src->esc&EscMask) != EscReturn) 1037 src->esc = EscReturn; 1038 src->esc |= 1<<((dst->vargen-1) + EscBits); 1039 goto recurse; 1040 } 1041 } 1042 } 1043 1044 leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth); 1045 1046 switch(src->op) { 1047 case ONAME: 1048 if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) { 1049 src->esc = EscScope; 1050 if(debug['m']) 1051 warnl(src->lineno, "leaking param: %hN", src); 1052 } 1053 1054 // Treat a PPARAMREF closure variable as equivalent to the 1055 // original variable. 1056 if(src->class == PPARAMREF) { 1057 if(leaks && debug['m']) 1058 warnl(src->lineno, "leaking closure reference %hN", src); 1059 escwalk(e, level, dst, src->closure); 1060 } 1061 break; 1062 1063 case OPTRLIT: 1064 case OADDR: 1065 if(leaks) { 1066 src->esc = EscHeap; 1067 addrescapes(src->left); 1068 if(debug['m']) 1069 warnl(src->lineno, "%hN escapes to heap", src); 1070 } 1071 newlevel = level; 1072 if(level > MinLevel) 1073 newlevel--; 1074 escwalk(e, newlevel, dst, src->left); 1075 break; 1076 1077 case OARRAYLIT: 1078 if(isfixedarray(src->type)) 1079 break; 1080 // fall through 1081 case ODDDARG: 1082 case OMAKECHAN: 1083 case OMAKEMAP: 1084 case OMAKESLICE: 1085 case OMAPLIT: 1086 case ONEW: 1087 case OCLOSURE: 1088 case OCALLPART: 1089 if(leaks) { 1090 src->esc = EscHeap; 1091 if(debug['m']) 1092 warnl(src->lineno, "%hN escapes to heap", src); 1093 } 1094 break; 1095 1096 case ODOT: 1097 escwalk(e, level, dst, src->left); 1098 break; 1099 1100 case OINDEX: 1101 if(isfixedarray(src->left->type)) { 1102 escwalk(e, level, dst, src->left); 1103 break; 1104 } 1105 // fall through 1106 case OSLICE: 1107 case ODOTPTR: 1108 case OINDEXMAP: 1109 case OIND: 1110 newlevel = level; 1111 if(level > MinLevel) 1112 newlevel++; 1113 escwalk(e, newlevel, dst, src->left); 1114 } 1115 1116 recurse: 1117 for(ll=src->escflowsrc; ll; ll=ll->next) 1118 escwalk(e, level, dst, ll->n); 1119 1120 e->pdepth--; 1121 } 1122 1123 static void 1124 esctag(EscState *e, Node *func) 1125 { 1126 Node *savefn; 1127 NodeList *ll; 1128 Type *t; 1129 1130 USED(e); 1131 func->esc = EscFuncTagged; 1132 1133 // External functions are assumed unsafe, 1134 // unless //go:noescape is given before the declaration. 1135 if(func->nbody == nil) { 1136 if(func->noescape) { 1137 for(t=getinargx(func->type)->type; t; t=t->down) 1138 if(haspointers(t->type)) 1139 t->note = mktag(EscNone); 1140 } 1141 return; 1142 } 1143 1144 savefn = curfn; 1145 curfn = func; 1146 1147 for(ll=curfn->dcl; ll; ll=ll->next) { 1148 if(ll->n->op != ONAME || ll->n->class != PPARAM) 1149 continue; 1150 1151 switch (ll->n->esc&EscMask) { 1152 case EscNone: // not touched by escflood 1153 case EscReturn: 1154 if(haspointers(ll->n->type)) // don't bother tagging for scalars 1155 ll->n->paramfld->note = mktag(ll->n->esc); 1156 break; 1157 case EscHeap: // touched by escflood, moved to heap 1158 case EscScope: // touched by escflood, value leaves scope 1159 break; 1160 } 1161 } 1162 1163 curfn = savefn; 1164 }