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