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