github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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.Class = 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 if n.Op == OIF && Isconst(n.Left, CTBOOL) { 694 // Don't examine dead code. 695 if n.Left.Bool() { 696 e.esclist(n.Nbody, n) 697 } else { 698 e.esclist(n.Rlist, n) 699 } 700 } else { 701 e.esc(n.Left, n) 702 e.esc(n.Right, n) 703 e.esclist(n.Nbody, n) 704 e.esclist(n.List, n) 705 e.esclist(n.Rlist, n) 706 } 707 708 if n.Op == OFOR || n.Op == OFORUNTIL || n.Op == ORANGE { 709 e.loopdepth-- 710 } 711 712 if Debug['m'] > 2 { 713 fmt.Printf("%v:[%d] %v esc: %v\n", linestr(lineno), e.loopdepth, funcSym(Curfn), n) 714 } 715 716 switch n.Op { 717 // Record loop depth at declaration. 718 case ODCL: 719 if n.Left != nil { 720 e.nodeEscState(n.Left).Loopdepth = e.loopdepth 721 } 722 723 case OLABEL: 724 if asNode(n.Left.Sym.Label) == &nonlooping { 725 if Debug['m'] > 2 { 726 fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n) 727 } 728 } else if asNode(n.Left.Sym.Label) == &looping { 729 if Debug['m'] > 2 { 730 fmt.Printf("%v: %v looping label\n", linestr(lineno), n) 731 } 732 e.loopdepth++ 733 } 734 735 // See case OLABEL in escloopdepth above 736 // else if(n.Left.Sym.Label == nil) 737 // fatal("escape analysis missed or messed up a label: %+N", n); 738 739 n.Left.Sym.Label = nil 740 741 case ORANGE: 742 if n.List.Len() >= 2 { 743 // Everything but fixed array is a dereference. 744 745 // If fixed array is really the address of fixed array, 746 // it is also a dereference, because it is implicitly 747 // dereferenced (see #12588) 748 if n.Type.IsArray() && 749 !(n.Right.Type.IsPtr() && eqtype(n.Right.Type.Elem(), n.Type)) { 750 e.escassignWhyWhere(n.List.Second(), n.Right, "range", n) 751 } else { 752 e.escassignDereference(n.List.Second(), n.Right, e.stepAssignWhere(n.List.Second(), n.Right, "range-deref", n)) 753 } 754 } 755 756 case OSWITCH: 757 if n.Left != nil && n.Left.Op == OTYPESW { 758 for _, cas := range n.List.Slice() { 759 // cases 760 // n.Left.Right is the argument of the .(type), 761 // it.N().Rlist is the variable per case 762 if cas.Rlist.Len() != 0 { 763 e.escassignWhyWhere(cas.Rlist.First(), n.Left.Right, "switch case", n) 764 } 765 } 766 } 767 768 // Filter out the following special case. 769 // 770 // func (b *Buffer) Foo() { 771 // n, m := ... 772 // b.buf = b.buf[n:m] 773 // } 774 // 775 // This assignment is a no-op for escape analysis, 776 // it does not store any new pointers into b that were not already there. 777 // However, without this special case b will escape, because we assign to OIND/ODOTPTR. 778 case OAS, OASOP: 779 if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference 780 (n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation 781 (n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference 782 n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME 783 784 // Here we also assume that the statement will not contain calls, 785 // that is, that order will move any calls to init. 786 // Otherwise base ONAME value could change between the moments 787 // when we evaluate it for dst and for src. 788 // 789 // Note, this optimization does not apply to OSLICEARR, 790 // because it does introduce a new pointer into b that was not already there 791 // (pointer to b itself). After such assignment, if b contents escape, 792 // b escapes as well. If we ignore such OSLICEARR, we will conclude 793 // that b does not escape when b contents do. 794 if Debug['m'] != 0 { 795 Warnl(n.Pos, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left) 796 } 797 798 break 799 } 800 801 e.escassign(n.Left, n.Right, e.stepAssignWhere(nil, nil, "", n)) 802 803 case OAS2: // x,y = a,b 804 if n.List.Len() == n.Rlist.Len() { 805 rs := n.Rlist.Slice() 806 for i, n := range n.List.Slice() { 807 e.escassignWhyWhere(n, rs[i], "assign-pair", n) 808 } 809 } 810 811 case OAS2RECV: // v, ok = <-ch 812 e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-receive", n) 813 case OAS2MAPR: // v, ok = m[k] 814 e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-mapr", n) 815 case OAS2DOTTYPE: // v, ok = x.(type) 816 e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-dot-type", n) 817 818 case OSEND: // ch <- x 819 e.escassignSinkWhy(n, n.Right, "send") 820 821 case ODEFER: 822 if e.loopdepth == 1 { // top level 823 break 824 } 825 // arguments leak out of scope 826 // TODO: leak to a dummy node instead 827 // defer f(x) - f and x escape 828 e.escassignSinkWhy(n, n.Left.Left, "defer func") 829 e.escassignSinkWhy(n, n.Left.Right, "defer func ...") // ODDDARG for call 830 for _, arg := range n.Left.List.Slice() { 831 e.escassignSinkWhy(n, arg, "defer func arg") 832 } 833 834 case OPROC: 835 // go f(x) - f and x escape 836 e.escassignSinkWhy(n, n.Left.Left, "go func") 837 e.escassignSinkWhy(n, n.Left.Right, "go func ...") // ODDDARG for call 838 for _, arg := range n.Left.List.Slice() { 839 e.escassignSinkWhy(n, arg, "go func arg") 840 } 841 842 case OCALLMETH, OCALLFUNC, OCALLINTER: 843 e.esccall(n, parent) 844 845 // esccall already done on n.Rlist.First(). tie it's Retval to n.List 846 case OAS2FUNC: // x,y = f() 847 rs := e.nodeEscState(n.Rlist.First()).Retval.Slice() 848 for i, n := range n.List.Slice() { 849 if i >= len(rs) { 850 break 851 } 852 e.escassignWhyWhere(n, rs[i], "assign-pair-func-call", n) 853 } 854 if n.List.Len() != len(rs) { 855 Fatalf("esc oas2func") 856 } 857 858 case ORETURN: 859 retList := n.List 860 if retList.Len() == 1 && Curfn.Type.Results().NumFields() > 1 { 861 // OAS2FUNC in disguise 862 // esccall already done on n.List.First() 863 // tie e.nodeEscState(n.List.First()).Retval to Curfn.Func.Dcl PPARAMOUT's 864 retList = e.nodeEscState(n.List.First()).Retval 865 } 866 867 i := 0 868 for _, lrn := range Curfn.Func.Dcl { 869 if i >= retList.Len() { 870 break 871 } 872 if lrn.Op != ONAME || lrn.Class != PPARAMOUT { 873 continue 874 } 875 e.escassignWhyWhere(lrn, retList.Index(i), "return", n) 876 i++ 877 } 878 879 if i < retList.Len() { 880 Fatalf("esc return list") 881 } 882 883 // Argument could leak through recover. 884 case OPANIC: 885 e.escassignSinkWhy(n, n.Left, "panic") 886 887 case OAPPEND: 888 if !n.Isddd() { 889 for _, nn := range n.List.Slice()[1:] { 890 e.escassignSinkWhy(n, nn, "appended to slice") // lose track of assign to dereference 891 } 892 } else { 893 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. 894 slice2 := n.List.Second() 895 e.escassignDereference(&e.theSink, slice2, e.stepAssignWhere(n, slice2, "appended slice...", n)) // lose track of assign of dereference 896 if Debug['m'] > 3 { 897 Warnl(n.Pos, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n) 898 } 899 } 900 e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too 901 902 case OCOPY: 903 e.escassignDereference(&e.theSink, n.Right, e.stepAssignWhere(n, n.Right, "copied slice", n)) // lose track of assign of dereference 904 905 case OCONV, OCONVNOP: 906 e.escassignWhyWhere(n, n.Left, "converted", n) 907 908 case OCONVIFACE: 909 e.track(n) 910 e.escassignWhyWhere(n, n.Left, "interface-converted", n) 911 912 case OARRAYLIT: 913 // Link values to array 914 for _, elt := range n.List.Slice() { 915 if elt.Op == OKEY { 916 elt = elt.Right 917 } 918 e.escassign(n, elt, e.stepAssignWhere(n, elt, "array literal element", n)) 919 } 920 921 case OSLICELIT: 922 // Slice is not leaked until proven otherwise 923 e.track(n) 924 // Link values to slice 925 for _, elt := range n.List.Slice() { 926 if elt.Op == OKEY { 927 elt = elt.Right 928 } 929 e.escassign(n, elt, e.stepAssignWhere(n, elt, "slice literal element", n)) 930 } 931 932 // Link values to struct. 933 case OSTRUCTLIT: 934 for _, elt := range n.List.Slice() { 935 e.escassignWhyWhere(n, elt.Left, "struct literal element", n) 936 } 937 938 case OPTRLIT: 939 e.track(n) 940 941 // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. 942 e.escassignWhyWhere(n, n.Left, "pointer literal [assign]", n) 943 944 case OCALLPART: 945 e.track(n) 946 947 // Contents make it to memory, lose track. 948 e.escassignSinkWhy(n, n.Left, "call part") 949 950 case OMAPLIT: 951 e.track(n) 952 // Keys and values make it to memory, lose track. 953 for _, elt := range n.List.Slice() { 954 e.escassignSinkWhy(n, elt.Left, "map literal key") 955 e.escassignSinkWhy(n, elt.Right, "map literal value") 956 } 957 958 case OCLOSURE: 959 // Link addresses of captured variables to closure. 960 for _, v := range n.Func.Cvars.Slice() { 961 if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs 962 continue 963 } 964 a := v.Name.Defn 965 if !v.Name.Byval() { 966 a = nod(OADDR, a, nil) 967 a.Pos = v.Pos 968 e.nodeEscState(a).Loopdepth = e.loopdepth 969 a = typecheck(a, Erv) 970 } 971 972 e.escassignWhyWhere(n, a, "captured by a closure", n) 973 } 974 fallthrough 975 976 case OMAKECHAN, 977 OMAKEMAP, 978 OMAKESLICE, 979 ONEW, 980 OARRAYRUNESTR, 981 OARRAYBYTESTR, 982 OSTRARRAYRUNE, 983 OSTRARRAYBYTE, 984 ORUNESTR: 985 e.track(n) 986 987 case OADDSTR: 988 e.track(n) 989 // Arguments of OADDSTR do not escape. 990 991 case OADDR: 992 // current loop depth is an upper bound on actual loop depth 993 // of addressed value. 994 e.track(n) 995 996 // for &x, use loop depth of x if known. 997 // it should always be known, but if not, be conservative 998 // and keep the current loop depth. 999 if n.Left.Op == ONAME { 1000 switch n.Left.Class { 1001 case PAUTO: 1002 nE := e.nodeEscState(n) 1003 leftE := e.nodeEscState(n.Left) 1004 if leftE.Loopdepth != 0 { 1005 nE.Loopdepth = leftE.Loopdepth 1006 } 1007 1008 // PPARAM is loop depth 1 always. 1009 // PPARAMOUT is loop depth 0 for writes 1010 // but considered loop depth 1 for address-of, 1011 // so that writing the address of one result 1012 // to another (or the same) result makes the 1013 // first result move to the heap. 1014 case PPARAM, PPARAMOUT: 1015 nE := e.nodeEscState(n) 1016 nE.Loopdepth = 1 1017 } 1018 } 1019 } 1020 1021 lineno = lno 1022 } 1023 1024 // escassignWhyWhere bundles a common case of 1025 // escassign(e, dst, src, e.stepAssignWhere(dst, src, reason, where)) 1026 func (e *EscState) escassignWhyWhere(dst, src *Node, reason string, where *Node) { 1027 var step *EscStep 1028 if Debug['m'] != 0 { 1029 step = e.stepAssignWhere(dst, src, reason, where) 1030 } 1031 e.escassign(dst, src, step) 1032 } 1033 1034 // escassignSinkWhy bundles a common case of 1035 // escassign(e, &e.theSink, src, e.stepAssign(nil, dst, src, reason)) 1036 func (e *EscState) escassignSinkWhy(dst, src *Node, reason string) { 1037 var step *EscStep 1038 if Debug['m'] != 0 { 1039 step = e.stepAssign(nil, dst, src, reason) 1040 } 1041 e.escassign(&e.theSink, src, step) 1042 } 1043 1044 // escassignSinkWhyWhere is escassignSinkWhy but includes a call site 1045 // for accurate location reporting. 1046 func (e *EscState) escassignSinkWhyWhere(dst, src *Node, reason string, call *Node) { 1047 var step *EscStep 1048 if Debug['m'] != 0 { 1049 step = e.stepAssignWhere(dst, src, reason, call) 1050 } 1051 e.escassign(&e.theSink, src, step) 1052 } 1053 1054 // Assert that expr somehow gets assigned to dst, if non nil. for 1055 // dst==nil, any name node expr still must be marked as being 1056 // evaluated in curfn. For expr==nil, dst must still be examined for 1057 // evaluations inside it (e.g *f(x) = y) 1058 func (e *EscState) escassign(dst, src *Node, step *EscStep) { 1059 if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX { 1060 return 1061 } 1062 1063 if Debug['m'] > 2 { 1064 fmt.Printf("%v:[%d] %v escassign: %S(%0j)[%v] = %S(%0j)[%v]\n", 1065 linestr(lineno), e.loopdepth, funcSym(Curfn), 1066 dst, dst, dst.Op, 1067 src, src, src.Op) 1068 } 1069 1070 setlineno(dst) 1071 1072 originalDst := dst 1073 dstwhy := "assigned" 1074 1075 // Analyze lhs of assignment. 1076 // Replace dst with &e.theSink if we can't track it. 1077 switch dst.Op { 1078 default: 1079 Dump("dst", dst) 1080 Fatalf("escassign: unexpected dst") 1081 1082 case OARRAYLIT, 1083 OSLICELIT, 1084 OCLOSURE, 1085 OCONV, 1086 OCONVIFACE, 1087 OCONVNOP, 1088 OMAPLIT, 1089 OSTRUCTLIT, 1090 OPTRLIT, 1091 ODDDARG, 1092 OCALLPART: 1093 1094 case ONAME: 1095 if dst.Class == PEXTERN { 1096 dstwhy = "assigned to top level variable" 1097 dst = &e.theSink 1098 } 1099 1100 case ODOT: // treat "dst.x = src" as "dst = src" 1101 e.escassign(dst.Left, src, e.stepAssign(step, originalDst, src, "dot-equals")) 1102 return 1103 1104 case OINDEX: 1105 if dst.Left.Type.IsArray() { 1106 e.escassign(dst.Left, src, e.stepAssign(step, originalDst, src, "array-element-equals")) 1107 return 1108 } 1109 1110 dstwhy = "slice-element-equals" 1111 dst = &e.theSink // lose track of dereference 1112 1113 case OIND: 1114 dstwhy = "star-equals" 1115 dst = &e.theSink // lose track of dereference 1116 1117 case ODOTPTR: 1118 dstwhy = "star-dot-equals" 1119 dst = &e.theSink // lose track of dereference 1120 1121 // lose track of key and value 1122 case OINDEXMAP: 1123 e.escassign(&e.theSink, dst.Right, e.stepAssign(nil, originalDst, src, "key of map put")) 1124 dstwhy = "value of map put" 1125 dst = &e.theSink 1126 } 1127 1128 lno := setlineno(src) 1129 e.pdepth++ 1130 1131 switch src.Op { 1132 case OADDR, // dst = &x 1133 OIND, // dst = *x 1134 ODOTPTR, // dst = (*x).f 1135 ONAME, 1136 ODDDARG, 1137 OPTRLIT, 1138 OARRAYLIT, 1139 OSLICELIT, 1140 OMAPLIT, 1141 OSTRUCTLIT, 1142 OMAKECHAN, 1143 OMAKEMAP, 1144 OMAKESLICE, 1145 OARRAYRUNESTR, 1146 OARRAYBYTESTR, 1147 OSTRARRAYRUNE, 1148 OSTRARRAYBYTE, 1149 OADDSTR, 1150 ONEW, 1151 OCALLPART, 1152 ORUNESTR, 1153 OCONVIFACE: 1154 e.escflows(dst, src, e.stepAssign(step, originalDst, src, dstwhy)) 1155 1156 case OCLOSURE: 1157 // OCLOSURE is lowered to OPTRLIT, 1158 // insert OADDR to account for the additional indirection. 1159 a := nod(OADDR, src, nil) 1160 a.Pos = src.Pos 1161 e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth 1162 a.Type = types.NewPtr(src.Type) 1163 e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy)) 1164 1165 // Flowing multiple returns to a single dst happens when 1166 // analyzing "go f(g())": here g() flows to sink (issue 4529). 1167 case OCALLMETH, OCALLFUNC, OCALLINTER: 1168 for _, n := range e.nodeEscState(src).Retval.Slice() { 1169 e.escflows(dst, n, e.stepAssign(nil, originalDst, n, dstwhy)) 1170 } 1171 1172 // A non-pointer escaping from a struct does not concern us. 1173 case ODOT: 1174 if src.Type != nil && !types.Haspointers(src.Type) { 1175 break 1176 } 1177 fallthrough 1178 1179 // Conversions, field access, slice all preserve the input value. 1180 case OCONV, 1181 OCONVNOP, 1182 ODOTMETH, 1183 // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 1184 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 1185 OSLICE, 1186 OSLICE3, 1187 OSLICEARR, 1188 OSLICE3ARR, 1189 OSLICESTR: 1190 // Conversions, field access, slice all preserve the input value. 1191 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1192 1193 case ODOTTYPE, 1194 ODOTTYPE2: 1195 if src.Type != nil && !types.Haspointers(src.Type) { 1196 break 1197 } 1198 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1199 1200 case OAPPEND: 1201 // Append returns first argument. 1202 // Subsequent arguments are already leaked because they are operands to append. 1203 e.escassign(dst, src.List.First(), e.stepAssign(step, dst, src.List.First(), dstwhy)) 1204 1205 case OINDEX: 1206 // Index of array preserves input value. 1207 if src.Left.Type.IsArray() { 1208 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1209 } else { 1210 e.escflows(dst, src, e.stepAssign(step, originalDst, src, dstwhy)) 1211 } 1212 1213 // Might be pointer arithmetic, in which case 1214 // the operands flow into the result. 1215 // TODO(rsc): Decide what the story is here. This is unsettling. 1216 case OADD, 1217 OSUB, 1218 OOR, 1219 OXOR, 1220 OMUL, 1221 ODIV, 1222 OMOD, 1223 OLSH, 1224 ORSH, 1225 OAND, 1226 OANDNOT, 1227 OPLUS, 1228 OMINUS, 1229 OCOM: 1230 e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy)) 1231 1232 e.escassign(dst, src.Right, e.stepAssign(step, originalDst, src, dstwhy)) 1233 } 1234 1235 e.pdepth-- 1236 lineno = lno 1237 } 1238 1239 // Common case for escapes is 16 bits 000000000xxxEEEE 1240 // where commonest cases for xxx encoding in-to-out pointer 1241 // flow are 000, 001, 010, 011 and EEEE is computed Esc bits. 1242 // Note width of xxx depends on value of constant 1243 // bitsPerOutputInTag -- expect 2 or 3, so in practice the 1244 // tag cache array is 64 or 128 long. Some entries will 1245 // never be populated. 1246 var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string 1247 1248 // mktag returns the string representation for an escape analysis tag. 1249 func mktag(mask int) string { 1250 switch mask & EscMask { 1251 case EscNone, EscReturn: 1252 default: 1253 Fatalf("escape mktag") 1254 } 1255 1256 if mask < len(tags) && tags[mask] != "" { 1257 return tags[mask] 1258 } 1259 1260 s := fmt.Sprintf("esc:0x%x", mask) 1261 if mask < len(tags) { 1262 tags[mask] = s 1263 } 1264 return s 1265 } 1266 1267 // parsetag decodes an escape analysis tag and returns the esc value. 1268 func parsetag(note string) uint16 { 1269 if !strings.HasPrefix(note, "esc:") { 1270 return EscUnknown 1271 } 1272 n, _ := strconv.ParseInt(note[4:], 0, 0) 1273 em := uint16(n) 1274 if em == 0 { 1275 return EscNone 1276 } 1277 return em 1278 } 1279 1280 // describeEscape returns a string describing the escape tag. 1281 // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation 1282 // or a description of parameter flow, which takes the form of an optional "contentToHeap" 1283 // indicating that the content of this parameter is leaked to the heap, followed by a sequence 1284 // of level encodings separated by spaces, one for each parameter, where _ means no flow, 1285 // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow. 1286 // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences) 1287 // escapes to the heap, the parameter does not leak to the first output, but does leak directly 1288 // to the second output (and if there are more than two outputs, there is no flow to those.) 1289 func describeEscape(em uint16) string { 1290 var s string 1291 if em&EscMask == EscUnknown { 1292 s = "EscUnknown" 1293 } 1294 if em&EscMask == EscNone { 1295 s = "EscNone" 1296 } 1297 if em&EscMask == EscHeap { 1298 s = "EscHeap" 1299 } 1300 if em&EscMask == EscReturn { 1301 s = "EscReturn" 1302 } 1303 if em&EscContentEscapes != 0 { 1304 if s != "" { 1305 s += " " 1306 } 1307 s += "contentToHeap" 1308 } 1309 for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag { 1310 // See encoding description above 1311 if s != "" { 1312 s += " " 1313 } 1314 switch embits := em & bitsMaskForTag; embits { 1315 case 0: 1316 s += "_" 1317 case 1: 1318 s += "=" 1319 default: 1320 for i := uint16(0); i < embits-1; i++ { 1321 s += "*" 1322 } 1323 } 1324 1325 } 1326 return s 1327 } 1328 1329 // escassignfromtag models the input-to-output assignment flow of one of a function 1330 // calls arguments, where the flow is encoded in "note". 1331 func (e *EscState) escassignfromtag(note string, dsts Nodes, src, call *Node) uint16 { 1332 em := parsetag(note) 1333 if src.Op == OLITERAL { 1334 return em 1335 } 1336 1337 if Debug['m'] > 3 { 1338 fmt.Printf("%v::assignfromtag:: src=%S, em=%s\n", 1339 linestr(lineno), src, describeEscape(em)) 1340 } 1341 1342 if em == EscUnknown { 1343 e.escassignSinkWhyWhere(src, src, "passed to call[argument escapes]", call) 1344 return em 1345 } 1346 1347 if em == EscNone { 1348 return em 1349 } 1350 1351 // If content inside parameter (reached via indirection) 1352 // escapes to heap, mark as such. 1353 if em&EscContentEscapes != 0 { 1354 e.escassign(&e.theSink, e.addDereference(src), e.stepAssignWhere(src, src, "passed to call[argument content escapes]", call)) 1355 } 1356 1357 em0 := em 1358 dstsi := 0 1359 for em >>= EscReturnBits; em != 0 && dstsi < dsts.Len(); em = em >> bitsPerOutputInTag { 1360 // Prefer the lowest-level path to the reference (for escape purposes). 1361 // Two-bit encoding (for example. 1, 3, and 4 bits are other options) 1362 // 01 = 0-level 1363 // 10 = 1-level, (content escapes), 1364 // 11 = 2-level, (content of content escapes), 1365 embits := em & bitsMaskForTag 1366 if embits > 0 { 1367 n := src 1368 for i := uint16(0); i < embits-1; i++ { 1369 n = e.addDereference(n) // encode level>0 as indirections 1370 } 1371 e.escassign(dsts.Index(dstsi), n, e.stepAssignWhere(dsts.Index(dstsi), src, "passed-to-and-returned-from-call", call)) 1372 } 1373 dstsi++ 1374 } 1375 // If there are too many outputs to fit in the tag, 1376 // that is handled at the encoding end as EscHeap, 1377 // so there is no need to check here. 1378 1379 if em != 0 && dstsi >= dsts.Len() { 1380 Fatalf("corrupt esc tag %q or messed up escretval list\n", note) 1381 } 1382 return em0 1383 } 1384 1385 func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) { 1386 if src.Op == OLITERAL { 1387 return 1388 } 1389 e.escassign(dst, e.addDereference(src), step) 1390 } 1391 1392 // addDereference constructs a suitable OIND note applied to src. 1393 // Because this is for purposes of escape accounting, not execution, 1394 // some semantically dubious node combinations are (currently) possible. 1395 func (e *EscState) addDereference(n *Node) *Node { 1396 ind := nod(OIND, n, nil) 1397 e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth 1398 ind.Pos = n.Pos 1399 t := n.Type 1400 if t.IsKind(types.Tptr) { 1401 // This should model our own sloppy use of OIND to encode 1402 // decreasing levels of indirection; i.e., "indirecting" an array 1403 // might yield the type of an element. To be enhanced... 1404 t = t.Elem() 1405 } 1406 ind.Type = t 1407 return ind 1408 } 1409 1410 // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter. 1411 // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel. 1412 // If the encoding cannot describe the modified input level and output number, then EscHeap is returned. 1413 func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { 1414 // Flow+level is encoded in two bits. 1415 // 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel 1416 // 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful. 1417 if level.int() <= 0 && level.guaranteedDereference() > 0 { 1418 return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content. 1419 } 1420 if level.int() < 0 { 1421 return EscHeap 1422 } 1423 if level.int() > maxEncodedLevel { 1424 // Cannot encode larger values than maxEncodedLevel. 1425 level = levelFrom(maxEncodedLevel) 1426 } 1427 encoded := uint16(level.int() + 1) 1428 1429 shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits) 1430 old := (e >> shift) & bitsMaskForTag 1431 if old == 0 || encoded != 0 && encoded < old { 1432 old = encoded 1433 } 1434 1435 encodedFlow := old << shift 1436 if (encodedFlow>>shift)&bitsMaskForTag != old { 1437 // Encoding failure defaults to heap. 1438 return EscHeap 1439 } 1440 1441 return (e &^ (bitsMaskForTag << shift)) | encodedFlow 1442 } 1443 1444 func (e *EscState) initEscRetval(call *Node, fntype *types.Type) { 1445 cE := e.nodeEscState(call) 1446 cE.Retval.Set(nil) // Suspect this is not nil for indirect calls. 1447 for i, f := range fntype.Results().Fields().Slice() { 1448 buf := fmt.Sprintf(".out%d", i) 1449 ret := newname(lookup(buf)) 1450 ret.SetAddable(false) // TODO(mdempsky): Seems suspicious. 1451 ret.Type = f.Type 1452 ret.Class = PAUTO 1453 ret.Name.Curfn = Curfn 1454 e.nodeEscState(ret).Loopdepth = e.loopdepth 1455 ret.SetUsed(true) 1456 ret.Pos = call.Pos 1457 cE.Retval.Append(ret) 1458 } 1459 } 1460 1461 // This is a bit messier than fortunate, pulled out of esc's big 1462 // switch for clarity. We either have the paramnodes, which may be 1463 // connected to other things through flows or we have the parameter type 1464 // nodes, which may be marked "noescape". Navigating the ast is slightly 1465 // different for methods vs plain functions and for imported vs 1466 // this-package 1467 func (e *EscState) esccall(call *Node, parent *Node) { 1468 var fntype *types.Type 1469 var indirect bool 1470 var fn *Node 1471 switch call.Op { 1472 default: 1473 Fatalf("esccall") 1474 1475 case OCALLFUNC: 1476 fn = call.Left 1477 fntype = fn.Type 1478 indirect = fn.Op != ONAME || fn.Class != PFUNC 1479 1480 case OCALLMETH: 1481 fn = asNode(call.Left.Sym.Def) 1482 if fn != nil { 1483 fntype = fn.Type 1484 } else { 1485 fntype = call.Left.Type 1486 } 1487 1488 case OCALLINTER: 1489 fntype = call.Left.Type 1490 indirect = true 1491 } 1492 1493 argList := call.List 1494 if argList.Len() == 1 { 1495 arg := argList.First() 1496 if arg.Type.IsFuncArgStruct() { // f(g()) 1497 argList = e.nodeEscState(arg).Retval 1498 } 1499 } 1500 1501 args := argList.Slice() 1502 1503 if indirect { 1504 // We know nothing! 1505 // Leak all the parameters 1506 for _, arg := range args { 1507 e.escassignSinkWhy(call, arg, "parameter to indirect call") 1508 if Debug['m'] > 3 { 1509 fmt.Printf("%v::esccall:: indirect call <- %S, untracked\n", linestr(lineno), arg) 1510 } 1511 } 1512 // Set up bogus outputs 1513 e.initEscRetval(call, fntype) 1514 // If there is a receiver, it also leaks to heap. 1515 if call.Op != OCALLFUNC { 1516 rf := fntype.Recv() 1517 r := call.Left.Left 1518 if types.Haspointers(rf.Type) { 1519 e.escassignSinkWhy(call, r, "receiver in indirect call") 1520 } 1521 } else { // indirect and OCALLFUNC = could be captured variables, too. (#14409) 1522 rets := e.nodeEscState(call).Retval.Slice() 1523 for _, ret := range rets { 1524 e.escassignDereference(ret, fn, e.stepAssignWhere(ret, fn, "captured by called closure", call)) 1525 } 1526 } 1527 return 1528 } 1529 1530 cE := e.nodeEscState(call) 1531 if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && 1532 fn.Name.Defn != nil && fn.Name.Defn.Nbody.Len() != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged { 1533 if Debug['m'] > 3 { 1534 fmt.Printf("%v::esccall:: %S in recursive group\n", linestr(lineno), call) 1535 } 1536 1537 // function in same mutually recursive group. Incorporate into flow graph. 1538 // print("esc local fn: %N\n", fn.Func.Ntype); 1539 if fn.Name.Defn.Esc == EscFuncUnknown || cE.Retval.Len() != 0 { 1540 Fatalf("graph inconsistency") 1541 } 1542 1543 sawRcvr := false 1544 for _, n := range fn.Name.Defn.Func.Dcl { 1545 switch n.Class { 1546 case PPARAM: 1547 if call.Op != OCALLFUNC && !sawRcvr { 1548 e.escassignWhyWhere(n, call.Left.Left, "call receiver", call) 1549 sawRcvr = true 1550 continue 1551 } 1552 if len(args) == 0 { 1553 continue 1554 } 1555 arg := args[0] 1556 if n.Isddd() && !call.Isddd() { 1557 // Introduce ODDDARG node to represent ... allocation. 1558 arg = nod(ODDDARG, nil, nil) 1559 arr := types.NewArray(n.Type.Elem(), int64(len(args))) 1560 arg.Type = types.NewPtr(arr) // make pointer so it will be tracked 1561 arg.Pos = call.Pos 1562 e.track(arg) 1563 call.Right = arg 1564 } 1565 e.escassignWhyWhere(n, arg, "arg to recursive call", call) // TODO this message needs help. 1566 if arg != args[0] { 1567 // "..." arguments are untracked 1568 for _, a := range args { 1569 if Debug['m'] > 3 { 1570 fmt.Printf("%v::esccall:: ... <- %S, untracked\n", linestr(lineno), a) 1571 } 1572 e.escassignSinkWhyWhere(arg, a, "... arg to recursive call", call) 1573 } 1574 // No more PPARAM processing, but keep 1575 // going for PPARAMOUT. 1576 args = nil 1577 continue 1578 } 1579 args = args[1:] 1580 1581 case PPARAMOUT: 1582 cE.Retval.Append(n) 1583 } 1584 } 1585 1586 return 1587 } 1588 1589 // Imported or completely analyzed function. Use the escape tags. 1590 if cE.Retval.Len() != 0 { 1591 Fatalf("esc already decorated call %+v\n", call) 1592 } 1593 1594 if Debug['m'] > 3 { 1595 fmt.Printf("%v::esccall:: %S not recursive\n", linestr(lineno), call) 1596 } 1597 1598 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 1599 e.initEscRetval(call, fntype) 1600 1601 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, e.nodeEscState(call).Retval); 1602 1603 // Receiver. 1604 if call.Op != OCALLFUNC { 1605 rf := fntype.Recv() 1606 r := call.Left.Left 1607 if types.Haspointers(rf.Type) { 1608 e.escassignfromtag(rf.Note, cE.Retval, r, call) 1609 } 1610 } 1611 1612 for i, param := range fntype.Params().FieldSlice() { 1613 note := param.Note 1614 var arg *Node 1615 if param.Isddd() && !call.Isddd() { 1616 rest := args[i:] 1617 if len(rest) == 0 { 1618 break 1619 } 1620 1621 // Introduce ODDDARG node to represent ... allocation. 1622 arg = nod(ODDDARG, nil, nil) 1623 arg.Pos = call.Pos 1624 arr := types.NewArray(param.Type.Elem(), int64(len(rest))) 1625 arg.Type = types.NewPtr(arr) // make pointer so it will be tracked 1626 e.track(arg) 1627 call.Right = arg 1628 1629 // Store arguments into slice for ... arg. 1630 for _, a := range rest { 1631 if Debug['m'] > 3 { 1632 fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), a) 1633 } 1634 if note == uintptrEscapesTag { 1635 e.escassignSinkWhyWhere(arg, a, "arg to uintptrescapes ...", call) 1636 } else { 1637 e.escassignWhyWhere(arg, a, "arg to ...", call) 1638 } 1639 } 1640 } else { 1641 arg = args[i] 1642 if note == uintptrEscapesTag { 1643 e.escassignSinkWhy(arg, arg, "escaping uintptr") 1644 } 1645 } 1646 1647 if types.Haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC { 1648 a := arg 1649 for a.Op == OCONVNOP { 1650 a = a.Left 1651 } 1652 switch a.Op { 1653 // The callee has already been analyzed, so its arguments have esc tags. 1654 // The argument is marked as not escaping at all. 1655 // Record that fact so that any temporary used for 1656 // synthesizing this expression can be reclaimed when 1657 // the function returns. 1658 // This 'noescape' is even stronger than the usual esc == EscNone. 1659 // arg.Esc == EscNone means that arg does not escape the current function. 1660 // arg.SetNoescape(true) here means that arg does not escape this statement 1661 // in the current function. 1662 case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT: 1663 a.SetNoescape(true) 1664 } 1665 } 1666 } 1667 } 1668 1669 // escflows records the link src->dst in dst, throwing out some quick wins, 1670 // and also ensuring that dst is noted as a flow destination. 1671 func (e *EscState) escflows(dst, src *Node, why *EscStep) { 1672 if dst == nil || src == nil || dst == src { 1673 return 1674 } 1675 1676 // Don't bother building a graph for scalars. 1677 if src.Type != nil && !types.Haspointers(src.Type) && !isReflectHeaderDataField(src) { 1678 if Debug['m'] > 3 { 1679 fmt.Printf("%v::NOT flows:: %S <- %S\n", linestr(lineno), dst, src) 1680 } 1681 return 1682 } 1683 1684 if Debug['m'] > 3 { 1685 fmt.Printf("%v::flows:: %S <- %S\n", linestr(lineno), dst, src) 1686 } 1687 1688 dstE := e.nodeEscState(dst) 1689 if len(dstE.Flowsrc) == 0 { 1690 e.dsts = append(e.dsts, dst) 1691 e.dstcount++ 1692 } 1693 1694 e.edgecount++ 1695 1696 if why == nil { 1697 dstE.Flowsrc = append(dstE.Flowsrc, EscStep{src: src}) 1698 } else { 1699 starwhy := *why 1700 starwhy.src = src // TODO: need to reconcile this w/ needs of explanations. 1701 dstE.Flowsrc = append(dstE.Flowsrc, starwhy) 1702 } 1703 } 1704 1705 // Whenever we hit a reference node, the level goes up by one, and whenever 1706 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 1707 // finding an OADDR just means we're following the upstream of a dereference, 1708 // so this address doesn't leak (yet). 1709 // If level == 0, it means the /value/ of this node can reach the root of this flood. 1710 // so if this node is an OADDR, its argument should be marked as escaping iff 1711 // its currfn/e.loopdepth are different from the flood's root. 1712 // Once an object has been moved to the heap, all of its upstream should be considered 1713 // escaping to the global scope. 1714 func (e *EscState) escflood(dst *Node) { 1715 switch dst.Op { 1716 case ONAME, OCLOSURE: 1717 default: 1718 return 1719 } 1720 1721 dstE := e.nodeEscState(dst) 1722 if Debug['m'] > 2 { 1723 fmt.Printf("\nescflood:%d: dst %S scope:%v[%d]\n", e.walkgen, dst, e.curfnSym(dst), dstE.Loopdepth) 1724 } 1725 1726 for i := range dstE.Flowsrc { 1727 e.walkgen++ 1728 s := &dstE.Flowsrc[i] 1729 s.parent = nil 1730 e.escwalk(levelFrom(0), dst, s.src, s) 1731 } 1732 } 1733 1734 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function. 1735 func funcOutputAndInput(dst, src *Node) bool { 1736 // Note if dst is marked as escaping, then "returned" is too weak. 1737 return dst.Op == ONAME && dst.Class == PPARAMOUT && 1738 src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn 1739 } 1740 1741 func (es *EscStep) describe(src *Node) { 1742 if Debug['m'] < 2 { 1743 return 1744 } 1745 step0 := es 1746 for step := step0; step != nil && !step.busy; step = step.parent { 1747 // TODO: We get cycles. Trigger is i = &i (where var i interface{}) 1748 step.busy = true 1749 // The trail is a little odd because of how the 1750 // graph is constructed. The link to the current 1751 // Node is parent.src unless parent is nil in which 1752 // case it is step.dst. 1753 nextDest := step.parent 1754 dst := step.dst 1755 where := step.where 1756 if nextDest != nil { 1757 dst = nextDest.src 1758 } 1759 if where == nil { 1760 where = dst 1761 } 1762 Warnl(src.Pos, "\tfrom %v (%s) at %s", dst, step.why, where.Line()) 1763 } 1764 for step := step0; step != nil && step.busy; step = step.parent { 1765 step.busy = false 1766 } 1767 } 1768 1769 const NOTALOOPDEPTH = -1 1770 1771 func (e *EscState) escwalk(level Level, dst *Node, src *Node, step *EscStep) { 1772 e.escwalkBody(level, dst, src, step, NOTALOOPDEPTH) 1773 } 1774 1775 func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep, extraloopdepth int32) { 1776 if src.Op == OLITERAL { 1777 return 1778 } 1779 srcE := e.nodeEscState(src) 1780 if srcE.Walkgen == e.walkgen { 1781 // Esclevels are vectors, do not compare as integers, 1782 // and must use "min" of old and new to guarantee 1783 // convergence. 1784 level = level.min(srcE.Level) 1785 if level == srcE.Level { 1786 // Have we been here already with an extraloopdepth, 1787 // or is the extraloopdepth provided no improvement on 1788 // what's already been seen? 1789 if srcE.Maxextraloopdepth >= extraloopdepth || srcE.Loopdepth >= extraloopdepth { 1790 return 1791 } 1792 srcE.Maxextraloopdepth = extraloopdepth 1793 } 1794 } else { // srcE.Walkgen < e.walkgen -- first time, reset this. 1795 srcE.Maxextraloopdepth = NOTALOOPDEPTH 1796 } 1797 1798 srcE.Walkgen = e.walkgen 1799 srcE.Level = level 1800 modSrcLoopdepth := srcE.Loopdepth 1801 1802 if extraloopdepth > modSrcLoopdepth { 1803 modSrcLoopdepth = extraloopdepth 1804 } 1805 1806 if Debug['m'] > 2 { 1807 fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %S(%0j) scope:%v[%d] extraloopdepth=%v\n", 1808 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) 1809 } 1810 1811 e.pdepth++ 1812 1813 // Input parameter flowing to output parameter? 1814 var leaks bool 1815 var osrcesc uint16 // used to prevent duplicate error messages 1816 1817 dstE := e.nodeEscState(dst) 1818 if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscHeap && dst.Esc != EscHeap { 1819 // This case handles: 1820 // 1. return in 1821 // 2. return &in 1822 // 3. tmp := in; return &tmp 1823 // 4. return *in 1824 if Debug['m'] != 0 { 1825 if Debug['m'] <= 2 { 1826 Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int()) 1827 step.describe(src) 1828 } else { 1829 Warnl(src.Pos, "leaking param: %S to result %v level=%v", src, dst.Sym, level) 1830 } 1831 } 1832 if src.Esc&EscMask != EscReturn { 1833 src.Esc = EscReturn | src.Esc&EscContentEscapes 1834 } 1835 src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level) 1836 goto recurse 1837 } 1838 1839 // If parameter content escapes to heap, set EscContentEscapes 1840 // Note minor confusion around escape from pointer-to-struct vs escape from struct 1841 if dst.Esc == EscHeap && 1842 src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscHeap && 1843 level.int() > 0 { 1844 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1845 if Debug['m'] != 0 { 1846 Warnl(src.Pos, "mark escaped content: %S", src) 1847 step.describe(src) 1848 } 1849 } 1850 1851 leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Loopdepth < modSrcLoopdepth 1852 leaks = leaks || level.int() <= 0 && dst.Esc&EscMask == EscHeap 1853 1854 osrcesc = src.Esc 1855 switch src.Op { 1856 case ONAME: 1857 if src.Class == PPARAM && (leaks || dstE.Loopdepth < 0) && src.Esc&EscMask < EscHeap { 1858 if level.guaranteedDereference() > 0 { 1859 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1860 if Debug['m'] != 0 { 1861 if Debug['m'] <= 2 { 1862 if osrcesc != src.Esc { 1863 Warnl(src.Pos, "leaking param content: %S", src) 1864 step.describe(src) 1865 } 1866 } else { 1867 Warnl(src.Pos, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S", 1868 src, level, dstE.Loopdepth, modSrcLoopdepth, dst) 1869 } 1870 } 1871 } else { 1872 src.Esc = EscHeap 1873 if Debug['m'] != 0 { 1874 if Debug['m'] <= 2 { 1875 Warnl(src.Pos, "leaking param: %S", src) 1876 step.describe(src) 1877 } else { 1878 Warnl(src.Pos, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S", 1879 src, level, dstE.Loopdepth, modSrcLoopdepth, dst) 1880 } 1881 } 1882 } 1883 } 1884 1885 // Treat a captured closure variable as equivalent to the 1886 // original variable. 1887 if src.IsClosureVar() { 1888 if leaks && Debug['m'] != 0 { 1889 Warnl(src.Pos, "leaking closure reference %S", src) 1890 step.describe(src) 1891 } 1892 e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step)) 1893 } 1894 1895 case OPTRLIT, OADDR: 1896 why := "pointer literal" 1897 if src.Op == OADDR { 1898 why = "address-of" 1899 } 1900 if leaks { 1901 src.Esc = EscHeap 1902 if Debug['m'] != 0 && osrcesc != src.Esc { 1903 p := src 1904 if p.Left.Op == OCLOSURE { 1905 p = p.Left // merely to satisfy error messages in tests 1906 } 1907 if Debug['m'] > 2 { 1908 Warnl(src.Pos, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v", 1909 p, level, dst, dstE.Loopdepth, modSrcLoopdepth) 1910 } else { 1911 Warnl(src.Pos, "%S escapes to heap", p) 1912 step.describe(src) 1913 } 1914 } 1915 addrescapes(src.Left) 1916 e.escwalkBody(level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth) 1917 extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op 1918 } else { 1919 e.escwalk(level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step)) 1920 } 1921 1922 case OAPPEND: 1923 e.escwalk(level, dst, src.List.First(), e.stepWalk(dst, src.List.First(), "append-first-arg", step)) 1924 1925 case ODDDARG: 1926 if leaks { 1927 src.Esc = EscHeap 1928 if Debug['m'] != 0 && osrcesc != src.Esc { 1929 Warnl(src.Pos, "%S escapes to heap", src) 1930 step.describe(src) 1931 } 1932 extraloopdepth = modSrcLoopdepth 1933 } 1934 // similar to a slice arraylit and its args. 1935 level = level.dec() 1936 1937 case OSLICELIT: 1938 for _, elt := range src.List.Slice() { 1939 if elt.Op == OKEY { 1940 elt = elt.Right 1941 } 1942 e.escwalk(level.dec(), dst, elt, e.stepWalk(dst, elt, "slice-literal-element", step)) 1943 } 1944 1945 fallthrough 1946 1947 case OMAKECHAN, 1948 OMAKEMAP, 1949 OMAKESLICE, 1950 OARRAYRUNESTR, 1951 OARRAYBYTESTR, 1952 OSTRARRAYRUNE, 1953 OSTRARRAYBYTE, 1954 OADDSTR, 1955 OMAPLIT, 1956 ONEW, 1957 OCLOSURE, 1958 OCALLPART, 1959 ORUNESTR, 1960 OCONVIFACE: 1961 if leaks { 1962 src.Esc = EscHeap 1963 if Debug['m'] != 0 && osrcesc != src.Esc { 1964 Warnl(src.Pos, "%S escapes to heap", src) 1965 step.describe(src) 1966 } 1967 extraloopdepth = modSrcLoopdepth 1968 } 1969 1970 case ODOT, 1971 ODOTTYPE: 1972 e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "dot", step)) 1973 1974 case 1975 OSLICE, 1976 OSLICEARR, 1977 OSLICE3, 1978 OSLICE3ARR, 1979 OSLICESTR: 1980 e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "slice", step)) 1981 1982 case OINDEX: 1983 if src.Left.Type.IsArray() { 1984 e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "fixed-array-index-of", step)) 1985 break 1986 } 1987 fallthrough 1988 1989 case ODOTPTR: 1990 e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "dot of pointer", step)) 1991 case OINDEXMAP: 1992 e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "map index", step)) 1993 case OIND: 1994 e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "indirection", step)) 1995 1996 // In this case a link went directly to a call, but should really go 1997 // to the dummy .outN outputs that were created for the call that 1998 // themselves link to the inputs with levels adjusted. 1999 // See e.g. #10466 2000 // This can only happen with functions returning a single result. 2001 case OCALLMETH, OCALLFUNC, OCALLINTER: 2002 if srcE.Retval.Len() != 0 { 2003 if Debug['m'] > 2 { 2004 fmt.Printf("%v:[%d] dst %S escwalk replace src: %S with %S\n", 2005 linestr(lineno), e.loopdepth, 2006 dst, src, srcE.Retval.First()) 2007 } 2008 src = srcE.Retval.First() 2009 srcE = e.nodeEscState(src) 2010 } 2011 } 2012 2013 recurse: 2014 level = level.copy() 2015 2016 for i := range srcE.Flowsrc { 2017 s := &srcE.Flowsrc[i] 2018 s.parent = step 2019 e.escwalkBody(level, dst, s.src, s, extraloopdepth) 2020 s.parent = nil 2021 } 2022 2023 e.pdepth-- 2024 } 2025 2026 // This special tag is applied to uintptr variables 2027 // that we believe may hold unsafe.Pointers for 2028 // calls into assembly functions. 2029 // It is logically a constant, but using a var 2030 // lets us take the address below to get a *string. 2031 var unsafeUintptrTag = "unsafe-uintptr" 2032 2033 // This special tag is applied to uintptr parameters of functions 2034 // marked go:uintptrescapes. 2035 const uintptrEscapesTag = "uintptr-escapes" 2036 2037 func (e *EscState) esctag(fn *Node) { 2038 fn.Esc = EscFuncTagged 2039 2040 name := func(s *types.Sym, narg int) string { 2041 if s != nil { 2042 return s.Name 2043 } 2044 return fmt.Sprintf("arg#%d", narg) 2045 } 2046 2047 // External functions are assumed unsafe, 2048 // unless //go:noescape is given before the declaration. 2049 if fn.Nbody.Len() == 0 { 2050 if fn.Noescape() { 2051 for _, f := range fn.Type.Params().Fields().Slice() { 2052 if types.Haspointers(f.Type) { 2053 f.Note = mktag(EscNone) 2054 } 2055 } 2056 } 2057 2058 // Assume that uintptr arguments must be held live across the call. 2059 // This is most important for syscall.Syscall. 2060 // See golang.org/issue/13372. 2061 // This really doesn't have much to do with escape analysis per se, 2062 // but we are reusing the ability to annotate an individual function 2063 // argument and pass those annotations along to importing code. 2064 narg := 0 2065 for _, f := range fn.Type.Params().Fields().Slice() { 2066 narg++ 2067 if f.Type.Etype == TUINTPTR { 2068 if Debug['m'] != 0 { 2069 Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg)) 2070 } 2071 f.Note = unsafeUintptrTag 2072 } 2073 } 2074 2075 return 2076 } 2077 2078 if fn.Func.Pragma&UintptrEscapes != 0 { 2079 narg := 0 2080 for _, f := range fn.Type.Params().Fields().Slice() { 2081 narg++ 2082 if f.Type.Etype == TUINTPTR { 2083 if Debug['m'] != 0 { 2084 Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg)) 2085 } 2086 f.Note = uintptrEscapesTag 2087 } 2088 2089 if f.Isddd() && f.Type.Elem().Etype == TUINTPTR { 2090 // final argument is ...uintptr. 2091 if Debug['m'] != 0 { 2092 Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg)) 2093 } 2094 f.Note = uintptrEscapesTag 2095 } 2096 } 2097 } 2098 2099 for _, ln := range fn.Func.Dcl { 2100 if ln.Op != ONAME { 2101 continue 2102 } 2103 2104 switch ln.Esc & EscMask { 2105 case EscNone, // not touched by escflood 2106 EscReturn: 2107 if types.Haspointers(ln.Type) { // don't bother tagging for scalars 2108 if ln.Name.Param.Field.Note != uintptrEscapesTag { 2109 ln.Name.Param.Field.Note = mktag(int(ln.Esc)) 2110 } 2111 } 2112 2113 case EscHeap: // touched by escflood, moved to heap 2114 } 2115 } 2116 2117 // Unnamed parameters are unused and therefore do not escape. 2118 // (Unnamed parameters are not in the Dcl list in the loop above 2119 // so we need to mark them separately.) 2120 for _, f := range fn.Type.Params().Fields().Slice() { 2121 if f.Sym == nil || isblanksym(f.Sym) { 2122 f.Note = mktag(EscNone) 2123 } 2124 } 2125 }