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 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "fmt" 10 "strings" 11 ) 12 13 // Run analysis on minimal sets of mutually recursive functions 14 // or single non-recursive functions, bottom up. 15 // 16 // Finding these sets is finding strongly connected components 17 // in the static call graph. The algorithm for doing that is taken 18 // from Sedgewick, Algorithms, Second Edition, p. 482, with two 19 // adaptations. 20 // 21 // First, a hidden closure function (n->curfn != N) cannot be the 22 // root of a connected component. Refusing to use it as a root 23 // forces it into the component of the function in which it appears. 24 // This is more convenient for escape analysis. 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 type bottomUpVisitor struct { 37 analyze func(*NodeList, bool) 38 visitgen uint32 39 nodeID map[*Node]uint32 40 stack *NodeList 41 } 42 43 // visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list. 44 // It calls analyze with successive groups of functions, working from 45 // the bottom of the call graph upward. Each time analyze is called with 46 // a list of functions, every function on that list only calls other functions 47 // on the list or functions that have been passed in previous invocations of 48 // analyze. Closures appear in the same list as their outer functions. 49 // The lists are as short as possible while preserving those requirements. 50 // (In a typical program, many invocations of analyze will be passed just 51 // a single function.) The boolean argument 'recursive' passed to analyze 52 // specifies whether the functions on the list are mutually recursive. 53 // If recursive is false, the list consists of only a single function and its closures. 54 // If recursive is true, the list may still contain only a single function, 55 // if that function is itself recursive. 56 func visitBottomUp(list *NodeList, analyze func(list *NodeList, recursive bool)) { 57 var v bottomUpVisitor 58 v.analyze = analyze 59 v.nodeID = make(map[*Node]uint32) 60 for l := list; l != nil; l = l.Next { 61 if l.N.Op == ODCLFUNC && l.N.Func.FCurfn == nil { 62 v.visit(l.N) 63 } 64 } 65 } 66 67 func (v *bottomUpVisitor) visit(n *Node) uint32 { 68 if id := v.nodeID[n]; id > 0 { 69 // already visited 70 return id 71 } 72 73 v.visitgen++ 74 id := v.visitgen 75 v.nodeID[n] = id 76 v.visitgen++ 77 min := v.visitgen 78 79 l := new(NodeList) 80 l.Next = v.stack 81 l.N = n 82 v.stack = l 83 min = v.visitcodelist(n.Nbody, min) 84 if (min == id || min == id+1) && n.Func.FCurfn == nil { 85 // This node is the root of a strongly connected component. 86 87 // The original min passed to visitcodelist was n->walkgen+1. 88 // If visitcodelist found its way back to n->walkgen, then this 89 // block is a set of mutually recursive functions. 90 // Otherwise it's just a lone function that does not recurse. 91 recursive := min == id 92 93 // Remove connected component from stack. 94 // Mark walkgen so that future visits return a large number 95 // so as not to affect the caller's min. 96 block := v.stack 97 98 var l *NodeList 99 for l = v.stack; l.N != n; l = l.Next { 100 v.nodeID[l.N] = ^uint32(0) 101 } 102 v.nodeID[n] = ^uint32(0) 103 v.stack = l.Next 104 l.Next = nil 105 106 // Run escape analysis on this set of functions. 107 v.analyze(block, recursive) 108 } 109 110 return min 111 } 112 113 func (v *bottomUpVisitor) visitcodelist(l *NodeList, min uint32) uint32 { 114 for ; l != nil; l = l.Next { 115 min = v.visitcode(l.N, min) 116 } 117 return min 118 } 119 120 func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 { 121 if n == nil { 122 return min 123 } 124 125 min = v.visitcodelist(n.Ninit, min) 126 min = v.visitcode(n.Left, min) 127 min = v.visitcode(n.Right, min) 128 min = v.visitcodelist(n.List, min) 129 min = v.visitcodelist(n.Nbody, min) 130 min = v.visitcodelist(n.Rlist, min) 131 132 if n.Op == OCALLFUNC || n.Op == OCALLMETH { 133 fn := n.Left 134 if n.Op == OCALLMETH { 135 fn = n.Left.Right.Sym.Def 136 } 137 if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil { 138 m := v.visit(fn.Name.Defn) 139 if m < min { 140 min = m 141 } 142 } 143 } 144 145 if n.Op == OCLOSURE { 146 m := v.visit(n.Func.Closure) 147 if m < min { 148 min = m 149 } 150 } 151 152 return min 153 } 154 155 // Escape analysis. 156 157 // An escape analysis pass for a set of functions. 158 // The analysis assumes that closures and the functions in which they 159 // appear are analyzed together, so that the aliasing between their 160 // variables can be modeled more precisely. 161 // 162 // First escfunc, esc and escassign recurse over the ast of each 163 // function to dig out flow(dst,src) edges between any 164 // pointer-containing nodes and store them in dst->escflowsrc. For 165 // variables assigned to a variable in an outer scope or used as a 166 // return value, they store a flow(theSink, src) edge to a fake node 167 // 'the Sink'. For variables referenced in closures, an edge 168 // flow(closure, &var) is recorded and the flow of a closure itself to 169 // an outer scope is tracked the same way as other variables. 170 // 171 // Then escflood walks the graph starting at theSink and tags all 172 // variables of it can reach an & node as escaping and all function 173 // parameters it can reach as leaking. 174 // 175 // If a value's address is taken but the address does not escape, 176 // then the value can stay on the stack. If the value new(T) does 177 // not escape, then new(T) can be rewritten into a stack allocation. 178 // The same is true of slice literals. 179 // 180 // If optimizations are disabled (-N), this code is not used. 181 // Instead, the compiler assumes that any value whose address 182 // is taken without being immediately dereferenced 183 // needs to be moved to the heap, and new(T) and slice 184 // literals are always real allocations. 185 186 func escapes(all *NodeList) { 187 visitBottomUp(all, escAnalyze) 188 } 189 190 const ( 191 EscFuncUnknown = 0 + iota 192 EscFuncPlanned 193 EscFuncStarted 194 EscFuncTagged 195 ) 196 197 // There appear to be some loops in the escape graph, causing 198 // arbitrary recursion into deeper and deeper levels. 199 // Cut this off safely by making minLevel sticky: once you 200 // get that deep, you cannot go down any further but you also 201 // cannot go up any further. This is a conservative fix. 202 // Making minLevel smaller (more negative) would handle more 203 // complex chains of indirections followed by address-of operations, 204 // at the cost of repeating the traversal once for each additional 205 // allowed level when a loop is encountered. Using -2 suffices to 206 // pass all the tests we have written so far, which we assume matches 207 // the level of complexity we want the escape analysis code to handle. 208 const ( 209 MinLevel = -2 210 ) 211 212 // A Level encodes the reference state and context applied to 213 // (stack, heap) allocated memory. 214 // 215 // value is the overall sum of *(1) and &(-1) operations encountered 216 // along a path from a destination (sink, return value) to a source 217 // (allocation, parameter). 218 // 219 // suffixValue is the maximum-copy-started-suffix-level applied to a sink. 220 // For example: 221 // sink = x.left.left --> level=2, x is dereferenced twice and does not escape to sink. 222 // sink = &Node{x} --> level=-1, x is accessible from sink via one "address of" 223 // sink = &Node{&Node{x}} --> level=-2, x is accessible from sink via two "address of" 224 // sink = &Node{&Node{x.left}} --> level=-1, but x is NOT accessible from sink because it was indirected and then copied. 225 // (The copy operations are sometimes implicit in the source code; in this case, 226 // value of x.left was copied into a field of a newly allocated Node) 227 // 228 // There's one of these for each Node, and the integer values 229 // rarely exceed even what can be stored in 4 bits, never mind 8. 230 type Level struct { 231 value, suffixValue int8 232 } 233 234 func (l Level) int() int { 235 return int(l.value) 236 } 237 238 func levelFrom(i int) Level { 239 if i <= MinLevel { 240 return Level{value: MinLevel} 241 } 242 return Level{value: int8(i)} 243 } 244 245 func satInc8(x int8) int8 { 246 if x == 127 { 247 return 127 248 } 249 return x + 1 250 } 251 252 func satAdd8(x, y int8) int8 { 253 z := x + y 254 if x^y < 0 || x^z >= 0 { 255 return z 256 } 257 if x < 0 { 258 return -128 259 } 260 return 127 261 } 262 263 func min8(a, b int8) int8 { 264 if a < b { 265 return a 266 } 267 return b 268 } 269 270 func max8(a, b int8) int8 { 271 if a > b { 272 return a 273 } 274 return b 275 } 276 277 // inc returns the level l + 1, representing the effect of an indirect (*) operation. 278 func (l Level) inc() Level { 279 if l.value <= MinLevel { 280 return Level{value: MinLevel} 281 } 282 return Level{value: satInc8(l.value), suffixValue: satInc8(l.suffixValue)} 283 } 284 285 // dec returns the level l - 1, representing the effect of an address-of (&) operation. 286 func (l Level) dec() Level { 287 if l.value <= MinLevel { 288 return Level{value: MinLevel} 289 } 290 return Level{value: l.value - 1, suffixValue: l.suffixValue - 1} 291 } 292 293 // copy returns the level for a copy of a value with level l. 294 func (l Level) copy() Level { 295 return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)} 296 } 297 298 func (l1 Level) min(l2 Level) Level { 299 return Level{ 300 value: min8(l1.value, l2.value), 301 suffixValue: min8(l1.suffixValue, l2.suffixValue)} 302 } 303 304 // guaranteedDereference returns the number of dereferences 305 // applied to a pointer before addresses are taken/generated. 306 // This is the maximum level computed from path suffixes starting 307 // with copies where paths flow from destination to source. 308 func (l Level) guaranteedDereference() int { 309 return int(l.suffixValue) 310 } 311 312 type NodeEscState struct { 313 Curfn *Node 314 Escflowsrc *NodeList // flow(this, src) 315 Escretval *NodeList // on OCALLxxx, list of dummy return values 316 Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes 317 Esclevel Level 318 Walkgen uint32 319 } 320 321 func (e *EscState) nodeEscState(n *Node) *NodeEscState { 322 if nE, ok := n.Opt().(*NodeEscState); ok { 323 return nE 324 } 325 if n.Opt() != nil { 326 Fatal("nodeEscState: opt in use (%T)", n.Opt()) 327 } 328 nE := new(NodeEscState) 329 nE.Curfn = Curfn 330 n.SetOpt(nE) 331 e.opts = append(e.opts, n) 332 return nE 333 } 334 335 func (e *EscState) track(n *Node) { 336 if Curfn == nil { 337 Fatal("EscState.track: Curfn nil") 338 } 339 n.Esc = EscNone // until proven otherwise 340 nE := e.nodeEscState(n) 341 nE.Escloopdepth = e.loopdepth 342 e.noesc = list(e.noesc, n) 343 } 344 345 // Escape constants are numbered in order of increasing "escapiness" 346 // to help make inferences be monotonic. With the exception of 347 // EscNever which is sticky, eX < eY means that eY is more exposed 348 // than eX, and hence replaces it in a conservative analysis. 349 const ( 350 EscUnknown = iota 351 EscNone // Does not escape to heap, result, or parameters. 352 EscReturn // Is returned or reachable from returned. 353 EscScope // Allocated in an inner loop scope, assigned to an outer loop scope, 354 // which allows the construction of non-escaping but arbitrarily large linked 355 // data structures (i.e., not eligible for allocation in a fixed-size stack frame). 356 EscHeap // Reachable from the heap 357 EscNever // By construction will not escape. 358 EscBits = 3 359 EscMask = (1 << EscBits) - 1 360 EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap 361 EscReturnBits = EscBits + 1 362 // Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3 363 ) 364 365 // escMax returns the maximum of an existing escape value 366 // (and its additional parameter flow flags) and a new escape type. 367 func escMax(e, etype uint16) uint16 { 368 if e&EscMask >= EscScope { 369 // normalize 370 if e&^EscMask != 0 { 371 Fatal("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask) 372 } 373 } 374 if e&EscMask > etype { 375 return e 376 } 377 if etype == EscNone || etype == EscReturn { 378 return (e &^ EscMask) | etype 379 } 380 return etype 381 } 382 383 // For each input parameter to a function, the escapeReturnEncoding describes 384 // how the parameter may leak to the function's outputs. This is currently the 385 // "level" of the leak where level is 0 or larger (negative level means stored into 386 // something whose address is returned -- but that implies stored into the heap, 387 // hence EscHeap, which means that the details are not currently relevant. ) 388 const ( 389 bitsPerOutputInTag = 3 // For each output, the number of bits for a tag 390 bitsMaskForTag = uint16(1<<bitsPerOutputInTag) - 1 // The bit mask to extract a single tag. 391 outputsPerTag = (16 - EscReturnBits) / bitsPerOutputInTag // The number of outputs that can be tagged. 392 maxEncodedLevel = int(bitsMaskForTag - 1) // The largest level that can be stored in a tag. 393 ) 394 395 type EscState struct { 396 // Fake node that all 397 // - return values and output variables 398 // - parameters on imported functions not marked 'safe' 399 // - assignments to global variables 400 // flow to. 401 theSink Node 402 403 dsts *NodeList // all dst nodes 404 loopdepth int32 // for detecting nested loop scopes 405 pdepth int // for debug printing in recursions. 406 dstcount int // diagnostic 407 edgecount int // diagnostic 408 noesc *NodeList // list of possible non-escaping nodes, for printing 409 recursive bool // recursive function or group of mutually recursive functions. 410 opts []*Node // nodes with .Opt initialized 411 walkgen uint32 412 } 413 414 // funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way. 415 func funcSym(fn *Node) *Sym { 416 if fn == nil || fn.Func.Nname == nil { 417 return nil 418 } 419 return fn.Func.Nname.Sym 420 } 421 422 // curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way. 423 func (e *EscState) curfnSym(n *Node) *Sym { 424 nE := e.nodeEscState(n) 425 return funcSym(nE.Curfn) 426 } 427 428 func escAnalyze(all *NodeList, recursive bool) { 429 var es EscState 430 e := &es 431 e.theSink.Op = ONAME 432 e.theSink.Orig = &e.theSink 433 e.theSink.Class = PEXTERN 434 e.theSink.Sym = Lookup(".sink") 435 e.nodeEscState(&e.theSink).Escloopdepth = -1 436 e.recursive = recursive 437 438 for l := all; l != nil; l = l.Next { 439 if l.N.Op == ODCLFUNC { 440 l.N.Esc = EscFuncPlanned 441 } 442 } 443 444 // flow-analyze functions 445 for l := all; l != nil; l = l.Next { 446 if l.N.Op == ODCLFUNC { 447 escfunc(e, l.N) 448 } 449 } 450 451 // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount); 452 453 // visit the upstream of each dst, mark address nodes with 454 // addrescapes, mark parameters unsafe 455 for l := e.dsts; l != nil; l = l.Next { 456 escflood(e, l.N) 457 } 458 459 // for all top level functions, tag the typenodes corresponding to the param nodes 460 for l := all; l != nil; l = l.Next { 461 if l.N.Op == ODCLFUNC { 462 esctag(e, l.N) 463 } 464 } 465 466 if Debug['m'] != 0 { 467 for l := e.noesc; l != nil; l = l.Next { 468 if l.N.Esc == EscNone { 469 Warnl(int(l.N.Lineno), "%v %v does not escape", e.curfnSym(l.N), Nconv(l.N, obj.FmtShort)) 470 } 471 } 472 } 473 for _, x := range e.opts { 474 x.SetOpt(nil) 475 } 476 } 477 478 func escfunc(e *EscState, func_ *Node) { 479 // print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":""); 480 if func_.Esc != 1 { 481 Fatal("repeat escfunc %v", func_.Func.Nname) 482 } 483 func_.Esc = EscFuncStarted 484 485 saveld := e.loopdepth 486 e.loopdepth = 1 487 savefn := Curfn 488 Curfn = func_ 489 490 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 491 if ll.N.Op != ONAME { 492 continue 493 } 494 llNE := e.nodeEscState(ll.N) 495 switch ll.N.Class { 496 // out params are in a loopdepth between the sink and all local variables 497 case PPARAMOUT: 498 llNE.Escloopdepth = 0 499 500 case PPARAM: 501 llNE.Escloopdepth = 1 502 if ll.N.Type != nil && !haspointers(ll.N.Type) { 503 break 504 } 505 if Curfn.Nbody == nil && !Curfn.Noescape { 506 ll.N.Esc = EscHeap 507 } else { 508 ll.N.Esc = EscNone // prime for escflood later 509 } 510 e.noesc = list(e.noesc, ll.N) 511 } 512 } 513 514 // in a mutually recursive group we lose track of the return values 515 if e.recursive { 516 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 517 if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT { 518 escflows(e, &e.theSink, ll.N) 519 } 520 } 521 } 522 523 escloopdepthlist(e, Curfn.Nbody) 524 esclist(e, Curfn.Nbody, Curfn) 525 Curfn = savefn 526 e.loopdepth = saveld 527 } 528 529 // Mark labels that have no backjumps to them as not increasing e->loopdepth. 530 // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat 531 // and set it to one of the following two. Then in esc we'll clear it again. 532 var looping Label 533 534 var nonlooping Label 535 536 func escloopdepthlist(e *EscState, l *NodeList) { 537 for ; l != nil; l = l.Next { 538 escloopdepth(e, l.N) 539 } 540 } 541 542 func escloopdepth(e *EscState, n *Node) { 543 if n == nil { 544 return 545 } 546 547 escloopdepthlist(e, n.Ninit) 548 549 switch n.Op { 550 case OLABEL: 551 if n.Left == nil || n.Left.Sym == nil { 552 Fatal("esc:label without label: %v", Nconv(n, obj.FmtSign)) 553 } 554 555 // Walk will complain about this label being already defined, but that's not until 556 // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc 557 // if(n->left->sym->label != nil) 558 // fatal("escape analysis messed up analyzing label: %+N", n); 559 n.Left.Sym.Label = &nonlooping 560 561 case OGOTO: 562 if n.Left == nil || n.Left.Sym == nil { 563 Fatal("esc:goto without label: %v", Nconv(n, obj.FmtSign)) 564 } 565 566 // If we come past one that's uninitialized, this must be a (harmless) forward jump 567 // but if it's set to nonlooping the label must have preceded this goto. 568 if n.Left.Sym.Label == &nonlooping { 569 n.Left.Sym.Label = &looping 570 } 571 } 572 573 escloopdepth(e, n.Left) 574 escloopdepth(e, n.Right) 575 escloopdepthlist(e, n.List) 576 escloopdepthlist(e, n.Nbody) 577 escloopdepthlist(e, n.Rlist) 578 } 579 580 func esclist(e *EscState, l *NodeList, up *Node) { 581 for ; l != nil; l = l.Next { 582 esc(e, l.N, up) 583 } 584 } 585 586 func esc(e *EscState, n *Node, up *Node) { 587 if n == nil { 588 return 589 } 590 591 lno := int(setlineno(n)) 592 593 // ninit logically runs at a different loopdepth than the rest of the for loop. 594 esclist(e, n.Ninit, n) 595 596 if n.Op == OFOR || n.Op == ORANGE { 597 e.loopdepth++ 598 } 599 600 // type switch variables have no ODCL. 601 // process type switch as declaration. 602 // must happen before processing of switch body, 603 // so before recursion. 604 if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW { 605 for ll := n.List; ll != nil; ll = ll.Next { // cases 606 607 // ll.N.Rlist is the variable per case 608 if ll.N.Rlist != nil { 609 e.nodeEscState(ll.N.Rlist.N).Escloopdepth = e.loopdepth 610 } 611 } 612 } 613 614 // Big stuff escapes unconditionally 615 // "Big" conditions that were scattered around in walk have been gathered here 616 if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize || 617 n.Op == ONEW && n.Type.Type.Width >= 1<<16 || 618 n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { 619 if Debug['m'] > 1 { 620 Warnl(int(n.Lineno), "%v is too large for stack", n) 621 } 622 n.Esc = EscHeap 623 addrescapes(n) 624 escassign(e, &e.theSink, n) 625 } 626 627 esc(e, n.Left, n) 628 esc(e, n.Right, n) 629 esclist(e, n.Nbody, n) 630 esclist(e, n.List, n) 631 esclist(e, n.Rlist, n) 632 633 if n.Op == OFOR || n.Op == ORANGE { 634 e.loopdepth-- 635 } 636 637 if Debug['m'] > 1 { 638 fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n) 639 } 640 641 switch n.Op { 642 // Record loop depth at declaration. 643 case ODCL: 644 if n.Left != nil { 645 e.nodeEscState(n.Left).Escloopdepth = e.loopdepth 646 } 647 648 case OLABEL: 649 if n.Left.Sym.Label == &nonlooping { 650 if Debug['m'] > 1 { 651 fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), n) 652 } 653 } else if n.Left.Sym.Label == &looping { 654 if Debug['m'] > 1 { 655 fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), n) 656 } 657 e.loopdepth++ 658 } 659 660 // See case OLABEL in escloopdepth above 661 // else if(n->left->sym->label == nil) 662 // fatal("escape analysis missed or messed up a label: %+N", n); 663 664 n.Left.Sym.Label = nil 665 666 // Everything but fixed array is a dereference. 667 case ORANGE: 668 if n.List != nil && n.List.Next != nil { 669 if Isfixedarray(n.Type) { 670 escassign(e, n.List.Next.N, n.Right) 671 } else { 672 escassignDereference(e, n.List.Next.N, n.Right) 673 } 674 } 675 676 case OSWITCH: 677 if n.Left != nil && n.Left.Op == OTYPESW { 678 for ll := n.List; ll != nil; ll = ll.Next { 679 // cases 680 // n.Left.Right is the argument of the .(type), 681 // ll.N.Rlist is the variable per case 682 if ll.N.Rlist != nil { 683 escassign(e, ll.N.Rlist.N, n.Left.Right) 684 } 685 } 686 } 687 688 // Filter out the following special case. 689 // 690 // func (b *Buffer) Foo() { 691 // n, m := ... 692 // b.buf = b.buf[n:m] 693 // } 694 // 695 // This assignment is a no-op for escape analysis, 696 // it does not store any new pointers into b that were not already there. 697 // However, without this special case b will escape, because we assign to OIND/ODOTPTR. 698 case OAS, OASOP, OASWB: 699 if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference 700 (n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation 701 (n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference 702 n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME 703 704 // Here we also assume that the statement will not contain calls, 705 // that is, that order will move any calls to init. 706 // Otherwise base ONAME value could change between the moments 707 // when we evaluate it for dst and for src. 708 // 709 // Note, this optimization does not apply to OSLICEARR, 710 // because it does introduce a new pointer into b that was not already there 711 // (pointer to b itself). After such assignment, if b contents escape, 712 // b escapes as well. If we ignore such OSLICEARR, we will conclude 713 // that b does not escape when b contents do. 714 if Debug['m'] != 0 { 715 Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, obj.FmtShort)) 716 } 717 718 break 719 } 720 721 escassign(e, n.Left, n.Right) 722 723 case OAS2: // x,y = a,b 724 if count(n.List) == count(n.Rlist) { 725 ll := n.List 726 lr := n.Rlist 727 for ; ll != nil; ll, lr = ll.Next, lr.Next { 728 escassign(e, ll.N, lr.N) 729 } 730 } 731 732 case OAS2RECV, // v, ok = <-ch 733 OAS2MAPR, // v, ok = m[k] 734 OAS2DOTTYPE: // v, ok = x.(type) 735 escassign(e, n.List.N, n.Rlist.N) 736 737 case OSEND: // ch <- x 738 escassign(e, &e.theSink, n.Right) 739 740 case ODEFER: 741 if e.loopdepth == 1 { // top level 742 break 743 } 744 // arguments leak out of scope 745 // TODO: leak to a dummy node instead 746 fallthrough 747 748 case OPROC: 749 // go f(x) - f and x escape 750 escassign(e, &e.theSink, n.Left.Left) 751 752 escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call 753 for ll := n.Left.List; ll != nil; ll = ll.Next { 754 escassign(e, &e.theSink, ll.N) 755 } 756 757 case OCALLMETH, OCALLFUNC, OCALLINTER: 758 esccall(e, n, up) 759 760 // esccall already done on n->rlist->n. tie it's escretval to n->list 761 case OAS2FUNC: // x,y = f() 762 lr := e.nodeEscState(n.Rlist.N).Escretval 763 764 var ll *NodeList 765 for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next { 766 escassign(e, ll.N, lr.N) 767 } 768 if lr != nil || ll != nil { 769 Fatal("esc oas2func") 770 } 771 772 case ORETURN: 773 ll := n.List 774 if count(n.List) == 1 && Curfn.Type.Outtuple > 1 { 775 // OAS2FUNC in disguise 776 // esccall already done on n->list->n 777 // tie n->list->n->escretval to curfn->dcl PPARAMOUT's 778 ll = e.nodeEscState(n.List.N).Escretval 779 } 780 781 for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next { 782 if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT { 783 continue 784 } 785 escassign(e, lr.N, ll.N) 786 ll = ll.Next 787 } 788 789 if ll != nil { 790 Fatal("esc return list") 791 } 792 793 // Argument could leak through recover. 794 case OPANIC: 795 escassign(e, &e.theSink, n.Left) 796 797 case OAPPEND: 798 if !n.Isddd { 799 for ll := n.List.Next; ll != nil; ll = ll.Next { 800 escassign(e, &e.theSink, ll.N) // lose track of assign to dereference 801 } 802 } else { 803 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. 804 slice2 := n.List.Next.N 805 escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference 806 if Debug['m'] > 2 { 807 Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort)) 808 } 809 } 810 escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too 811 812 case OCOPY: 813 escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference 814 815 case OCONV, OCONVNOP: 816 escassign(e, n, n.Left) 817 818 case OCONVIFACE: 819 e.track(n) 820 escassign(e, n, n.Left) 821 822 case OARRAYLIT: 823 if Isslice(n.Type) { 824 // Slice itself is not leaked until proven otherwise 825 e.track(n) 826 } 827 828 // Link values to array/slice 829 for ll := n.List; ll != nil; ll = ll.Next { 830 escassign(e, n, ll.N.Right) 831 } 832 833 // Link values to struct. 834 case OSTRUCTLIT: 835 for ll := n.List; ll != nil; ll = ll.Next { 836 escassign(e, n, ll.N.Right) 837 } 838 839 case OPTRLIT: 840 e.track(n) 841 842 // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. 843 escassign(e, n, n.Left) 844 845 case OCALLPART: 846 e.track(n) 847 848 // Contents make it to memory, lose track. 849 escassign(e, &e.theSink, n.Left) 850 851 case OMAPLIT: 852 e.track(n) 853 854 // Keys and values make it to memory, lose track. 855 for ll := n.List; ll != nil; ll = ll.Next { 856 escassign(e, &e.theSink, ll.N.Left) 857 escassign(e, &e.theSink, ll.N.Right) 858 } 859 860 // Link addresses of captured variables to closure. 861 case OCLOSURE: 862 var a *Node 863 var v *Node 864 for ll := n.Func.Cvars; ll != nil; ll = ll.Next { 865 v = ll.N 866 if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs 867 continue 868 } 869 a = v.Name.Param.Closure 870 if !v.Name.Byval { 871 a = Nod(OADDR, a, nil) 872 a.Lineno = v.Lineno 873 e.nodeEscState(a).Escloopdepth = e.loopdepth 874 typecheck(&a, Erv) 875 } 876 877 escassign(e, n, a) 878 } 879 fallthrough 880 881 case OMAKECHAN, 882 OMAKEMAP, 883 OMAKESLICE, 884 ONEW, 885 OARRAYRUNESTR, 886 OARRAYBYTESTR, 887 OSTRARRAYRUNE, 888 OSTRARRAYBYTE, 889 ORUNESTR: 890 e.track(n) 891 892 case OADDSTR: 893 e.track(n) 894 // Arguments of OADDSTR do not escape. 895 896 case OADDR: 897 // current loop depth is an upper bound on actual loop depth 898 // of addressed value. 899 e.track(n) 900 901 // for &x, use loop depth of x if known. 902 // it should always be known, but if not, be conservative 903 // and keep the current loop depth. 904 if n.Left.Op == ONAME { 905 switch n.Left.Class { 906 case PAUTO: 907 nE := e.nodeEscState(n) 908 leftE := e.nodeEscState(n.Left) 909 if leftE.Escloopdepth != 0 { 910 nE.Escloopdepth = leftE.Escloopdepth 911 } 912 913 // PPARAM is loop depth 1 always. 914 // PPARAMOUT is loop depth 0 for writes 915 // but considered loop depth 1 for address-of, 916 // so that writing the address of one result 917 // to another (or the same) result makes the 918 // first result move to the heap. 919 case PPARAM, PPARAMOUT: 920 nE := e.nodeEscState(n) 921 nE.Escloopdepth = 1 922 } 923 } 924 } 925 926 lineno = int32(lno) 927 } 928 929 // Assert that expr somehow gets assigned to dst, if non nil. for 930 // dst==nil, any name node expr still must be marked as being 931 // evaluated in curfn. For expr==nil, dst must still be examined for 932 // evaluations inside it (e.g *f(x) = y) 933 func escassign(e *EscState, dst *Node, src *Node) { 934 if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX { 935 return 936 } 937 938 if Debug['m'] > 1 { 939 fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n", 940 Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), 941 Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0), 942 Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0)) 943 } 944 945 setlineno(dst) 946 947 // Analyze lhs of assignment. 948 // Replace dst with e->theSink if we can't track it. 949 switch dst.Op { 950 default: 951 Dump("dst", dst) 952 Fatal("escassign: unexpected dst") 953 954 case OARRAYLIT, 955 OCLOSURE, 956 OCONV, 957 OCONVIFACE, 958 OCONVNOP, 959 OMAPLIT, 960 OSTRUCTLIT, 961 OPTRLIT, 962 OCALLPART: 963 break 964 965 case ONAME: 966 if dst.Class == PEXTERN { 967 dst = &e.theSink 968 } 969 970 case ODOT: // treat "dst.x = src" as "dst = src" 971 escassign(e, dst.Left, src) 972 973 return 974 975 case OINDEX: 976 if Isfixedarray(dst.Left.Type) { 977 escassign(e, dst.Left, src) 978 return 979 } 980 981 dst = &e.theSink // lose track of dereference 982 983 case OIND, ODOTPTR: 984 dst = &e.theSink // lose track of dereference 985 986 // lose track of key and value 987 case OINDEXMAP: 988 escassign(e, &e.theSink, dst.Right) 989 990 dst = &e.theSink 991 } 992 993 lno := int(setlineno(src)) 994 e.pdepth++ 995 996 switch src.Op { 997 case OADDR, // dst = &x 998 OIND, // dst = *x 999 ODOTPTR, // dst = (*x).f 1000 ONAME, 1001 OPARAM, 1002 ODDDARG, 1003 OPTRLIT, 1004 OARRAYLIT, 1005 OMAPLIT, 1006 OSTRUCTLIT, 1007 OMAKECHAN, 1008 OMAKEMAP, 1009 OMAKESLICE, 1010 OARRAYRUNESTR, 1011 OARRAYBYTESTR, 1012 OSTRARRAYRUNE, 1013 OSTRARRAYBYTE, 1014 OADDSTR, 1015 ONEW, 1016 OCALLPART, 1017 ORUNESTR, 1018 OCONVIFACE: 1019 escflows(e, dst, src) 1020 1021 case OCLOSURE: 1022 // OCLOSURE is lowered to OPTRLIT, 1023 // insert OADDR to account for the additional indirection. 1024 a := Nod(OADDR, src, nil) 1025 a.Lineno = src.Lineno 1026 e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth 1027 a.Type = Ptrto(src.Type) 1028 escflows(e, dst, a) 1029 1030 // Flowing multiple returns to a single dst happens when 1031 // analyzing "go f(g())": here g() flows to sink (issue 4529). 1032 case OCALLMETH, OCALLFUNC, OCALLINTER: 1033 for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next { 1034 escflows(e, dst, ll.N) 1035 } 1036 1037 // A non-pointer escaping from a struct does not concern us. 1038 case ODOT: 1039 if src.Type != nil && !haspointers(src.Type) { 1040 break 1041 } 1042 fallthrough 1043 1044 // Conversions, field access, slice all preserve the input value. 1045 case OCONV, 1046 OCONVNOP, 1047 ODOTMETH, 1048 // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 1049 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 1050 ODOTTYPE, 1051 ODOTTYPE2, 1052 OSLICE, 1053 OSLICE3, 1054 OSLICEARR, 1055 OSLICE3ARR, 1056 OSLICESTR: 1057 // Conversions, field access, slice all preserve the input value. 1058 escassign(e, dst, src.Left) 1059 1060 case OAPPEND: 1061 // Append returns first argument. 1062 // Subsequent arguments are already leaked because they are operands to append. 1063 escassign(e, dst, src.List.N) 1064 1065 case OINDEX: 1066 // Index of array preserves input value. 1067 if Isfixedarray(src.Left.Type) { 1068 escassign(e, dst, src.Left) 1069 } else { 1070 escflows(e, dst, src) 1071 } 1072 1073 // Might be pointer arithmetic, in which case 1074 // the operands flow into the result. 1075 // TODO(rsc): Decide what the story is here. This is unsettling. 1076 case OADD, 1077 OSUB, 1078 OOR, 1079 OXOR, 1080 OMUL, 1081 ODIV, 1082 OMOD, 1083 OLSH, 1084 ORSH, 1085 OAND, 1086 OANDNOT, 1087 OPLUS, 1088 OMINUS, 1089 OCOM: 1090 escassign(e, dst, src.Left) 1091 1092 escassign(e, dst, src.Right) 1093 } 1094 1095 e.pdepth-- 1096 lineno = int32(lno) 1097 } 1098 1099 // Common case for escapes is 16 bits 000000000xxxEEEE 1100 // where commonest cases for xxx encoding in-to-out pointer 1101 // flow are 000, 001, 010, 011 and EEEE is computed Esc bits. 1102 // Note width of xxx depends on value of constant 1103 // bitsPerOutputInTag -- expect 2 or 3, so in practice the 1104 // tag cache array is 64 or 128 long. Some entries will 1105 // never be populated. 1106 var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string 1107 1108 // mktag returns the string representation for an escape analysis tag. 1109 func mktag(mask int) *string { 1110 switch mask & EscMask { 1111 case EscNone, EscReturn: 1112 break 1113 1114 default: 1115 Fatal("escape mktag") 1116 } 1117 1118 if mask < len(tags) && tags[mask] != "" { 1119 return &tags[mask] 1120 } 1121 1122 s := fmt.Sprintf("esc:0x%x", mask) 1123 if mask < len(tags) { 1124 tags[mask] = s 1125 } 1126 return &s 1127 } 1128 1129 // parsetag decodes an escape analysis tag and returns the esc value. 1130 func parsetag(note *string) uint16 { 1131 if note == nil || !strings.HasPrefix(*note, "esc:") { 1132 return EscUnknown 1133 } 1134 em := uint16(atoi((*note)[4:])) 1135 if em == 0 { 1136 return EscNone 1137 } 1138 return em 1139 } 1140 1141 // describeEscape returns a string describing the escape tag. 1142 // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation 1143 // or a description of parameter flow, which takes the form of an optional "contentToHeap" 1144 // indicating that the content of this parameter is leaked to the heap, followed by a sequence 1145 // of level encodings separated by spaces, one for each parameter, where _ means no flow, 1146 // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow. 1147 // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences) 1148 // escapes to the heap, the parameter does not leak to the first output, but does leak directly 1149 // to the second output (and if there are more than two outputs, there is no flow to those.) 1150 func describeEscape(em uint16) string { 1151 var s string 1152 if em&EscMask == EscUnknown { 1153 s = "EscUnknown" 1154 } 1155 if em&EscMask == EscNone { 1156 s = "EscNone" 1157 } 1158 if em&EscMask == EscHeap { 1159 s = "EscHeap" 1160 } 1161 if em&EscMask == EscReturn { 1162 s = "EscReturn" 1163 } 1164 if em&EscMask == EscScope { 1165 s = "EscScope" 1166 } 1167 if em&EscContentEscapes != 0 { 1168 if s != "" { 1169 s += " " 1170 } 1171 s += "contentToHeap" 1172 } 1173 for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag { 1174 // See encoding description above 1175 if s != "" { 1176 s += " " 1177 } 1178 switch embits := em & bitsMaskForTag; embits { 1179 case 0: 1180 s += "_" 1181 case 1: 1182 s += "=" 1183 default: 1184 for i := uint16(0); i < embits-1; i++ { 1185 s += "*" 1186 } 1187 } 1188 1189 } 1190 return s 1191 } 1192 1193 // escassignfromtag models the input-to-output assignment flow of one of a function 1194 // calls arguments, where the flow is encoded in "note". 1195 func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 { 1196 em := parsetag(note) 1197 if src.Op == OLITERAL { 1198 return em 1199 } 1200 1201 if Debug['m'] > 2 { 1202 fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n", 1203 Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em)) 1204 } 1205 1206 if em == EscUnknown { 1207 escassign(e, &e.theSink, src) 1208 return em 1209 } 1210 1211 if em == EscNone { 1212 return em 1213 } 1214 1215 // If content inside parameter (reached via indirection) 1216 // escapes to heap, mark as such. 1217 if em&EscContentEscapes != 0 { 1218 escassign(e, &e.theSink, e.addDereference(src)) 1219 } 1220 1221 em0 := em 1222 for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next { 1223 // Prefer the lowest-level path to the reference (for escape purposes). 1224 // Two-bit encoding (for example. 1, 3, and 4 bits are other options) 1225 // 01 = 0-level 1226 // 10 = 1-level, (content escapes), 1227 // 11 = 2-level, (content of content escapes), 1228 embits := em & bitsMaskForTag 1229 if embits > 0 { 1230 n := src 1231 for i := uint16(0); i < embits-1; i++ { 1232 n = e.addDereference(n) // encode level>0 as indirections 1233 } 1234 escassign(e, dsts.N, n) 1235 } 1236 } 1237 // If there are too many outputs to fit in the tag, 1238 // that is handled at the encoding end as EscHeap, 1239 // so there is no need to check here. 1240 1241 if em != 0 && dsts == nil { 1242 Fatal("corrupt esc tag %q or messed up escretval list\n", note) 1243 } 1244 return em0 1245 } 1246 1247 func escassignDereference(e *EscState, dst *Node, src *Node) { 1248 if src.Op == OLITERAL { 1249 return 1250 } 1251 escassign(e, dst, e.addDereference(src)) 1252 } 1253 1254 // addDereference constructs a suitable OIND note applied to src. 1255 // Because this is for purposes of escape accounting, not execution, 1256 // some semantically dubious node combinations are (currently) possible. 1257 func (e *EscState) addDereference(n *Node) *Node { 1258 ind := Nod(OIND, n, nil) 1259 e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth 1260 ind.Lineno = n.Lineno 1261 t := n.Type 1262 if Istype(t, Tptr) { 1263 // This should model our own sloppy use of OIND to encode 1264 // decreasing levels of indirection; i.e., "indirecting" an array 1265 // might yield the type of an element. To be enhanced... 1266 t = t.Type 1267 } 1268 ind.Type = t 1269 return ind 1270 } 1271 1272 // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter. 1273 // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel. 1274 // If the encoding cannot describe the modified input level and output number, then EscHeap is returned. 1275 func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { 1276 // Flow+level is encoded in two bits. 1277 // 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel 1278 // 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful. 1279 if level.int() <= 0 && level.guaranteedDereference() > 0 { 1280 return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content. 1281 } 1282 if level.int() < 0 { 1283 return EscHeap 1284 } 1285 if level.int() > maxEncodedLevel { 1286 // Cannot encode larger values than maxEncodedLevel. 1287 level = levelFrom(maxEncodedLevel) 1288 } 1289 encoded := uint16(level.int() + 1) 1290 1291 shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits) 1292 old := (e >> shift) & bitsMaskForTag 1293 if old == 0 || encoded != 0 && encoded < old { 1294 old = encoded 1295 } 1296 1297 encodedFlow := old << shift 1298 if (encodedFlow>>shift)&bitsMaskForTag != old { 1299 // Encoding failure defaults to heap. 1300 return EscHeap 1301 } 1302 1303 return (e &^ (bitsMaskForTag << shift)) | encodedFlow 1304 } 1305 1306 func initEscretval(e *EscState, n *Node, fntype *Type) { 1307 i := 0 1308 nE := e.nodeEscState(n) 1309 nE.Escretval = nil // Suspect this is not nil for indirect calls. 1310 for t := getoutargx(fntype).Type; t != nil; t = t.Down { 1311 src := Nod(ONAME, nil, nil) 1312 buf := fmt.Sprintf(".out%d", i) 1313 i++ 1314 src.Sym = Lookup(buf) 1315 src.Type = t.Type 1316 src.Class = PAUTO 1317 src.Name.Curfn = Curfn 1318 e.nodeEscState(src).Escloopdepth = e.loopdepth 1319 src.Used = true 1320 src.Lineno = n.Lineno 1321 nE.Escretval = list(nE.Escretval, src) 1322 } 1323 } 1324 1325 // This is a bit messier than fortunate, pulled out of esc's big 1326 // switch for clarity. We either have the paramnodes, which may be 1327 // connected to other things through flows or we have the parameter type 1328 // nodes, which may be marked "noescape". Navigating the ast is slightly 1329 // different for methods vs plain functions and for imported vs 1330 // this-package 1331 func esccall(e *EscState, n *Node, up *Node) { 1332 var fntype *Type 1333 var indirect bool 1334 var fn *Node 1335 switch n.Op { 1336 default: 1337 Fatal("esccall") 1338 1339 case OCALLFUNC: 1340 fn = n.Left 1341 fntype = fn.Type 1342 indirect = fn.Op != ONAME || fn.Class != PFUNC 1343 1344 case OCALLMETH: 1345 fn = n.Left.Right.Sym.Def 1346 if fn != nil { 1347 fntype = fn.Type 1348 } else { 1349 fntype = n.Left.Type 1350 } 1351 1352 case OCALLINTER: 1353 fntype = n.Left.Type 1354 indirect = true 1355 } 1356 1357 ll := n.List 1358 if n.List != nil && n.List.Next == nil { 1359 a := n.List.N 1360 if a.Type.Etype == TSTRUCT && a.Type.Funarg != 0 { // f(g()). 1361 ll = e.nodeEscState(a).Escretval 1362 } 1363 } 1364 1365 if indirect { 1366 // We know nothing! 1367 // Leak all the parameters 1368 for ; ll != nil; ll = ll.Next { 1369 escassign(e, &e.theSink, ll.N) 1370 if Debug['m'] > 2 { 1371 fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1372 } 1373 } 1374 // Set up bogus outputs 1375 initEscretval(e, n, fntype) 1376 // If there is a receiver, it also leaks to heap. 1377 if n.Op != OCALLFUNC { 1378 t := getthisx(fntype).Type 1379 src := n.Left.Left 1380 if haspointers(t.Type) { 1381 escassign(e, &e.theSink, src) 1382 } 1383 } 1384 return 1385 } 1386 1387 nE := e.nodeEscState(n) 1388 if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && 1389 fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged { 1390 if Debug['m'] > 2 { 1391 fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) 1392 } 1393 1394 // function in same mutually recursive group. Incorporate into flow graph. 1395 // print("esc local fn: %N\n", fn->ntype); 1396 if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil { 1397 Fatal("graph inconsistency") 1398 } 1399 1400 // set up out list on this call node 1401 for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next { 1402 nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT) 1403 } 1404 1405 // Receiver. 1406 if n.Op != OCALLFUNC { 1407 escassign(e, fn.Name.Param.Ntype.Left.Left, n.Left.Left) 1408 } 1409 1410 var src *Node 1411 for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next { 1412 src = ll.N 1413 if lr.N.Isddd && !n.Isddd { 1414 // Introduce ODDDARG node to represent ... allocation. 1415 src = Nod(ODDDARG, nil, nil) 1416 src.Type = typ(TARRAY) 1417 src.Type.Type = lr.N.Type.Type 1418 src.Type.Bound = int64(count(ll)) 1419 src.Type = Ptrto(src.Type) // make pointer so it will be tracked 1420 src.Lineno = n.Lineno 1421 e.track(src) 1422 n.Right = src 1423 } 1424 1425 if lr.N.Left != nil { 1426 escassign(e, lr.N.Left, src) 1427 } 1428 if src != ll.N { 1429 break 1430 } 1431 } 1432 1433 // "..." arguments are untracked 1434 for ; ll != nil; ll = ll.Next { 1435 if Debug['m'] > 2 { 1436 fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1437 } 1438 escassign(e, &e.theSink, ll.N) 1439 } 1440 1441 return 1442 } 1443 1444 // Imported or completely analyzed function. Use the escape tags. 1445 if nE.Escretval != nil { 1446 Fatal("esc already decorated call %v\n", Nconv(n, obj.FmtSign)) 1447 } 1448 1449 if Debug['m'] > 2 { 1450 fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) 1451 } 1452 1453 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 1454 initEscretval(e, n, fntype) 1455 1456 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); 1457 1458 // Receiver. 1459 if n.Op != OCALLFUNC { 1460 t := getthisx(fntype).Type 1461 src := n.Left.Left 1462 if haspointers(t.Type) { 1463 escassignfromtag(e, t.Note, nE.Escretval, src) 1464 } 1465 } 1466 1467 for t := getinargx(fntype).Type; ll != nil; ll = ll.Next { 1468 src := ll.N 1469 if t.Isddd && !n.Isddd { 1470 // Introduce ODDDARG node to represent ... allocation. 1471 src = Nod(ODDDARG, nil, nil) 1472 src.Lineno = n.Lineno 1473 src.Type = typ(TARRAY) 1474 src.Type.Type = t.Type.Type 1475 src.Type.Bound = int64(count(ll)) 1476 src.Type = Ptrto(src.Type) // make pointer so it will be tracked 1477 e.track(src) 1478 n.Right = src 1479 } 1480 1481 if haspointers(t.Type) { 1482 if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC { 1483 a := src 1484 for a.Op == OCONVNOP { 1485 a = a.Left 1486 } 1487 switch a.Op { 1488 // The callee has already been analyzed, so its arguments have esc tags. 1489 // The argument is marked as not escaping at all. 1490 // Record that fact so that any temporary used for 1491 // synthesizing this expression can be reclaimed when 1492 // the function returns. 1493 // This 'noescape' is even stronger than the usual esc == EscNone. 1494 // src->esc == EscNone means that src does not escape the current function. 1495 // src->noescape = 1 here means that src does not escape this statement 1496 // in the current function. 1497 case OCALLPART, 1498 OCLOSURE, 1499 ODDDARG, 1500 OARRAYLIT, 1501 OPTRLIT, 1502 OSTRUCTLIT: 1503 a.Noescape = true 1504 } 1505 } 1506 } 1507 1508 if src != ll.N { 1509 break 1510 } 1511 t = t.Down 1512 } 1513 1514 // "..." arguments are untracked 1515 for ; ll != nil; ll = ll.Next { 1516 escassign(e, &e.theSink, ll.N) 1517 if Debug['m'] > 2 { 1518 fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1519 } 1520 } 1521 } 1522 1523 // escflows records the link src->dst in dst, throwing out some quick wins, 1524 // and also ensuring that dst is noted as a flow destination. 1525 func escflows(e *EscState, dst *Node, src *Node) { 1526 if dst == nil || src == nil || dst == src { 1527 return 1528 } 1529 1530 // Don't bother building a graph for scalars. 1531 if src.Type != nil && !haspointers(src.Type) { 1532 return 1533 } 1534 1535 if Debug['m'] > 2 { 1536 fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort)) 1537 } 1538 1539 dstE := e.nodeEscState(dst) 1540 if dstE.Escflowsrc == nil { 1541 e.dsts = list(e.dsts, dst) 1542 e.dstcount++ 1543 } 1544 1545 e.edgecount++ 1546 1547 dstE.Escflowsrc = list(dstE.Escflowsrc, src) 1548 } 1549 1550 // Whenever we hit a reference node, the level goes up by one, and whenever 1551 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 1552 // finding an OADDR just means we're following the upstream of a dereference, 1553 // so this address doesn't leak (yet). 1554 // If level == 0, it means the /value/ of this node can reach the root of this flood. 1555 // so if this node is an OADDR, it's argument should be marked as escaping iff 1556 // it's currfn/e->loopdepth are different from the flood's root. 1557 // Once an object has been moved to the heap, all of it's upstream should be considered 1558 // escaping to the global scope. 1559 func escflood(e *EscState, dst *Node) { 1560 switch dst.Op { 1561 case ONAME, OCLOSURE: 1562 break 1563 1564 default: 1565 return 1566 } 1567 1568 dstE := e.nodeEscState(dst) 1569 if Debug['m'] > 1 { 1570 fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth) 1571 } 1572 1573 for l := dstE.Escflowsrc; l != nil; l = l.Next { 1574 e.walkgen++ 1575 escwalk(e, levelFrom(0), dst, l.N) 1576 } 1577 } 1578 1579 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function. 1580 func funcOutputAndInput(dst, src *Node) bool { 1581 // Note if dst is marked as escaping, then "returned" is too weak. 1582 return dst.Op == ONAME && dst.Class == PPARAMOUT && 1583 src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn 1584 } 1585 1586 func escwalk(e *EscState, level Level, dst *Node, src *Node) { 1587 if src.Op == OLITERAL { 1588 return 1589 } 1590 srcE := e.nodeEscState(src) 1591 if srcE.Walkgen == e.walkgen { 1592 // Esclevels are vectors, do not compare as integers, 1593 // and must use "min" of old and new to guarantee 1594 // convergence. 1595 level = level.min(srcE.Esclevel) 1596 if level == srcE.Esclevel { 1597 return 1598 } 1599 } 1600 1601 srcE.Walkgen = e.walkgen 1602 srcE.Esclevel = level 1603 1604 if Debug['m'] > 1 { 1605 fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n", 1606 level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), e.curfnSym(src), srcE.Escloopdepth) 1607 } 1608 1609 e.pdepth++ 1610 1611 // Input parameter flowing to output parameter? 1612 var leaks bool 1613 dstE := e.nodeEscState(dst) 1614 if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap { 1615 // This case handles: 1616 // 1. return in 1617 // 2. return &in 1618 // 3. tmp := in; return &tmp 1619 // 4. return *in 1620 if Debug['m'] != 0 { 1621 if Debug['m'] == 1 { 1622 Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int()) 1623 } else { 1624 Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level) 1625 } 1626 } 1627 if src.Esc&EscMask != EscReturn { 1628 src.Esc = EscReturn | src.Esc&EscContentEscapes 1629 } 1630 src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level) 1631 goto recurse 1632 } 1633 1634 // If parameter content escapes to heap, set EscContentEscapes 1635 // Note minor confusion around escape from pointer-to-struct vs escape from struct 1636 if dst.Esc == EscHeap && 1637 src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope && 1638 level.int() > 0 { 1639 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1640 if Debug['m'] != 0 { 1641 Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort)) 1642 } 1643 } 1644 1645 leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < srcE.Escloopdepth 1646 1647 switch src.Op { 1648 case ONAME: 1649 if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope { 1650 if level.guaranteedDereference() > 0 { 1651 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1652 if Debug['m'] != 0 { 1653 if Debug['m'] == 1 { 1654 Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort)) 1655 } else { 1656 Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v", 1657 Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort)) 1658 } 1659 } 1660 } else { 1661 src.Esc = EscScope 1662 if Debug['m'] != 0 { 1663 if Debug['m'] == 1 { 1664 Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort)) 1665 } else { 1666 Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v", 1667 Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort)) 1668 } 1669 } 1670 } 1671 } 1672 1673 // Treat a PPARAMREF closure variable as equivalent to the 1674 // original variable. 1675 if src.Class == PPARAMREF { 1676 if leaks && Debug['m'] != 0 { 1677 Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort)) 1678 } 1679 escwalk(e, level, dst, src.Name.Param.Closure) 1680 } 1681 1682 case OPTRLIT, OADDR: 1683 if leaks { 1684 src.Esc = EscHeap 1685 addrescapes(src.Left) 1686 if Debug['m'] != 0 { 1687 p := src 1688 if p.Left.Op == OCLOSURE { 1689 p = p.Left // merely to satisfy error messages in tests 1690 } 1691 if Debug['m'] > 1 { 1692 Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v", 1693 Nconv(p, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth) 1694 } else { 1695 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort)) 1696 } 1697 } 1698 } 1699 1700 escwalk(e, level.dec(), dst, src.Left) 1701 1702 case OAPPEND: 1703 escwalk(e, level, dst, src.List.N) 1704 1705 case OARRAYLIT: 1706 if Isfixedarray(src.Type) { 1707 break 1708 } 1709 for ll := src.List; ll != nil; ll = ll.Next { 1710 escwalk(e, level.dec(), dst, ll.N.Right) 1711 } 1712 1713 fallthrough 1714 1715 case ODDDARG, 1716 OMAKECHAN, 1717 OMAKEMAP, 1718 OMAKESLICE, 1719 OARRAYRUNESTR, 1720 OARRAYBYTESTR, 1721 OSTRARRAYRUNE, 1722 OSTRARRAYBYTE, 1723 OADDSTR, 1724 OMAPLIT, 1725 ONEW, 1726 OCLOSURE, 1727 OCALLPART, 1728 ORUNESTR, 1729 OCONVIFACE: 1730 if leaks { 1731 src.Esc = EscHeap 1732 if Debug['m'] != 0 { 1733 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort)) 1734 } 1735 } 1736 1737 case ODOT, 1738 ODOTTYPE, 1739 OSLICE, 1740 OSLICEARR, 1741 OSLICE3, 1742 OSLICE3ARR, 1743 OSLICESTR: 1744 escwalk(e, level, dst, src.Left) 1745 1746 case OINDEX: 1747 if Isfixedarray(src.Left.Type) { 1748 escwalk(e, level, dst, src.Left) 1749 break 1750 } 1751 fallthrough 1752 1753 case ODOTPTR, OINDEXMAP, OIND: 1754 escwalk(e, level.inc(), dst, src.Left) 1755 1756 // In this case a link went directly to a call, but should really go 1757 // to the dummy .outN outputs that were created for the call that 1758 // themselves link to the inputs with levels adjusted. 1759 // See e.g. #10466 1760 // This can only happen with functions returning a single result. 1761 case OCALLMETH, OCALLFUNC, OCALLINTER: 1762 if srcE.Escretval != nil { 1763 if Debug['m'] > 1 { 1764 fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n", 1765 Ctxt.Line(int(lineno)), e.loopdepth, 1766 Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort)) 1767 } 1768 src = srcE.Escretval.N 1769 srcE = e.nodeEscState(src) 1770 } 1771 } 1772 1773 recurse: 1774 level = level.copy() 1775 for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next { 1776 escwalk(e, level, dst, ll.N) 1777 } 1778 1779 e.pdepth-- 1780 } 1781 1782 func esctag(e *EscState, func_ *Node) { 1783 func_.Esc = EscFuncTagged 1784 1785 // External functions are assumed unsafe, 1786 // unless //go:noescape is given before the declaration. 1787 if func_.Nbody == nil { 1788 if func_.Noescape { 1789 for t := getinargx(func_.Type).Type; t != nil; t = t.Down { 1790 if haspointers(t.Type) { 1791 t.Note = mktag(EscNone) 1792 } 1793 } 1794 } 1795 1796 return 1797 } 1798 1799 savefn := Curfn 1800 Curfn = func_ 1801 1802 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 1803 if ll.N.Op != ONAME { 1804 continue 1805 } 1806 1807 switch ll.N.Esc & EscMask { 1808 case EscNone, // not touched by escflood 1809 EscReturn: 1810 if haspointers(ll.N.Type) { // don't bother tagging for scalars 1811 ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc)) 1812 } 1813 1814 case EscHeap, // touched by escflood, moved to heap 1815 EscScope: // touched by escflood, value leaves scope 1816 break 1817 } 1818 } 1819 1820 Curfn = savefn 1821 } 1822