github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/src/cmd/compile/internal/gc/esc.go (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 package gc 6 7 import ( 8 "cmd/compile/internal/types" 9 "fmt" 10 "strconv" 11 "strings" 12 ) 13 14 // Run analysis on minimal sets of mutually recursive functions 15 // or single non-recursive functions, bottom up. 16 // 17 // Finding these sets is finding strongly connected components 18 // by reverse topological order in the static call graph. 19 // The algorithm (known as Tarjan's algorithm) for doing that is taken from 20 // Sedgewick, Algorithms, Second Edition, p. 482, with two adaptations. 21 // 22 // First, a hidden closure function (n.Func.IsHiddenClosure()) cannot be the 23 // root of a connected component. Refusing to use it as a root 24 // forces it into the component of the function in which it appears. 25 // This is more convenient for escape analysis. 26 // 27 // Second, each function becomes two virtual nodes in the graph, 28 // with numbers n and n+1. We record the function's node number as n 29 // but search from node n+1. If the search tells us that the component 30 // number (min) is n+1, we know that this is a trivial component: one function 31 // plus its closures. If the search tells us that the component number is 32 // n, then there was a path from node n+1 back to node n, meaning that 33 // the function set is mutually recursive. The escape analysis can be 34 // more precise when analyzing a single non-recursive function than 35 // when analyzing a set of mutually recursive functions. 36 37 type bottomUpVisitor struct { 38 analyze func([]*Node, bool) 39 visitgen uint32 40 nodeID map[*Node]uint32 41 stack []*Node 42 } 43 44 // visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list. 45 // It calls analyze with successive groups of functions, working from 46 // the bottom of the call graph upward. Each time analyze is called with 47 // a list of functions, every function on that list only calls other functions 48 // on the list or functions that have been passed in previous invocations of 49 // analyze. Closures appear in the same list as their outer functions. 50 // The lists are as short as possible while preserving those requirements. 51 // (In a typical program, many invocations of analyze will be passed just 52 // a single function.) The boolean argument 'recursive' passed to analyze 53 // specifies whether the functions on the list are mutually recursive. 54 // If recursive is false, the list consists of only a single function and its closures. 55 // If recursive is true, the list may still contain only a single function, 56 // if that function is itself recursive. 57 func visitBottomUp(list []*Node, analyze func(list []*Node, recursive bool)) { 58 var v bottomUpVisitor 59 v.analyze = analyze 60 v.nodeID = make(map[*Node]uint32) 61 for _, n := range list { 62 if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure() { 63 v.visit(n) 64 } 65 } 66 } 67 68 func (v *bottomUpVisitor) visit(n *Node) uint32 { 69 if id := v.nodeID[n]; id > 0 { 70 // already visited 71 return id 72 } 73 74 v.visitgen++ 75 id := v.visitgen 76 v.nodeID[n] = id 77 v.visitgen++ 78 min := v.visitgen 79 80 v.stack = append(v.stack, n) 81 min = v.visitcodelist(n.Nbody, min) 82 if (min == id || min == id+1) && !n.Func.IsHiddenClosure() { 83 // This node is the root of a strongly connected component. 84 85 // The original min passed to visitcodelist was v.nodeID[n]+1. 86 // If visitcodelist found its way back to v.nodeID[n], then this 87 // block is a set of mutually recursive functions. 88 // Otherwise it's just a lone function that does not recurse. 89 recursive := min == id 90 91 // Remove connected component from stack. 92 // Mark walkgen so that future visits return a large number 93 // so as not to affect the caller's min. 94 95 var i int 96 for i = len(v.stack) - 1; i >= 0; i-- { 97 x := v.stack[i] 98 if x == n { 99 break 100 } 101 v.nodeID[x] = ^uint32(0) 102 } 103 v.nodeID[n] = ^uint32(0) 104 block := v.stack[i:] 105 // Run escape analysis on this set of functions. 106 v.stack = v.stack[:i] 107 v.analyze(block, recursive) 108 } 109 110 return min 111 } 112 113 func (v *bottomUpVisitor) visitcodelist(l Nodes, min uint32) uint32 { 114 for _, n := range l.Slice() { 115 min = v.visitcode(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 = asNode(n.Left.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 e.nodeEscState(dst).Flowsrc. 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 []*Node) { 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 min8(a, b int8) int8 { 253 if a < b { 254 return a 255 } 256 return b 257 } 258 259 func max8(a, b int8) int8 { 260 if a > b { 261 return a 262 } 263 return b 264 } 265 266 // inc returns the level l + 1, representing the effect of an indirect (*) operation. 267 func (l Level) inc() Level { 268 if l.value <= MinLevel { 269 return Level{value: MinLevel} 270 } 271 return Level{value: satInc8(l.value), suffixValue: satInc8(l.suffixValue)} 272 } 273 274 // dec returns the level l - 1, representing the effect of an address-of (&) operation. 275 func (l Level) dec() Level { 276 if l.value <= MinLevel { 277 return Level{value: MinLevel} 278 } 279 return Level{value: l.value - 1, suffixValue: l.suffixValue - 1} 280 } 281 282 // copy returns the level for a copy of a value with level l. 283 func (l Level) copy() Level { 284 return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)} 285 } 286 287 func (l1 Level) min(l2 Level) Level { 288 return Level{ 289 value: min8(l1.value, l2.value), 290 suffixValue: min8(l1.suffixValue, l2.suffixValue)} 291 } 292 293 // guaranteedDereference returns the number of dereferences 294 // applied to a pointer before addresses are taken/generated. 295 // This is the maximum level computed from path suffixes starting 296 // with copies where paths flow from destination to source. 297 func (l Level) guaranteedDereference() int { 298 return int(l.suffixValue) 299 } 300 301 // An EscStep documents one step in the path from memory 302 // that is heap allocated to the (alleged) reason for the 303 // heap allocation. 304 type EscStep struct { 305 src, dst *Node // the endpoints of this edge in the escape-to-heap chain. 306 where *Node // sometimes the endpoints don't match source locations; set 'where' to make that right 307 parent *EscStep // used in flood to record path 308 why string // explanation for this step in the escape-to-heap chain 309 busy bool // used in prevent to snip cycles. 310 } 311 312 type NodeEscState struct { 313 Curfn *Node 314 Flowsrc []EscStep // flow(this, src) 315 Retval Nodes // on OCALLxxx, list of dummy return values 316 Loopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes 317 Level Level 318 Walkgen uint32 319 Maxextraloopdepth int32 320 } 321 322 func (e *EscState) nodeEscState(n *Node) *NodeEscState { 323 if nE, ok := n.Opt().(*NodeEscState); ok { 324 return nE 325 } 326 if n.Opt() != nil { 327 Fatalf("nodeEscState: opt in use (%T)", n.Opt()) 328 } 329 nE := &NodeEscState{ 330 Curfn: Curfn, 331 } 332 n.SetOpt(nE) 333 e.opts = append(e.opts, n) 334 return nE 335 } 336 337 func (e *EscState) track(n *Node) { 338 if Curfn == nil { 339 Fatalf("EscState.track: Curfn nil") 340 } 341 n.Esc = EscNone // until proven otherwise 342 nE := e.nodeEscState(n) 343 nE.Loopdepth = e.loopdepth 344 e.noesc = append(e.noesc, n) 345 } 346 347 // Escape constants are numbered in order of increasing "escapiness" 348 // to help make inferences be monotonic. With the exception of 349 // EscNever which is sticky, eX < eY means that eY is more exposed 350 // than eX, and hence replaces it in a conservative analysis. 351 const ( 352 EscUnknown = iota 353 EscNone // Does not escape to heap, result, or parameters. 354 EscReturn // Is returned or reachable from returned. 355 EscHeap // Reachable from the heap 356 EscNever // By construction will not escape. 357 EscBits = 3 358 EscMask = (1 << EscBits) - 1 359 EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap 360 EscReturnBits = EscBits + 1 361 // Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3 362 ) 363 364 // escMax returns the maximum of an existing escape value 365 // (and its additional parameter flow flags) and a new escape type. 366 func escMax(e, etype uint16) uint16 { 367 if e&EscMask >= EscHeap { 368 // normalize 369 if e&^EscMask != 0 { 370 Fatalf("Escape information had unexpected return encoding bits (w/ EscHeap, EscNever), e&EscMask=%v", e&EscMask) 371 } 372 } 373 if e&EscMask > etype { 374 return e 375 } 376 if etype == EscNone || etype == EscReturn { 377 return (e &^ EscMask) | etype 378 } 379 return etype 380 } 381 382 // For each input parameter to a function, the escapeReturnEncoding describes 383 // how the parameter may leak to the function's outputs. This is currently the 384 // "level" of the leak where level is 0 or larger (negative level means stored into 385 // something whose address is returned -- but that implies stored into the heap, 386 // hence EscHeap, which means that the details are not currently relevant. ) 387 const ( 388 bitsPerOutputInTag = 3 // For each output, the number of bits for a tag 389 bitsMaskForTag = uint16(1<<bitsPerOutputInTag) - 1 // The bit mask to extract a single tag. 390 maxEncodedLevel = int(bitsMaskForTag - 1) // The largest level that can be stored in a tag. 391 ) 392 393 type EscState struct { 394 // Fake node that all 395 // - return values and output variables 396 // - parameters on imported functions not marked 'safe' 397 // - assignments to global variables 398 // flow to. 399 theSink Node 400 401 dsts []*Node // all dst nodes 402 loopdepth int32 // for detecting nested loop scopes 403 pdepth int // for debug printing in recursions. 404 dstcount int // diagnostic 405 edgecount int // diagnostic 406 noesc []*Node // list of possible non-escaping nodes, for printing 407 recursive bool // recursive function or group of mutually recursive functions. 408 opts []*Node // nodes with .Opt initialized 409 walkgen uint32 410 } 411 412 func newEscState(recursive bool) *EscState { 413 e := new(EscState) 414 e.theSink.Op = ONAME 415 e.theSink.Orig = &e.theSink 416 e.theSink.SetClass(PEXTERN) 417 e.theSink.Sym = lookup(".sink") 418 e.nodeEscState(&e.theSink).Loopdepth = -1 419 e.recursive = recursive 420 return e 421 } 422 423 func (e *EscState) stepWalk(dst, src *Node, why string, parent *EscStep) *EscStep { 424 // TODO: keep a cache of these, mark entry/exit in escwalk to avoid allocation 425 // Or perhaps never mind, since it is disabled unless printing is on. 426 // We may want to revisit this, since the EscStep nodes would make 427 // an excellent replacement for the poorly-separated graph-build/graph-flood 428 // stages. 429 if Debug['m'] == 0 { 430 return nil 431 } 432 return &EscStep{src: src, dst: dst, why: why, parent: parent} 433 } 434 435 func (e *EscState) stepAssign(step *EscStep, dst, src *Node, why string) *EscStep { 436 if Debug['m'] == 0 { 437 return nil 438 } 439 if step != nil { // Caller may have known better. 440 if step.why == "" { 441 step.why = why 442 } 443 if step.dst == nil { 444 step.dst = dst 445 } 446 if step.src == nil { 447 step.src = src 448 } 449 return step 450 } 451 return &EscStep{src: src, dst: dst, why: why} 452 } 453 454 func (e *EscState) stepAssignWhere(dst, src *Node, why string, where *Node) *EscStep { 455 if Debug['m'] == 0 { 456 return nil 457 } 458 return &EscStep{src: src, dst: dst, why: why, where: where} 459 } 460 461 // funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way. 462 func funcSym(fn *Node) *types.Sym { 463 if fn == nil || fn.Func.Nname == nil { 464 return nil 465 } 466 return fn.Func.Nname.Sym 467 } 468 469 // curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way. 470 func (e *EscState) curfnSym(n *Node) *types.Sym { 471 nE := e.nodeEscState(n) 472 return funcSym(nE.Curfn) 473 } 474 475 func escAnalyze(all []*Node, recursive bool) { 476 e := newEscState(recursive) 477 478 for _, n := range all { 479 if n.Op == ODCLFUNC { 480 n.Esc = EscFuncPlanned 481 if Debug['m'] > 3 { 482 Dump("escAnalyze", n) 483 } 484 485 } 486 } 487 488 // flow-analyze functions 489 for _, n := range all { 490 if n.Op == ODCLFUNC { 491 e.escfunc(n) 492 } 493 } 494 495 // print("escapes: %d e.dsts, %d edges\n", e.dstcount, e.edgecount); 496 497 // visit the upstream of each dst, mark address nodes with 498 // addrescapes, mark parameters unsafe 499 escapes := make([]uint16, len(e.dsts)) 500 for i, n := range e.dsts { 501 escapes[i] = n.Esc 502 } 503 for _, n := range e.dsts { 504 e.escflood(n) 505 } 506 for { 507 done := true 508 for i, n := range e.dsts { 509 if n.Esc != escapes[i] { 510 done = false 511 if Debug['m'] > 2 { 512 Warnl(n.Pos, "Reflooding %v %S", e.curfnSym(n), n) 513 } 514 escapes[i] = n.Esc 515 e.escflood(n) 516 } 517 } 518 if done { 519 break 520 } 521 } 522 523 // for all top level functions, tag the typenodes corresponding to the param nodes 524 for _, n := range all { 525 if n.Op == ODCLFUNC { 526 e.esctag(n) 527 } 528 } 529 530 if Debug['m'] != 0 { 531 for _, n := range e.noesc { 532 if n.Esc == EscNone { 533 Warnl(n.Pos, "%v %S does not escape", e.curfnSym(n), n) 534 } 535 } 536 } 537 538 for _, x := range e.opts { 539 x.SetOpt(nil) 540 } 541 } 542 543 func (e *EscState) escfunc(fn *Node) { 544 // print("escfunc %N %s\n", fn.Func.Nname, e.recursive?"(recursive)":""); 545 if fn.Esc != EscFuncPlanned { 546 Fatalf("repeat escfunc %v", fn.Func.Nname) 547 } 548 fn.Esc = EscFuncStarted 549 550 saveld := e.loopdepth 551 e.loopdepth = 1 552 savefn := Curfn 553 Curfn = fn 554 555 for _, ln := range Curfn.Func.Dcl { 556 if ln.Op != ONAME { 557 continue 558 } 559 lnE := e.nodeEscState(ln) 560 switch ln.Class() { 561 // out params are in a loopdepth between the sink and all local variables 562 case PPARAMOUT: 563 lnE.Loopdepth = 0 564 565 case PPARAM: 566 lnE.Loopdepth = 1 567 if ln.Type != nil && !types.Haspointers(ln.Type) { 568 break 569 } 570 if Curfn.Nbody.Len() == 0 && !Curfn.Noescape() { 571 ln.Esc = EscHeap 572 } else { 573 ln.Esc = EscNone // prime for escflood later 574 } 575 e.noesc = append(e.noesc, ln) 576 } 577 } 578 579 // in a mutually recursive group we lose track of the return values 580 if e.recursive { 581 for _, ln := range Curfn.Func.Dcl { 582 if ln.Op == ONAME && ln.Class() == PPARAMOUT { 583 e.escflows(&e.theSink, ln, e.stepAssign(nil, ln, ln, "returned from recursive function")) 584 } 585 } 586 } 587 588 e.escloopdepthlist(Curfn.Nbody) 589 e.esclist(Curfn.Nbody, Curfn) 590 Curfn = savefn 591 e.loopdepth = saveld 592 } 593 594 // Mark labels that have no backjumps to them as not increasing e.loopdepth. 595 // Walk hasn't generated (goto|label).Left.Sym.Label yet, so we'll cheat 596 // and set it to one of the following two. Then in esc we'll clear it again. 597 var ( 598 looping Node 599 nonlooping Node 600 ) 601 602 func (e *EscState) escloopdepthlist(l Nodes) { 603 for _, n := range l.Slice() { 604 e.escloopdepth(n) 605 } 606 } 607 608 func (e *EscState) escloopdepth(n *Node) { 609 if n == nil { 610 return 611 } 612 613 e.escloopdepthlist(n.Ninit) 614 615 switch n.Op { 616 case OLABEL: 617 if n.Left == nil || n.Left.Sym == nil { 618 Fatalf("esc:label without label: %+v", n) 619 } 620 621 // Walk will complain about this label being already defined, but that's not until 622 // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc 623 // if(n.Left.Sym.Label != nil) 624 // fatal("escape analysis messed up analyzing label: %+N", n); 625 n.Left.Sym.Label = asTypesNode(&nonlooping) 626 627 case OGOTO: 628 if n.Left == nil || n.Left.Sym == nil { 629 Fatalf("esc:goto without label: %+v", n) 630 } 631 632 // If we come past one that's uninitialized, this must be a (harmless) forward jump 633 // but if it's set to nonlooping the label must have preceded this goto. 634 if asNode(n.Left.Sym.Label) == &nonlooping { 635 n.Left.Sym.Label = asTypesNode(&looping) 636 } 637 } 638 639 e.escloopdepth(n.Left) 640 e.escloopdepth(n.Right) 641 e.escloopdepthlist(n.List) 642 e.escloopdepthlist(n.Nbody) 643 e.escloopdepthlist(n.Rlist) 644 } 645 646 func (e *EscState) esclist(l Nodes, parent *Node) { 647 for _, n := range l.Slice() { 648 e.esc(n, parent) 649 } 650 } 651 652 func (e *EscState) esc(n *Node, parent *Node) { 653 if n == nil { 654 return 655 } 656 657 lno := setlineno(n) 658 659 // ninit logically runs at a different loopdepth than the rest of the for loop. 660 e.esclist(n.Ninit, n) 661 662 if n.Op == OFOR || n.Op == OFORUNTIL || n.Op == ORANGE { 663 e.loopdepth++ 664 } 665 666 // type switch variables have no ODCL. 667 // process type switch as declaration. 668 // must happen before processing of switch body, 669 // so before recursion. 670 if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW { 671 for _, cas := range n.List.Slice() { // cases 672 // it.N().Rlist is the variable per case 673 if cas.Rlist.Len() != 0 { 674 e.nodeEscState(cas.Rlist.First()).Loopdepth = e.loopdepth 675 } 676 } 677 } 678 679 // Big stuff escapes unconditionally 680 // "Big" conditions that were scattered around in walk have been gathered here 681 if n.Esc != EscHeap && n.Type != nil && 682 (n.Type.Width > MaxStackVarSize || 683 (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 || 684 n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { 685 if Debug['m'] > 2 { 686 Warnl(n.Pos, "%v is too large for stack", n) 687 } 688 n.Esc = EscHeap 689 addrescapes(n) 690 e.escassignSinkWhy(n, n, "too large for stack") // TODO category: tooLarge 691 } 692 693 e.esc(n.Left, n) 694 e.esc(n.Right, n) 695 e.esclist(n.Nbody, n) 696 e.esclist(n.List, n) 697 e.esclist(n.Rlist, n) 698 699 if n.Op == OFOR || n.Op == OFORUNTIL || n.Op == ORANGE { 700 e.loopdepth-- 701 } 702 703 if Debug['m'] > 2 { 704 fmt.Printf("%v:[%d] %v esc: %v\n", linestr(lineno), e.loopdepth, funcSym(Curfn), n) 705 } 706 707 switch n.Op { 708 // Record loop depth at declaration. 709 case ODCL: 710 if n.Left != nil { 711 e.nodeEscState(n.Left).Loopdepth = e.loopdepth 712 } 713 714 case OLABEL: 715 if asNode(n.Left.Sym.Label) == &nonlooping { 716 if Debug['m'] > 2 { 717 fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n) 718 } 719 } else if asNode(n.Left.Sym.Label) == &looping { 720 if Debug['m'] > 2 { 721 fmt.Printf("%v: %v looping label\n", linestr(lineno), n) 722 } 723 e.loopdepth++ 724 } 725 726 // See case OLABEL in escloopdepth above 727 // else if(n.Left.Sym.Label == nil) 728 // fatal("escape analysis missed or messed up a label: %+N", n); 729 730 n.Left.Sym.Label = nil 731 732 case ORANGE: 733 if n.List.Len() >= 2 { 734 // Everything but fixed array is a dereference. 735 736 // If fixed array is really the address of fixed array, 737 // it is also a dereference, because it is implicitly 738 // dereferenced (see #12588) 739 if n.Type.IsArray() && 740 !(n.Right.Type.IsPtr() && eqtype(n.Right.Type.Elem(), n.Type)) { 741 e.escassignWhyWhere(n.List.Second(), n.Right, "range", n) 742 } else { 743 e.escassignDereference(n.List.Second(), n.Right, e.stepAssignWhere(n.List.Second(), n.Right, "range-deref", n)) 744 } 745 } 746 747 case OSWITCH: 748 if n.Left != nil && n.Left.Op == OTYPESW { 749 for _, cas := range n.List.Slice() { 750 // cases 751 // n.Left.Right is the argument of the .(type), 752 // it.N().Rlist is the variable per case 753 if cas.Rlist.Len() != 0 { 754 e.escassignWhyWhere(cas.Rlist.First(), n.Left.Right, "switch case", n) 755 } 756 } 757 } 758 759 // Filter out the following special case. 760 // 761 // func (b *Buffer) Foo() { 762 // n, m := ... 763 // b.buf = b.buf[n:m] 764 // } 765 // 766 // This assignment is a no-op for escape analysis, 767 // it does not store any new pointers into b that were not already there. 768 // However, without this special case b will escape, because we assign to OIND/ODOTPTR. 769 case OAS, OASOP: 770 if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference 771 (n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation 772 (n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference 773 n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME 774 775 // Here we also assume that the statement will not contain calls, 776 // that is, that order will move any calls to init. 777 // Otherwise base ONAME value could change between the moments 778 // when we evaluate it for dst and for src. 779 // 780 // Note, this optimization does not apply to OSLICEARR, 781 // because it does introduce a new pointer into b that was not already there 782 // (pointer to b itself). After such assignment, if b contents escape, 783 // b escapes as well. If we ignore such OSLICEARR, we will conclude 784 // that b does not escape when b contents do. 785 if Debug['m'] != 0 { 786 Warnl(n.Pos, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left) 787 } 788 789 break 790 } 791 792 e.escassign(n.Left, n.Right, e.stepAssignWhere(nil, nil, "", n)) 793 794 case OAS2: // x,y = a,b 795 if n.List.Len() == n.Rlist.Len() { 796 rs := n.Rlist.Slice() 797 for i, n := range n.List.Slice() { 798 e.escassignWhyWhere(n, rs[i], "assign-pair", n) 799 } 800 } 801 802 case OAS2RECV: // v, ok = <-ch 803 e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-receive", n) 804 case OAS2MAPR: // v, ok = m[k] 805 e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-mapr", n) 806 case OAS2DOTTYPE: // v, ok = x.(type) 807 e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-dot-type", n) 808 809 case OSEND: // ch <- x 810 e.escassignSinkWhy(n, n.Right, "send") 811 812 case ODEFER: 813 if e.loopdepth == 1 { // top level 814 break 815 } 816 // arguments leak out of scope 817 // TODO: leak to a dummy node instead 818 // defer f(x) - f and x escape 819 e.escassignSinkWhy(n, n.Left.Left, "defer func") 820 e.escassignSinkWhy(n, n.Left.Right, "defer func ...") // ODDDARG for call 821 for _, arg := range n.Left.List.Slice() { 822 e.escassignSinkWhy(n, arg, "defer func arg") 823 } 824 825 case OPROC: 826 // go f(x) - f and x escape 827 e.escassignSinkWhy(n, n.Left.Left, "go func") 828 e.escassignSinkWhy(n, n.Left.Right, "go func ...") // ODDDARG for call 829 for _, arg := range n.Left.List.Slice() { 830 e.escassignSinkWhy(n, arg, "go func arg") 831 } 832 833 case OCALLMETH, OCALLFUNC, OCALLINTER: 834 e.esccall(n, parent) 835 836 // esccall already done on n.Rlist.First(). tie it's Retval to n.List 837 case OAS2FUNC: // x,y = f() 838 rs := e.nodeEscState(n.Rlist.First()).Retval.Slice() 839 for i, n := range n.List.Slice() { 840 if i >= len(rs) { 841 break 842 } 843 e.escassignWhyWhere(n, rs[i], "assign-pair-func-call", n) 844 } 845 if n.List.Len() != len(rs) { 846 Fatalf("esc oas2func") 847 } 848 849 case ORETURN: 850 retList := n.List 851 if retList.Len() == 1 && Curfn.Type.Results().NumFields() > 1 { 852 // OAS2FUNC in disguise 853 // esccall already done on n.List.First() 854 // tie e.nodeEscState(n.List.First()).Retval to Curfn.Func.Dcl PPARAMOUT's 855 retList = e.nodeEscState(n.List.First()).Retval 856 } 857 858 i := 0 859 for _, lrn := range Curfn.Func.Dcl { 860 if i >= retList.Len() { 861 break 862 } 863 if lrn.Op != ONAME || lrn.Class() != PPARAMOUT { 864 continue 865 } 866 e.escassignWhyWhere(lrn, retList.Index(i), "return", n) 867 i++ 868 } 869 870 if i < retList.Len() { 871 Fatalf("esc return list") 872 } 873 874 // Argument could leak through recover. 875 case OPANIC: 876 e.escassignSinkWhy(n, n.Left, "panic") 877 878 case OAPPEND: 879 if !n.Isddd() { 880 for _, nn := range n.List.Slice()[1:] { 881 e.escassignSinkWhy(n, nn, "appended to slice") // lose track of assign to dereference 882 } 883 } else { 884 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. 885 slice2 := n.List.Second() 886 e.escassignDereference(&e.theSink, slice2, e.stepAssignWhere(n, slice2, "appended slice...", n)) // lose track of assign of dereference 887 if Debug['m'] > 3 { 888 Warnl(n.Pos, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n) 889 } 890 } 891 e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too 892 893 case OCOPY: 894 e.escassignDereference(&e.theSink, n.Right, e.stepAssignWhere(n, n.Right, "copied slice", n)) // lose track of assign of dereference 895 896 case OCONV, OCONVNOP: 897 e.escassignWhyWhere(n, n.Left, "converted", n) 898 899 case OCONVIFACE: 900 e.track(n) 901 e.escassignWhyWhere(n, n.Left, "interface-converted", n) 902 903 case OARRAYLIT: 904 // Link values to array 905 for _, elt := range n.List.Slice() { 906 if elt.Op == OKEY { 907 elt = elt.Right 908 } 909 e.escassign(n, elt, e.stepAssignWhere(n, elt, "array literal element", n)) 910 } 911 912 case OSLICELIT: 913 // Slice is not leaked until proven otherwise 914 e.track(n) 915 // Link values to slice 916 for _, elt := range n.List.Slice() { 917 if elt.Op == OKEY { 918 elt = elt.Right 919 } 920 e.escassign(n, elt, e.stepAssignWhere(n, elt, "slice literal element", n)) 921 } 922 923 // Link values to struct. 924 case OSTRUCTLIT: 925 for _, elt := range n.List.Slice() { 926 e.escassignWhyWhere(n, elt.Left, "struct literal element", n) 927 } 928 929 case OPTRLIT: 930 e.track(n) 931 932 // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. 933 e.escassignWhyWhere(n, n.Left, "pointer literal [assign]", n) 934 935 case OCALLPART: 936 e.track(n) 937 938 // Contents make it to memory, lose track. 939 e.escassignSinkWhy(n, n.Left, "call part") 940 941 case OMAPLIT: 942 e.track(n) 943 // Keys and values make it to memory, lose track. 944 for _, elt := range n.List.Slice() { 945 e.escassignSinkWhy(n, elt.Left, "map literal key") 946 e.escassignSinkWhy(n, elt.Right, "map literal value") 947 } 948 949 case OCLOSURE: 950 // Link addresses of captured variables to closure. 951 for _, v := range n.Func.Cvars.Slice() { 952 if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs 953 continue 954 } 955 a := v.Name.Defn 956 if !v.Name.Byval() { 957 a = nod(OADDR, a, nil) 958 a.Pos = v.Pos 959 e.nodeEscState(a).Loopdepth = e.loopdepth 960 a = typecheck(a, Erv) 961 } 962 963 e.escassignWhyWhere(n, a, "captured by a closure", n) 964 } 965 fallthrough 966 967 case OMAKECHAN, 968 OMAKEMAP, 969 OMAKESLICE, 970 ONEW, 971 OARRAYRUNESTR, 972 OARRAYBYTESTR, 973 OSTRARRAYRUNE, 974 OSTRARRAYBYTE, 975 ORUNESTR: 976 e.track(n) 977 978 case OADDSTR: 979 e.track(n) 980 // Arguments of OADDSTR do not escape. 981 982 case OADDR: 983 // current loop depth is an upper bound on actual loop depth 984 // of addressed value. 985 e.track(n) 986 987 // for &x, use loop depth of x if known. 988 // it should always be known, but if not, be conservative 989 // and keep the current loop depth. 990 if n.Left.Op == ONAME { 991 switch n.Left.Class() { 992 case PAUTO: 993 nE := e.nodeEscState(n) 994 leftE := e.nodeEscState(n.Left) 995 if leftE.Loopdepth != 0 { 996 nE.Loopdepth = leftE.Loopdepth 997 } 998 999 // PPARAM is loop depth 1 always. 1000 // PPARAMOUT is loop depth 0 for writes 1001 // but considered loop depth 1 for address-of, 1002 // so that writing the address of one result 1003 // to another (or the same) result makes the 1004 // first result move to the heap. 1005 case PPARAM, PPARAMOUT: 1006 nE := e.nodeEscState(n) 1007 nE.Loopdepth = 1 1008 } 1009 } 1010 } 1011 1012 lineno = lno 1013 } 1014 1015 // escassignWhyWhere bundles a common case of 1016 // escassign(e, dst, src, e.stepAssignWhere(dst, src, reason, where)) 1017 func (e *EscState) escassignWhyWhere(dst, src *Node, reason string, where *Node) { 1018 var step *EscStep 1019 if Debug['m'] != 0 { 1020 step = e.stepAssignWhere(dst, src, reason, where) 1021 } 1022 e.escassign(dst, src, step) 1023 } 1024 1025 // escassignSinkWhy bundles a common case of 1026 // escassign(e, &e.theSink, src, e.stepAssign(nil, dst, src, reason)) 1027 func (e *EscState) escassignSinkWhy(dst, src *Node, reason string) { 1028 var step *EscStep 1029 if Debug['m'] != 0 { 1030 step = e.stepAssign(nil, dst, src, reason) 1031 } 1032 e.escassign(&e.theSink, src, step) 1033 } 1034 1035 // escassignSinkWhyWhere is escassignSinkWhy but includes a call site 1036 // for accurate location reporting. 1037 func (e *EscState) escassignSinkWhyWhere(dst, src *Node, reason string, call *Node) { 1038 var step *EscStep 1039 if Debug['m'] != 0 { 1040 step = e.stepAssignWhere(dst, src, reason, call) 1041 } 1042 e.escassign(&e.theSink, src, step) 1043 } 1044 1045 // Assert that expr somehow gets assigned to dst, if non nil. for 1046 // dst==nil, any name node expr still must be marked as being 1047 // evaluated in curfn. For expr==nil, dst must still be examined for 1048 // evaluations inside it (e.g *f(x) = y) 1049 func (e *EscState) escassign(dst, src *Node, step *EscStep) { 1050 if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX { 1051 return 1052 } 1053 1054 if Debug['m'] > 2 { 1055 fmt.Printf("%v:[%d] %v escassign: %S(%0j)[%v] = %S(%0j)[%v]\n", 1056 linestr(lineno), e.loopdepth, funcSym(Curfn), 1057 dst, dst, dst.Op, 1058 src, src, src.Op) 1059 } 1060 1061 setlineno(dst) 1062 1063 originalDst := dst 1064 dstwhy := "assigned" 1065 1066 // Analyze lhs of assignment. 1067 // Replace dst with &e.theSink if we can't track it. 1068 switch dst.Op { 1069 default: 1070 Dump("dst", dst) 1071 Fatalf("escassign: unexpected dst") 1072 1073 case OARRAYLIT, 1074 OSLICELIT, 1075 OCLOSURE, 1076 OCONV, 1077 OCONVIFACE, 1078 OCONVNOP, 1079 OMAPLIT, 1080 OSTRUCTLIT, 1081 OPTRLIT, 1082 ODDDARG, 1083 OCALLPART: 1084 1085 case ONAME: 1086 if dst.Class() == PEXTERN { 1087 dstwhy = "assigned to top level variable" 1088 dst = &e.theSink 1089 } 1090 1091 case ODOT: // treat "dst.x = src" as "dst = src" 1092 e.escassign(dst.Left, src, e.stepAssign(step, originalDst, src, "dot-equals")) 1093 return 1094 1095 case OINDEX: 1096 if dst.Left.Type.IsArray() { 1097 e.escassign(dst.Left, src, e.stepAssign(step, originalDst, src, "array-element-equals")) 1098 return 1099 } 1100 1101 dstwhy = "slice-element-equals" 1102 dst = &e.theSink // lose track of dereference 1103 1104 case OIND: 1105 dstwhy = "star-equals" 1106 dst = &e.theSink // lose track of dereference 1107 1108 case ODOTPTR: 1109 dstwhy = "star-dot-equals" 1110 dst = &e.theSink // lose track of dereference 1111 1112 // lose track of key and value 1113 case OINDEXMAP: 1114 e.escassign(&e.theSink, dst.Right, e.stepAssign(nil, originalDst, src, "key of map put")) 1115 dstwhy = "value of map put" 1116 dst = &e.theSink 1117 } 1118 1119 lno := setlineno(src) 1120 e.pdepth++ 1121 1122 switch src.Op { 1123 case OADDR, // dst = &x 1124 OIND, // dst = *x 1125 ODOTPTR, // dst = (*x).f 1126 ONAME, 1127 ODDDARG, 1128 OPTRLIT, 1129 OARRAYLIT, 1130 OSLICELIT, 1131 OMAPLIT, 1132 OSTRUCTLIT, 1133 OMAKECHAN, 1134 OMAKEMAP, 1135 OMAKESLICE, 1136 OARRAYRUNESTR, 1137 OARRAYBYTESTR, 1138 OSTRARRAYRUNE, 1139 OSTRARRAYBYTE, 1140 OADDSTR, 1141 ONEW, 1142 OCALLPART, 1143 ORUNESTR, 1144 OCONVIFACE: 1145 e.escflows(dst, src, e.stepAssign(step, originalDst, src, dstwhy)) 1146 1147 case OCLOSURE: 1148 // OCLOSURE is lowered to OPTRLIT, 1149 // insert OADDR to account for the additional indirection. 1150 a := nod(OADDR, src, nil) 1151 a.Pos = src.Pos 1152 e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth 1153 a.Type = types.NewPtr(src.Type) 1154 e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy)) 1155 1156 // Flowing multiple returns to a single dst happens when 1157 // analyzing "go f(g())": here g() flows to sink (issue 4529). 1158 case OCALLMETH, OCALLFUNC, OCALLINTER: 1159 for _, n := range e.nodeEscState(src).Retval.Slice() { 1160 e.escflows(dst, n, e.stepAssign(nil, originalDst, n, dstwhy)) 1161 } 1162 1163 // A non-pointer escaping from a struct does not concern us. 1164 case ODOT: 1165 if src.Type != nil && !types.Haspointers(src.Type) { 1166 break 1167 } 1168 fallthrough 1169 1170 // Conversions, field access, slice all preserve the input value. 1171 case OCONV, 1172 OCONVNOP, 1173 ODOTMETH, 1174 // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 1175 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 1176 OSLICE, 1177 OSLICE3, 1178 OSLICEARR, 1179 OSLICE3ARR, 1180 OSLICESTR: 1181 // Conversions, field access, slice all preserve the input value. 1182 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1183 1184 case ODOTTYPE, 1185 ODOTTYPE2: 1186 if src.Type != nil && !types.Haspointers(src.Type) { 1187 break 1188 } 1189 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1190 1191 case OAPPEND: 1192 // Append returns first argument. 1193 // Subsequent arguments are already leaked because they are operands to append. 1194 e.escassign(dst, src.List.First(), e.stepAssign(step, dst, src.List.First(), dstwhy)) 1195 1196 case OINDEX: 1197 // Index of array preserves input value. 1198 if src.Left.Type.IsArray() { 1199 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1200 } else { 1201 e.escflows(dst, src, e.stepAssign(step, originalDst, src, dstwhy)) 1202 } 1203 1204 // Might be pointer arithmetic, in which case 1205 // the operands flow into the result. 1206 // TODO(rsc): Decide what the story is here. This is unsettling. 1207 case OADD, 1208 OSUB, 1209 OOR, 1210 OXOR, 1211 OMUL, 1212 ODIV, 1213 OMOD, 1214 OLSH, 1215 ORSH, 1216 OAND, 1217 OANDNOT, 1218 OPLUS, 1219 OMINUS, 1220 OCOM: 1221 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1222 1223 e.escassign(dst, src.Right, e.stepAssign(step, originalDst, src, dstwhy)) 1224 } 1225 1226 e.pdepth-- 1227 lineno = lno 1228 } 1229 1230 // Common case for escapes is 16 bits 000000000xxxEEEE 1231 // where commonest cases for xxx encoding in-to-out pointer 1232 // flow are 000, 001, 010, 011 and EEEE is computed Esc bits. 1233 // Note width of xxx depends on value of constant 1234 // bitsPerOutputInTag -- expect 2 or 3, so in practice the 1235 // tag cache array is 64 or 128 long. Some entries will 1236 // never be populated. 1237 var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string 1238 1239 // mktag returns the string representation for an escape analysis tag. 1240 func mktag(mask int) string { 1241 switch mask & EscMask { 1242 case EscNone, EscReturn: 1243 default: 1244 Fatalf("escape mktag") 1245 } 1246 1247 if mask < len(tags) && tags[mask] != "" { 1248 return tags[mask] 1249 } 1250 1251 s := fmt.Sprintf("esc:0x%x", mask) 1252 if mask < len(tags) { 1253 tags[mask] = s 1254 } 1255 return s 1256 } 1257 1258 // parsetag decodes an escape analysis tag and returns the esc value. 1259 func parsetag(note string) uint16 { 1260 if !strings.HasPrefix(note, "esc:") { 1261 return EscUnknown 1262 } 1263 n, _ := strconv.ParseInt(note[4:], 0, 0) 1264 em := uint16(n) 1265 if em == 0 { 1266 return EscNone 1267 } 1268 return em 1269 } 1270 1271 // describeEscape returns a string describing the escape tag. 1272 // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation 1273 // or a description of parameter flow, which takes the form of an optional "contentToHeap" 1274 // indicating that the content of this parameter is leaked to the heap, followed by a sequence 1275 // of level encodings separated by spaces, one for each parameter, where _ means no flow, 1276 // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow. 1277 // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences) 1278 // escapes to the heap, the parameter does not leak to the first output, but does leak directly 1279 // to the second output (and if there are more than two outputs, there is no flow to those.) 1280 func describeEscape(em uint16) string { 1281 var s string 1282 if em&EscMask == EscUnknown { 1283 s = "EscUnknown" 1284 } 1285 if em&EscMask == EscNone { 1286 s = "EscNone" 1287 } 1288 if em&EscMask == EscHeap { 1289 s = "EscHeap" 1290 } 1291 if em&EscMask == EscReturn { 1292 s = "EscReturn" 1293 } 1294 if em&EscContentEscapes != 0 { 1295 if s != "" { 1296 s += " " 1297 } 1298 s += "contentToHeap" 1299 } 1300 for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag { 1301 // See encoding description above 1302 if s != "" { 1303 s += " " 1304 } 1305 switch embits := em & bitsMaskForTag; embits { 1306 case 0: 1307 s += "_" 1308 case 1: 1309 s += "=" 1310 default: 1311 for i := uint16(0); i < embits-1; i++ { 1312 s += "*" 1313 } 1314 } 1315 1316 } 1317 return s 1318 } 1319 1320 // escassignfromtag models the input-to-output assignment flow of one of a function 1321 // calls arguments, where the flow is encoded in "note". 1322 func (e *EscState) escassignfromtag(note string, dsts Nodes, src, call *Node) uint16 { 1323 em := parsetag(note) 1324 if src.Op == OLITERAL { 1325 return em 1326 } 1327 1328 if Debug['m'] > 3 { 1329 fmt.Printf("%v::assignfromtag:: src=%S, em=%s\n", 1330 linestr(lineno), src, describeEscape(em)) 1331 } 1332 1333 if em == EscUnknown { 1334 e.escassignSinkWhyWhere(src, src, "passed to call[argument escapes]", call) 1335 return em 1336 } 1337 1338 if em == EscNone { 1339 return em 1340 } 1341 1342 // If content inside parameter (reached via indirection) 1343 // escapes to heap, mark as such. 1344 if em&EscContentEscapes != 0 { 1345 e.escassign(&e.theSink, e.addDereference(src), e.stepAssignWhere(src, src, "passed to call[argument content escapes]", call)) 1346 } 1347 1348 em0 := em 1349 dstsi := 0 1350 for em >>= EscReturnBits; em != 0 && dstsi < dsts.Len(); em = em >> bitsPerOutputInTag { 1351 // Prefer the lowest-level path to the reference (for escape purposes). 1352 // Two-bit encoding (for example. 1, 3, and 4 bits are other options) 1353 // 01 = 0-level 1354 // 10 = 1-level, (content escapes), 1355 // 11 = 2-level, (content of content escapes), 1356 embits := em & bitsMaskForTag 1357 if embits > 0 { 1358 n := src 1359 for i := uint16(0); i < embits-1; i++ { 1360 n = e.addDereference(n) // encode level>0 as indirections 1361 } 1362 e.escassign(dsts.Index(dstsi), n, e.stepAssignWhere(dsts.Index(dstsi), src, "passed-to-and-returned-from-call", call)) 1363 } 1364 dstsi++ 1365 } 1366 // If there are too many outputs to fit in the tag, 1367 // that is handled at the encoding end as EscHeap, 1368 // so there is no need to check here. 1369 1370 if em != 0 && dstsi >= dsts.Len() { 1371 Fatalf("corrupt esc tag %q or messed up escretval list\n", note) 1372 } 1373 return em0 1374 } 1375 1376 func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) { 1377 if src.Op == OLITERAL { 1378 return 1379 } 1380 e.escassign(dst, e.addDereference(src), step) 1381 } 1382 1383 // addDereference constructs a suitable OIND note applied to src. 1384 // Because this is for purposes of escape accounting, not execution, 1385 // some semantically dubious node combinations are (currently) possible. 1386 func (e *EscState) addDereference(n *Node) *Node { 1387 ind := nod(OIND, n, nil) 1388 e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth 1389 ind.Pos = n.Pos 1390 t := n.Type 1391 if t.IsKind(types.Tptr) { 1392 // This should model our own sloppy use of OIND to encode 1393 // decreasing levels of indirection; i.e., "indirecting" an array 1394 // might yield the type of an element. To be enhanced... 1395 t = t.Elem() 1396 } 1397 ind.Type = t 1398 return ind 1399 } 1400 1401 // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter. 1402 // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel. 1403 // If the encoding cannot describe the modified input level and output number, then EscHeap is returned. 1404 func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { 1405 // Flow+level is encoded in two bits. 1406 // 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel 1407 // 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful. 1408 if level.int() <= 0 && level.guaranteedDereference() > 0 { 1409 return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content. 1410 } 1411 if level.int() < 0 { 1412 return EscHeap 1413 } 1414 if level.int() > maxEncodedLevel { 1415 // Cannot encode larger values than maxEncodedLevel. 1416 level = levelFrom(maxEncodedLevel) 1417 } 1418 encoded := uint16(level.int() + 1) 1419 1420 shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits) 1421 old := (e >> shift) & bitsMaskForTag 1422 if old == 0 || encoded != 0 && encoded < old { 1423 old = encoded 1424 } 1425 1426 encodedFlow := old << shift 1427 if (encodedFlow>>shift)&bitsMaskForTag != old { 1428 // Encoding failure defaults to heap. 1429 return EscHeap 1430 } 1431 1432 return (e &^ (bitsMaskForTag << shift)) | encodedFlow 1433 } 1434 1435 func (e *EscState) initEscRetval(call *Node, fntype *types.Type) { 1436 cE := e.nodeEscState(call) 1437 cE.Retval.Set(nil) // Suspect this is not nil for indirect calls. 1438 for i, f := range fntype.Results().Fields().Slice() { 1439 buf := fmt.Sprintf(".out%d", i) 1440 ret := newname(lookup(buf)) 1441 ret.SetAddable(false) // TODO(mdempsky): Seems suspicious. 1442 ret.Type = f.Type 1443 ret.SetClass(PAUTO) 1444 ret.Name.Curfn = Curfn 1445 e.nodeEscState(ret).Loopdepth = e.loopdepth 1446 ret.Name.SetUsed(true) 1447 ret.Pos = call.Pos 1448 cE.Retval.Append(ret) 1449 } 1450 } 1451 1452 // This is a bit messier than fortunate, pulled out of esc's big 1453 // switch for clarity. We either have the paramnodes, which may be 1454 // connected to other things through flows or we have the parameter type 1455 // nodes, which may be marked "noescape". Navigating the ast is slightly 1456 // different for methods vs plain functions and for imported vs 1457 // this-package 1458 func (e *EscState) esccall(call *Node, parent *Node) { 1459 var fntype *types.Type 1460 var indirect bool 1461 var fn *Node 1462 switch call.Op { 1463 default: 1464 Fatalf("esccall") 1465 1466 case OCALLFUNC: 1467 fn = call.Left 1468 fntype = fn.Type 1469 indirect = fn.Op != ONAME || fn.Class() != PFUNC 1470 1471 case OCALLMETH: 1472 fn = asNode(call.Left.Sym.Def) 1473 if fn != nil { 1474 fntype = fn.Type 1475 } else { 1476 fntype = call.Left.Type 1477 } 1478 1479 case OCALLINTER: 1480 fntype = call.Left.Type 1481 indirect = true 1482 } 1483 1484 argList := call.List 1485 if argList.Len() == 1 { 1486 arg := argList.First() 1487 if arg.Type.IsFuncArgStruct() { // f(g()) 1488 argList = e.nodeEscState(arg).Retval 1489 } 1490 } 1491 1492 args := argList.Slice() 1493 1494 if indirect { 1495 // We know nothing! 1496 // Leak all the parameters 1497 for _, arg := range args { 1498 e.escassignSinkWhy(call, arg, "parameter to indirect call") 1499 if Debug['m'] > 3 { 1500 fmt.Printf("%v::esccall:: indirect call <- %S, untracked\n", linestr(lineno), arg) 1501 } 1502 } 1503 // Set up bogus outputs 1504 e.initEscRetval(call, fntype) 1505 // If there is a receiver, it also leaks to heap. 1506 if call.Op != OCALLFUNC { 1507 rf := fntype.Recv() 1508 r := call.Left.Left 1509 if types.Haspointers(rf.Type) { 1510 e.escassignSinkWhy(call, r, "receiver in indirect call") 1511 } 1512 } else { // indirect and OCALLFUNC = could be captured variables, too. (#14409) 1513 rets := e.nodeEscState(call).Retval.Slice() 1514 for _, ret := range rets { 1515 e.escassignDereference(ret, fn, e.stepAssignWhere(ret, fn, "captured by called closure", call)) 1516 } 1517 } 1518 return 1519 } 1520 1521 cE := e.nodeEscState(call) 1522 if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && 1523 fn.Name.Defn != nil && fn.Name.Defn.Nbody.Len() != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged { 1524 if Debug['m'] > 3 { 1525 fmt.Printf("%v::esccall:: %S in recursive group\n", linestr(lineno), call) 1526 } 1527 1528 // function in same mutually recursive group. Incorporate into flow graph. 1529 // print("esc local fn: %N\n", fn.Func.Ntype); 1530 if fn.Name.Defn.Esc == EscFuncUnknown || cE.Retval.Len() != 0 { 1531 Fatalf("graph inconsistency") 1532 } 1533 1534 sawRcvr := false 1535 for _, n := range fn.Name.Defn.Func.Dcl { 1536 switch n.Class() { 1537 case PPARAM: 1538 if call.Op != OCALLFUNC && !sawRcvr { 1539 e.escassignWhyWhere(n, call.Left.Left, "call receiver", call) 1540 sawRcvr = true 1541 continue 1542 } 1543 if len(args) == 0 { 1544 continue 1545 } 1546 arg := args[0] 1547 if n.Isddd() && !call.Isddd() { 1548 // Introduce ODDDARG node to represent ... allocation. 1549 arg = nod(ODDDARG, nil, nil) 1550 arr := types.NewArray(n.Type.Elem(), int64(len(args))) 1551 arg.Type = types.NewPtr(arr) // make pointer so it will be tracked 1552 arg.Pos = call.Pos 1553 e.track(arg) 1554 call.Right = arg 1555 } 1556 e.escassignWhyWhere(n, arg, "arg to recursive call", call) // TODO this message needs help. 1557 if arg != args[0] { 1558 // "..." arguments are untracked 1559 for _, a := range args { 1560 if Debug['m'] > 3 { 1561 fmt.Printf("%v::esccall:: ... <- %S, untracked\n", linestr(lineno), a) 1562 } 1563 e.escassignSinkWhyWhere(arg, a, "... arg to recursive call", call) 1564 } 1565 // No more PPARAM processing, but keep 1566 // going for PPARAMOUT. 1567 args = nil 1568 continue 1569 } 1570 args = args[1:] 1571 1572 case PPARAMOUT: 1573 cE.Retval.Append(n) 1574 } 1575 } 1576 1577 return 1578 } 1579 1580 // Imported or completely analyzed function. Use the escape tags. 1581 if cE.Retval.Len() != 0 { 1582 Fatalf("esc already decorated call %+v\n", call) 1583 } 1584 1585 if Debug['m'] > 3 { 1586 fmt.Printf("%v::esccall:: %S not recursive\n", linestr(lineno), call) 1587 } 1588 1589 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 1590 e.initEscRetval(call, fntype) 1591 1592 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, e.nodeEscState(call).Retval); 1593 1594 // Receiver. 1595 if call.Op != OCALLFUNC { 1596 rf := fntype.Recv() 1597 r := call.Left.Left 1598 if types.Haspointers(rf.Type) { 1599 e.escassignfromtag(rf.Note, cE.Retval, r, call) 1600 } 1601 } 1602 1603 for i, param := range fntype.Params().FieldSlice() { 1604 note := param.Note 1605 var arg *Node 1606 if param.Isddd() && !call.Isddd() { 1607 rest := args[i:] 1608 if len(rest) == 0 { 1609 break 1610 } 1611 1612 // Introduce ODDDARG node to represent ... allocation. 1613 arg = nod(ODDDARG, nil, nil) 1614 arg.Pos = call.Pos 1615 arr := types.NewArray(param.Type.Elem(), int64(len(rest))) 1616 arg.Type = types.NewPtr(arr) // make pointer so it will be tracked 1617 e.track(arg) 1618 call.Right = arg 1619 1620 // Store arguments into slice for ... arg. 1621 for _, a := range rest { 1622 if Debug['m'] > 3 { 1623 fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), a) 1624 } 1625 if note == uintptrEscapesTag { 1626 e.escassignSinkWhyWhere(arg, a, "arg to uintptrescapes ...", call) 1627 } else { 1628 e.escassignWhyWhere(arg, a, "arg to ...", call) 1629 } 1630 } 1631 } else { 1632 arg = args[i] 1633 if note == uintptrEscapesTag { 1634 e.escassignSinkWhy(arg, arg, "escaping uintptr") 1635 } 1636 } 1637 1638 if types.Haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC { 1639 a := arg 1640 for a.Op == OCONVNOP { 1641 a = a.Left 1642 } 1643 switch a.Op { 1644 // The callee has already been analyzed, so its arguments have esc tags. 1645 // The argument is marked as not escaping at all. 1646 // Record that fact so that any temporary used for 1647 // synthesizing this expression can be reclaimed when 1648 // the function returns. 1649 // This 'noescape' is even stronger than the usual esc == EscNone. 1650 // arg.Esc == EscNone means that arg does not escape the current function. 1651 // arg.SetNoescape(true) here means that arg does not escape this statement 1652 // in the current function. 1653 case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT: 1654 a.SetNoescape(true) 1655 } 1656 } 1657 } 1658 } 1659 1660 // escflows records the link src->dst in dst, throwing out some quick wins, 1661 // and also ensuring that dst is noted as a flow destination. 1662 func (e *EscState) escflows(dst, src *Node, why *EscStep) { 1663 if dst == nil || src == nil || dst == src { 1664 return 1665 } 1666 1667 // Don't bother building a graph for scalars. 1668 if src.Type != nil && !types.Haspointers(src.Type) && !isReflectHeaderDataField(src) { 1669 if Debug['m'] > 3 { 1670 fmt.Printf("%v::NOT flows:: %S <- %S\n", linestr(lineno), dst, src) 1671 } 1672 return 1673 } 1674 1675 if Debug['m'] > 3 { 1676 fmt.Printf("%v::flows:: %S <- %S\n", linestr(lineno), dst, src) 1677 } 1678 1679 dstE := e.nodeEscState(dst) 1680 if len(dstE.Flowsrc) == 0 { 1681 e.dsts = append(e.dsts, dst) 1682 e.dstcount++ 1683 } 1684 1685 e.edgecount++ 1686 1687 if why == nil { 1688 dstE.Flowsrc = append(dstE.Flowsrc, EscStep{src: src}) 1689 } else { 1690 starwhy := *why 1691 starwhy.src = src // TODO: need to reconcile this w/ needs of explanations. 1692 dstE.Flowsrc = append(dstE.Flowsrc, starwhy) 1693 } 1694 } 1695 1696 // Whenever we hit a reference node, the level goes up by one, and whenever 1697 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 1698 // finding an OADDR just means we're following the upstream of a dereference, 1699 // so this address doesn't leak (yet). 1700 // If level == 0, it means the /value/ of this node can reach the root of this flood. 1701 // so if this node is an OADDR, its argument should be marked as escaping iff 1702 // its currfn/e.loopdepth are different from the flood's root. 1703 // Once an object has been moved to the heap, all of its upstream should be considered 1704 // escaping to the global scope. 1705 func (e *EscState) escflood(dst *Node) { 1706 switch dst.Op { 1707 case ONAME, OCLOSURE: 1708 default: 1709 return 1710 } 1711 1712 dstE := e.nodeEscState(dst) 1713 if Debug['m'] > 2 { 1714 fmt.Printf("\nescflood:%d: dst %S scope:%v[%d]\n", e.walkgen, dst, e.curfnSym(dst), dstE.Loopdepth) 1715 } 1716 1717 for i := range dstE.Flowsrc { 1718 e.walkgen++ 1719 s := &dstE.Flowsrc[i] 1720 s.parent = nil 1721 e.escwalk(levelFrom(0), dst, s.src, s) 1722 } 1723 } 1724 1725 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function. 1726 func funcOutputAndInput(dst, src *Node) bool { 1727 // Note if dst is marked as escaping, then "returned" is too weak. 1728 return dst.Op == ONAME && dst.Class() == PPARAMOUT && 1729 src.Op == ONAME && src.Class() == PPARAM && src.Name.Curfn == dst.Name.Curfn 1730 } 1731 1732 func (es *EscStep) describe(src *Node) { 1733 if Debug['m'] < 2 { 1734 return 1735 } 1736 step0 := es 1737 for step := step0; step != nil && !step.busy; step = step.parent { 1738 // TODO: We get cycles. Trigger is i = &i (where var i interface{}) 1739 step.busy = true 1740 // The trail is a little odd because of how the 1741 // graph is constructed. The link to the current 1742 // Node is parent.src unless parent is nil in which 1743 // case it is step.dst. 1744 nextDest := step.parent 1745 dst := step.dst 1746 where := step.where 1747 if nextDest != nil { 1748 dst = nextDest.src 1749 } 1750 if where == nil { 1751 where = dst 1752 } 1753 Warnl(src.Pos, "\tfrom %v (%s) at %s", dst, step.why, where.Line()) 1754 } 1755 for step := step0; step != nil && step.busy; step = step.parent { 1756 step.busy = false 1757 } 1758 } 1759 1760 const NOTALOOPDEPTH = -1 1761 1762 func (e *EscState) escwalk(level Level, dst *Node, src *Node, step *EscStep) { 1763 e.escwalkBody(level, dst, src, step, NOTALOOPDEPTH) 1764 } 1765 1766 func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep, extraloopdepth int32) { 1767 if src.Op == OLITERAL { 1768 return 1769 } 1770 srcE := e.nodeEscState(src) 1771 if srcE.Walkgen == e.walkgen { 1772 // Esclevels are vectors, do not compare as integers, 1773 // and must use "min" of old and new to guarantee 1774 // convergence. 1775 level = level.min(srcE.Level) 1776 if level == srcE.Level { 1777 // Have we been here already with an extraloopdepth, 1778 // or is the extraloopdepth provided no improvement on 1779 // what's already been seen? 1780 if srcE.Maxextraloopdepth >= extraloopdepth || srcE.Loopdepth >= extraloopdepth { 1781 return 1782 } 1783 srcE.Maxextraloopdepth = extraloopdepth 1784 } 1785 } else { // srcE.Walkgen < e.walkgen -- first time, reset this. 1786 srcE.Maxextraloopdepth = NOTALOOPDEPTH 1787 } 1788 1789 srcE.Walkgen = e.walkgen 1790 srcE.Level = level 1791 modSrcLoopdepth := srcE.Loopdepth 1792 1793 if extraloopdepth > modSrcLoopdepth { 1794 modSrcLoopdepth = extraloopdepth 1795 } 1796 1797 if Debug['m'] > 2 { 1798 fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %S(%0j) scope:%v[%d] extraloopdepth=%v\n", 1799 level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", src.Op, src, src, e.curfnSym(src), srcE.Loopdepth, extraloopdepth) 1800 } 1801 1802 e.pdepth++ 1803 1804 // Input parameter flowing to output parameter? 1805 var leaks bool 1806 var osrcesc uint16 // used to prevent duplicate error messages 1807 1808 dstE := e.nodeEscState(dst) 1809 if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscHeap && dst.Esc != EscHeap { 1810 // This case handles: 1811 // 1. return in 1812 // 2. return &in 1813 // 3. tmp := in; return &tmp 1814 // 4. return *in 1815 if Debug['m'] != 0 { 1816 if Debug['m'] <= 2 { 1817 Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int()) 1818 step.describe(src) 1819 } else { 1820 Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level) 1821 } 1822 } 1823 if src.Esc&EscMask != EscReturn { 1824 src.Esc = EscReturn | src.Esc&EscContentEscapes 1825 } 1826 src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level) 1827 goto recurse 1828 } 1829 1830 // If parameter content escapes to heap, set EscContentEscapes 1831 // Note minor confusion around escape from pointer-to-struct vs escape from struct 1832 if dst.Esc == EscHeap && 1833 src.Op == ONAME && src.Class() == PPARAM && src.Esc&EscMask < EscHeap && 1834 level.int() > 0 { 1835 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1836 if Debug['m'] != 0 { 1837 Warnl(src.Pos, "mark escaped content: %S", src) 1838 step.describe(src) 1839 } 1840 } 1841 1842 leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Loopdepth < modSrcLoopdepth 1843 leaks = leaks || level.int() <= 0 && dst.Esc&EscMask == EscHeap 1844 1845 osrcesc = src.Esc 1846 switch src.Op { 1847 case ONAME: 1848 if src.Class() == PPARAM && (leaks || dstE.Loopdepth < 0) && src.Esc&EscMask < EscHeap { 1849 if level.guaranteedDereference() > 0 { 1850 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1851 if Debug['m'] != 0 { 1852 if Debug['m'] <= 2 { 1853 if osrcesc != src.Esc { 1854 Warnl(src.Pos, "leaking param content: %S", src) 1855 step.describe(src) 1856 } 1857 } else { 1858 Warnl(src.Pos, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S", 1859 src, level, dstE.Loopdepth, modSrcLoopdepth, dst) 1860 } 1861 } 1862 } else { 1863 src.Esc = EscHeap 1864 if Debug['m'] != 0 { 1865 if Debug['m'] <= 2 { 1866 Warnl(src.Pos, "leaking param: %S", src) 1867 step.describe(src) 1868 } else { 1869 Warnl(src.Pos, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S", 1870 src, level, dstE.Loopdepth, modSrcLoopdepth, dst) 1871 } 1872 } 1873 } 1874 } 1875 1876 // Treat a captured closure variable as equivalent to the 1877 // original variable. 1878 if src.IsClosureVar() { 1879 if leaks && Debug['m'] != 0 { 1880 Warnl(src.Pos, "leaking closure reference %S", src) 1881 step.describe(src) 1882 } 1883 e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step)) 1884 } 1885 1886 case OPTRLIT, OADDR: 1887 why := "pointer literal" 1888 if src.Op == OADDR { 1889 why = "address-of" 1890 } 1891 if leaks { 1892 src.Esc = EscHeap 1893 if Debug['m'] != 0 && osrcesc != src.Esc { 1894 p := src 1895 if p.Left.Op == OCLOSURE { 1896 p = p.Left // merely to satisfy error messages in tests 1897 } 1898 if Debug['m'] > 2 { 1899 Warnl(src.Pos, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v", 1900 p, level, dst, dstE.Loopdepth, modSrcLoopdepth) 1901 } else { 1902 Warnl(src.Pos, "%S escapes to heap", p) 1903 step.describe(src) 1904 } 1905 } 1906 addrescapes(src.Left) 1907 e.escwalkBody(level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth) 1908 extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op 1909 } else { 1910 e.escwalk(level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step)) 1911 } 1912 1913 case OAPPEND: 1914 e.escwalk(level, dst, src.List.First(), e.stepWalk(dst, src.List.First(), "append-first-arg", step)) 1915 1916 case ODDDARG: 1917 if leaks { 1918 src.Esc = EscHeap 1919 if Debug['m'] != 0 && osrcesc != src.Esc { 1920 Warnl(src.Pos, "%S escapes to heap", src) 1921 step.describe(src) 1922 } 1923 extraloopdepth = modSrcLoopdepth 1924 } 1925 // similar to a slice arraylit and its args. 1926 level = level.dec() 1927 1928 case OSLICELIT: 1929 for _, elt := range src.List.Slice() { 1930 if elt.Op == OKEY { 1931 elt = elt.Right 1932 } 1933 e.escwalk(level.dec(), dst, elt, e.stepWalk(dst, elt, "slice-literal-element", step)) 1934 } 1935 1936 fallthrough 1937 1938 case OMAKECHAN, 1939 OMAKEMAP, 1940 OMAKESLICE, 1941 OARRAYRUNESTR, 1942 OARRAYBYTESTR, 1943 OSTRARRAYRUNE, 1944 OSTRARRAYBYTE, 1945 OADDSTR, 1946 OMAPLIT, 1947 ONEW, 1948 OCLOSURE, 1949 OCALLPART, 1950 ORUNESTR, 1951 OCONVIFACE: 1952 if leaks { 1953 src.Esc = EscHeap 1954 if Debug['m'] != 0 && osrcesc != src.Esc { 1955 Warnl(src.Pos, "%S escapes to heap", src) 1956 step.describe(src) 1957 } 1958 extraloopdepth = modSrcLoopdepth 1959 } 1960 1961 case ODOT, 1962 ODOTTYPE: 1963 e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "dot", step)) 1964 1965 case 1966 OSLICE, 1967 OSLICEARR, 1968 OSLICE3, 1969 OSLICE3ARR, 1970 OSLICESTR: 1971 e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "slice", step)) 1972 1973 case OINDEX: 1974 if src.Left.Type.IsArray() { 1975 e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "fixed-array-index-of", step)) 1976 break 1977 } 1978 fallthrough 1979 1980 case ODOTPTR: 1981 e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "dot of pointer", step)) 1982 case OINDEXMAP: 1983 e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "map index", step)) 1984 case OIND: 1985 e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "indirection", step)) 1986 1987 // In this case a link went directly to a call, but should really go 1988 // to the dummy .outN outputs that were created for the call that 1989 // themselves link to the inputs with levels adjusted. 1990 // See e.g. #10466 1991 // This can only happen with functions returning a single result. 1992 case OCALLMETH, OCALLFUNC, OCALLINTER: 1993 if srcE.Retval.Len() != 0 { 1994 if Debug['m'] > 2 { 1995 fmt.Printf("%v:[%d] dst %S escwalk replace src: %S with %S\n", 1996 linestr(lineno), e.loopdepth, 1997 dst, src, srcE.Retval.First()) 1998 } 1999 src = srcE.Retval.First() 2000 srcE = e.nodeEscState(src) 2001 } 2002 } 2003 2004 recurse: 2005 level = level.copy() 2006 2007 for i := range srcE.Flowsrc { 2008 s := &srcE.Flowsrc[i] 2009 s.parent = step 2010 e.escwalkBody(level, dst, s.src, s, extraloopdepth) 2011 s.parent = nil 2012 } 2013 2014 e.pdepth-- 2015 } 2016 2017 // addrescapes tags node n as having had its address taken 2018 // by "increasing" the "value" of n.Esc to EscHeap. 2019 // Storage is allocated as necessary to allow the address 2020 // to be taken. 2021 func addrescapes(n *Node) { 2022 switch n.Op { 2023 default: 2024 // Unexpected Op, probably due to a previous type error. Ignore. 2025 2026 case OIND, ODOTPTR: 2027 // Nothing to do. 2028 2029 case ONAME: 2030 if n == nodfp { 2031 break 2032 } 2033 2034 // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. 2035 // on PPARAM it means something different. 2036 if n.Class() == PAUTO && n.Esc == EscNever { 2037 break 2038 } 2039 2040 // If a closure reference escapes, mark the outer variable as escaping. 2041 if n.IsClosureVar() { 2042 addrescapes(n.Name.Defn) 2043 break 2044 } 2045 2046 if n.Class() != PPARAM && n.Class() != PPARAMOUT && n.Class() != PAUTO { 2047 break 2048 } 2049 2050 // This is a plain parameter or local variable that needs to move to the heap, 2051 // but possibly for the function outside the one we're compiling. 2052 // That is, if we have: 2053 // 2054 // func f(x int) { 2055 // func() { 2056 // global = &x 2057 // } 2058 // } 2059 // 2060 // then we're analyzing the inner closure but we need to move x to the 2061 // heap in f, not in the inner closure. Flip over to f before calling moveToHeap. 2062 oldfn := Curfn 2063 Curfn = n.Name.Curfn 2064 if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE { 2065 Curfn = Curfn.Func.Closure 2066 } 2067 ln := lineno 2068 lineno = Curfn.Pos 2069 moveToHeap(n) 2070 Curfn = oldfn 2071 lineno = ln 2072 2073 // ODOTPTR has already been introduced, 2074 // so these are the non-pointer ODOT and OINDEX. 2075 // In &x[0], if x is a slice, then x does not 2076 // escape--the pointer inside x does, but that 2077 // is always a heap pointer anyway. 2078 case ODOT, OINDEX, OPAREN, OCONVNOP: 2079 if !n.Left.Type.IsSlice() { 2080 addrescapes(n.Left) 2081 } 2082 } 2083 } 2084 2085 // moveToHeap records the parameter or local variable n as moved to the heap. 2086 func moveToHeap(n *Node) { 2087 if Debug['r'] != 0 { 2088 Dump("MOVE", n) 2089 } 2090 if compiling_runtime { 2091 yyerror("%v escapes to heap, not allowed in runtime.", n) 2092 } 2093 if n.Class() == PAUTOHEAP { 2094 Dump("n", n) 2095 Fatalf("double move to heap") 2096 } 2097 2098 // Allocate a local stack variable to hold the pointer to the heap copy. 2099 // temp will add it to the function declaration list automatically. 2100 heapaddr := temp(types.NewPtr(n.Type)) 2101 heapaddr.Sym = lookup("&" + n.Sym.Name) 2102 heapaddr.Orig.Sym = heapaddr.Sym 2103 2104 // Unset AutoTemp to persist the &foo variable name through SSA to 2105 // liveness analysis. 2106 // TODO(mdempsky/drchase): Cleaner solution? 2107 heapaddr.Name.SetAutoTemp(false) 2108 2109 // Parameters have a local stack copy used at function start/end 2110 // in addition to the copy in the heap that may live longer than 2111 // the function. 2112 if n.Class() == PPARAM || n.Class() == PPARAMOUT { 2113 if n.Xoffset == BADWIDTH { 2114 Fatalf("addrescapes before param assignment") 2115 } 2116 2117 // We rewrite n below to be a heap variable (indirection of heapaddr). 2118 // Preserve a copy so we can still write code referring to the original, 2119 // and substitute that copy into the function declaration list 2120 // so that analyses of the local (on-stack) variables use it. 2121 stackcopy := newname(n.Sym) 2122 stackcopy.SetAddable(false) 2123 stackcopy.Type = n.Type 2124 stackcopy.Xoffset = n.Xoffset 2125 stackcopy.SetClass(n.Class()) 2126 stackcopy.Name.Param.Heapaddr = heapaddr 2127 if n.Class() == PPARAMOUT { 2128 // Make sure the pointer to the heap copy is kept live throughout the function. 2129 // The function could panic at any point, and then a defer could recover. 2130 // Thus, we need the pointer to the heap copy always available so the 2131 // post-deferreturn code can copy the return value back to the stack. 2132 // See issue 16095. 2133 heapaddr.SetIsOutputParamHeapAddr(true) 2134 } 2135 n.Name.Param.Stackcopy = stackcopy 2136 2137 // Substitute the stackcopy into the function variable list so that 2138 // liveness and other analyses use the underlying stack slot 2139 // and not the now-pseudo-variable n. 2140 found := false 2141 for i, d := range Curfn.Func.Dcl { 2142 if d == n { 2143 Curfn.Func.Dcl[i] = stackcopy 2144 found = true 2145 break 2146 } 2147 // Parameters are before locals, so can stop early. 2148 // This limits the search even in functions with many local variables. 2149 if d.Class() == PAUTO { 2150 break 2151 } 2152 } 2153 if !found { 2154 Fatalf("cannot find %v in local variable list", n) 2155 } 2156 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) 2157 } 2158 2159 // Modify n in place so that uses of n now mean indirection of the heapaddr. 2160 n.SetClass(PAUTOHEAP) 2161 n.Xoffset = 0 2162 n.Name.Param.Heapaddr = heapaddr 2163 n.Esc = EscHeap 2164 if Debug['m'] != 0 { 2165 fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) 2166 } 2167 } 2168 2169 // This special tag is applied to uintptr variables 2170 // that we believe may hold unsafe.Pointers for 2171 // calls into assembly functions. 2172 // It is logically a constant, but using a var 2173 // lets us take the address below to get a *string. 2174 var unsafeUintptrTag = "unsafe-uintptr" 2175 2176 // This special tag is applied to uintptr parameters of functions 2177 // marked go:uintptrescapes. 2178 const uintptrEscapesTag = "uintptr-escapes" 2179 2180 func (e *EscState) esctag(fn *Node) { 2181 fn.Esc = EscFuncTagged 2182 2183 name := func(s *types.Sym, narg int) string { 2184 if s != nil { 2185 return s.Name 2186 } 2187 return fmt.Sprintf("arg#%d", narg) 2188 } 2189 2190 // External functions are assumed unsafe, 2191 // unless //go:noescape is given before the declaration. 2192 if fn.Nbody.Len() == 0 { 2193 if fn.Noescape() { 2194 for _, f := range fn.Type.Params().Fields().Slice() { 2195 if types.Haspointers(f.Type) { 2196 f.Note = mktag(EscNone) 2197 } 2198 } 2199 } 2200 2201 // Assume that uintptr arguments must be held live across the call. 2202 // This is most important for syscall.Syscall. 2203 // See golang.org/issue/13372. 2204 // This really doesn't have much to do with escape analysis per se, 2205 // but we are reusing the ability to annotate an individual function 2206 // argument and pass those annotations along to importing code. 2207 narg := 0 2208 for _, f := range fn.Type.Params().Fields().Slice() { 2209 narg++ 2210 if f.Type.Etype == TUINTPTR { 2211 if Debug['m'] != 0 { 2212 Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg)) 2213 } 2214 f.Note = unsafeUintptrTag 2215 } 2216 } 2217 2218 return 2219 } 2220 2221 if fn.Func.Pragma&UintptrEscapes != 0 { 2222 narg := 0 2223 for _, f := range fn.Type.Params().Fields().Slice() { 2224 narg++ 2225 if f.Type.Etype == TUINTPTR { 2226 if Debug['m'] != 0 { 2227 Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg)) 2228 } 2229 f.Note = uintptrEscapesTag 2230 } 2231 2232 if f.Isddd() && f.Type.Elem().Etype == TUINTPTR { 2233 // final argument is ...uintptr. 2234 if Debug['m'] != 0 { 2235 Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg)) 2236 } 2237 f.Note = uintptrEscapesTag 2238 } 2239 } 2240 } 2241 2242 for _, ln := range fn.Func.Dcl { 2243 if ln.Op != ONAME { 2244 continue 2245 } 2246 2247 switch ln.Esc & EscMask { 2248 case EscNone, // not touched by escflood 2249 EscReturn: 2250 if types.Haspointers(ln.Type) { // don't bother tagging for scalars 2251 if ln.Name.Param.Field.Note != uintptrEscapesTag { 2252 ln.Name.Param.Field.Note = mktag(int(ln.Esc)) 2253 } 2254 } 2255 2256 case EscHeap: // touched by escflood, moved to heap 2257 } 2258 } 2259 2260 // Unnamed parameters are unused and therefore do not escape. 2261 // (Unnamed parameters are not in the Dcl list in the loop above 2262 // so we need to mark them separately.) 2263 for _, f := range fn.Type.Params().Fields().Slice() { 2264 if f.Sym == nil || f.Sym.IsBlank() { 2265 f.Note = mktag(EscNone) 2266 } 2267 } 2268 }