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