github.com/jonasi/go@v0.0.0-20150930005915-e78e654c1de0/src/cmd/compile/internal/gc/esc.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "fmt" 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 *NodeList, analyze func(list []*Node, recursive bool)) { 57 var v bottomUpVisitor 58 v.analyze = analyze 59 v.nodeID = make(map[*Node]uint32) 60 for l := list; l != nil; l = l.Next { 61 if l.N.Op == ODCLFUNC && l.N.Func.FCurfn == nil { 62 v.visit(l.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 *NodeList, min uint32) uint32 { 113 for ; l != nil; l = l.Next { 114 min = v.visitcode(l.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.Right.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 *NodeList) { 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 type NodeEscState struct { 301 Curfn *Node 302 Escflowsrc *NodeList // flow(this, src) 303 Escretval *NodeList // on OCALLxxx, list of dummy return values 304 Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes 305 Esclevel Level 306 Walkgen uint32 307 } 308 309 func (e *EscState) nodeEscState(n *Node) *NodeEscState { 310 if nE, ok := n.Opt().(*NodeEscState); ok { 311 return nE 312 } 313 if n.Opt() != nil { 314 Fatalf("nodeEscState: opt in use (%T)", n.Opt()) 315 } 316 nE := new(NodeEscState) 317 nE.Curfn = Curfn 318 n.SetOpt(nE) 319 e.opts = append(e.opts, n) 320 return nE 321 } 322 323 func (e *EscState) track(n *Node) { 324 if Curfn == nil { 325 Fatalf("EscState.track: Curfn nil") 326 } 327 n.Esc = EscNone // until proven otherwise 328 nE := e.nodeEscState(n) 329 nE.Escloopdepth = e.loopdepth 330 e.noesc = list(e.noesc, n) 331 } 332 333 // Escape constants are numbered in order of increasing "escapiness" 334 // to help make inferences be monotonic. With the exception of 335 // EscNever which is sticky, eX < eY means that eY is more exposed 336 // than eX, and hence replaces it in a conservative analysis. 337 const ( 338 EscUnknown = iota 339 EscNone // Does not escape to heap, result, or parameters. 340 EscReturn // Is returned or reachable from returned. 341 EscScope // Allocated in an inner loop scope, assigned to an outer loop scope, 342 // which allows the construction of non-escaping but arbitrarily large linked 343 // data structures (i.e., not eligible for allocation in a fixed-size stack frame). 344 EscHeap // Reachable from the heap 345 EscNever // By construction will not escape. 346 EscBits = 3 347 EscMask = (1 << EscBits) - 1 348 EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap 349 EscReturnBits = EscBits + 1 350 // Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3 351 ) 352 353 // escMax returns the maximum of an existing escape value 354 // (and its additional parameter flow flags) and a new escape type. 355 func escMax(e, etype uint16) uint16 { 356 if e&EscMask >= EscScope { 357 // normalize 358 if e&^EscMask != 0 { 359 Fatalf("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask) 360 } 361 } 362 if e&EscMask > etype { 363 return e 364 } 365 if etype == EscNone || etype == EscReturn { 366 return (e &^ EscMask) | etype 367 } 368 return etype 369 } 370 371 // For each input parameter to a function, the escapeReturnEncoding describes 372 // how the parameter may leak to the function's outputs. This is currently the 373 // "level" of the leak where level is 0 or larger (negative level means stored into 374 // something whose address is returned -- but that implies stored into the heap, 375 // hence EscHeap, which means that the details are not currently relevant. ) 376 const ( 377 bitsPerOutputInTag = 3 // For each output, the number of bits for a tag 378 bitsMaskForTag = uint16(1<<bitsPerOutputInTag) - 1 // The bit mask to extract a single tag. 379 maxEncodedLevel = int(bitsMaskForTag - 1) // The largest level that can be stored in a tag. 380 ) 381 382 type EscState struct { 383 // Fake node that all 384 // - return values and output variables 385 // - parameters on imported functions not marked 'safe' 386 // - assignments to global variables 387 // flow to. 388 theSink Node 389 390 dsts *NodeList // all dst nodes 391 loopdepth int32 // for detecting nested loop scopes 392 pdepth int // for debug printing in recursions. 393 dstcount int // diagnostic 394 edgecount int // diagnostic 395 noesc *NodeList // list of possible non-escaping nodes, for printing 396 recursive bool // recursive function or group of mutually recursive functions. 397 opts []*Node // nodes with .Opt initialized 398 walkgen uint32 399 } 400 401 // funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way. 402 func funcSym(fn *Node) *Sym { 403 if fn == nil || fn.Func.Nname == nil { 404 return nil 405 } 406 return fn.Func.Nname.Sym 407 } 408 409 // curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way. 410 func (e *EscState) curfnSym(n *Node) *Sym { 411 nE := e.nodeEscState(n) 412 return funcSym(nE.Curfn) 413 } 414 415 func escAnalyze(all []*Node, recursive bool) { 416 var es EscState 417 e := &es 418 e.theSink.Op = ONAME 419 e.theSink.Orig = &e.theSink 420 e.theSink.Class = PEXTERN 421 e.theSink.Sym = Lookup(".sink") 422 e.nodeEscState(&e.theSink).Escloopdepth = -1 423 e.recursive = recursive 424 425 for i := len(all) - 1; i >= 0; i-- { 426 if n := all[i]; n.Op == ODCLFUNC { 427 n.Esc = EscFuncPlanned 428 } 429 } 430 431 // flow-analyze functions 432 for i := len(all) - 1; i >= 0; i-- { 433 if n := all[i]; n.Op == ODCLFUNC { 434 escfunc(e, n) 435 } 436 } 437 438 // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount); 439 440 // visit the upstream of each dst, mark address nodes with 441 // addrescapes, mark parameters unsafe 442 for l := e.dsts; l != nil; l = l.Next { 443 escflood(e, l.N) 444 } 445 446 // for all top level functions, tag the typenodes corresponding to the param nodes 447 for i := len(all) - 1; i >= 0; i-- { 448 if n := all[i]; n.Op == ODCLFUNC { 449 esctag(e, n) 450 } 451 } 452 453 if Debug['m'] != 0 { 454 for l := e.noesc; l != nil; l = l.Next { 455 if l.N.Esc == EscNone { 456 Warnl(int(l.N.Lineno), "%v %v does not escape", e.curfnSym(l.N), Nconv(l.N, obj.FmtShort)) 457 } 458 } 459 } 460 for _, x := range e.opts { 461 x.SetOpt(nil) 462 } 463 } 464 465 func escfunc(e *EscState, func_ *Node) { 466 // print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":""); 467 if func_.Esc != 1 { 468 Fatalf("repeat escfunc %v", func_.Func.Nname) 469 } 470 func_.Esc = EscFuncStarted 471 472 saveld := e.loopdepth 473 e.loopdepth = 1 474 savefn := Curfn 475 Curfn = func_ 476 477 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 478 if ll.N.Op != ONAME { 479 continue 480 } 481 llNE := e.nodeEscState(ll.N) 482 switch ll.N.Class { 483 // out params are in a loopdepth between the sink and all local variables 484 case PPARAMOUT: 485 llNE.Escloopdepth = 0 486 487 case PPARAM: 488 llNE.Escloopdepth = 1 489 if ll.N.Type != nil && !haspointers(ll.N.Type) { 490 break 491 } 492 if Curfn.Nbody == nil && !Curfn.Noescape { 493 ll.N.Esc = EscHeap 494 } else { 495 ll.N.Esc = EscNone // prime for escflood later 496 } 497 e.noesc = list(e.noesc, ll.N) 498 } 499 } 500 501 // in a mutually recursive group we lose track of the return values 502 if e.recursive { 503 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 504 if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT { 505 escflows(e, &e.theSink, ll.N) 506 } 507 } 508 } 509 510 escloopdepthlist(e, Curfn.Nbody) 511 esclist(e, Curfn.Nbody, Curfn) 512 Curfn = savefn 513 e.loopdepth = saveld 514 } 515 516 // Mark labels that have no backjumps to them as not increasing e->loopdepth. 517 // Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat 518 // and set it to one of the following two. Then in esc we'll clear it again. 519 var looping Label 520 521 var nonlooping Label 522 523 func escloopdepthlist(e *EscState, l *NodeList) { 524 for ; l != nil; l = l.Next { 525 escloopdepth(e, l.N) 526 } 527 } 528 529 func escloopdepth(e *EscState, n *Node) { 530 if n == nil { 531 return 532 } 533 534 escloopdepthlist(e, n.Ninit) 535 536 switch n.Op { 537 case OLABEL: 538 if n.Left == nil || n.Left.Sym == nil { 539 Fatalf("esc:label without label: %v", Nconv(n, obj.FmtSign)) 540 } 541 542 // Walk will complain about this label being already defined, but that's not until 543 // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc 544 // if(n->left->sym->label != nil) 545 // fatal("escape analysis messed up analyzing label: %+N", n); 546 n.Left.Sym.Label = &nonlooping 547 548 case OGOTO: 549 if n.Left == nil || n.Left.Sym == nil { 550 Fatalf("esc:goto without label: %v", Nconv(n, obj.FmtSign)) 551 } 552 553 // If we come past one that's uninitialized, this must be a (harmless) forward jump 554 // but if it's set to nonlooping the label must have preceded this goto. 555 if n.Left.Sym.Label == &nonlooping { 556 n.Left.Sym.Label = &looping 557 } 558 } 559 560 escloopdepth(e, n.Left) 561 escloopdepth(e, n.Right) 562 escloopdepthlist(e, n.List) 563 escloopdepthlist(e, n.Nbody) 564 escloopdepthlist(e, n.Rlist) 565 } 566 567 func esclist(e *EscState, l *NodeList, up *Node) { 568 for ; l != nil; l = l.Next { 569 esc(e, l.N, up) 570 } 571 } 572 573 func esc(e *EscState, n *Node, up *Node) { 574 if n == nil { 575 return 576 } 577 578 lno := int(setlineno(n)) 579 580 // ninit logically runs at a different loopdepth than the rest of the for loop. 581 esclist(e, n.Ninit, n) 582 583 if n.Op == OFOR || n.Op == ORANGE { 584 e.loopdepth++ 585 } 586 587 // type switch variables have no ODCL. 588 // process type switch as declaration. 589 // must happen before processing of switch body, 590 // so before recursion. 591 if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW { 592 for ll := n.List; ll != nil; ll = ll.Next { // cases 593 594 // ll.N.Rlist is the variable per case 595 if ll.N.Rlist != nil { 596 e.nodeEscState(ll.N.Rlist.N).Escloopdepth = e.loopdepth 597 } 598 } 599 } 600 601 // Big stuff escapes unconditionally 602 // "Big" conditions that were scattered around in walk have been gathered here 603 if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize || 604 n.Op == ONEW && n.Type.Type.Width >= 1<<16 || 605 n.Op == OMAKESLICE && !isSmallMakeSlice(n)) { 606 if Debug['m'] > 1 { 607 Warnl(int(n.Lineno), "%v is too large for stack", n) 608 } 609 n.Esc = EscHeap 610 addrescapes(n) 611 escassign(e, &e.theSink, n) 612 } 613 614 esc(e, n.Left, n) 615 esc(e, n.Right, n) 616 esclist(e, n.Nbody, n) 617 esclist(e, n.List, n) 618 esclist(e, n.Rlist, n) 619 620 if n.Op == OFOR || n.Op == ORANGE { 621 e.loopdepth-- 622 } 623 624 if Debug['m'] > 1 { 625 fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n) 626 } 627 628 switch n.Op { 629 // Record loop depth at declaration. 630 case ODCL: 631 if n.Left != nil { 632 e.nodeEscState(n.Left).Escloopdepth = e.loopdepth 633 } 634 635 case OLABEL: 636 if n.Left.Sym.Label == &nonlooping { 637 if Debug['m'] > 1 { 638 fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), n) 639 } 640 } else if n.Left.Sym.Label == &looping { 641 if Debug['m'] > 1 { 642 fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), n) 643 } 644 e.loopdepth++ 645 } 646 647 // See case OLABEL in escloopdepth above 648 // else if(n->left->sym->label == nil) 649 // fatal("escape analysis missed or messed up a label: %+N", n); 650 651 n.Left.Sym.Label = nil 652 653 // Everything but fixed array is a dereference. 654 case ORANGE: 655 if n.List != nil && n.List.Next != nil { 656 if Isfixedarray(n.Type) { 657 escassign(e, n.List.Next.N, n.Right) 658 } else { 659 escassignDereference(e, n.List.Next.N, n.Right) 660 } 661 } 662 663 case OSWITCH: 664 if n.Left != nil && n.Left.Op == OTYPESW { 665 for ll := n.List; ll != nil; ll = ll.Next { 666 // cases 667 // n.Left.Right is the argument of the .(type), 668 // ll.N.Rlist is the variable per case 669 if ll.N.Rlist != nil { 670 escassign(e, ll.N.Rlist.N, n.Left.Right) 671 } 672 } 673 } 674 675 // Filter out the following special case. 676 // 677 // func (b *Buffer) Foo() { 678 // n, m := ... 679 // b.buf = b.buf[n:m] 680 // } 681 // 682 // This assignment is a no-op for escape analysis, 683 // it does not store any new pointers into b that were not already there. 684 // However, without this special case b will escape, because we assign to OIND/ODOTPTR. 685 case OAS, OASOP, OASWB: 686 if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference 687 (n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation 688 (n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference 689 n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME 690 691 // Here we also assume that the statement will not contain calls, 692 // that is, that order will move any calls to init. 693 // Otherwise base ONAME value could change between the moments 694 // when we evaluate it for dst and for src. 695 // 696 // Note, this optimization does not apply to OSLICEARR, 697 // because it does introduce a new pointer into b that was not already there 698 // (pointer to b itself). After such assignment, if b contents escape, 699 // b escapes as well. If we ignore such OSLICEARR, we will conclude 700 // that b does not escape when b contents do. 701 if Debug['m'] != 0 { 702 Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, obj.FmtShort)) 703 } 704 705 break 706 } 707 708 escassign(e, n.Left, n.Right) 709 710 case OAS2: // x,y = a,b 711 if count(n.List) == count(n.Rlist) { 712 ll := n.List 713 lr := n.Rlist 714 for ; ll != nil; ll, lr = ll.Next, lr.Next { 715 escassign(e, ll.N, lr.N) 716 } 717 } 718 719 case OAS2RECV, // v, ok = <-ch 720 OAS2MAPR, // v, ok = m[k] 721 OAS2DOTTYPE: // v, ok = x.(type) 722 escassign(e, n.List.N, n.Rlist.N) 723 724 case OSEND: // ch <- x 725 escassign(e, &e.theSink, n.Right) 726 727 case ODEFER: 728 if e.loopdepth == 1 { // top level 729 break 730 } 731 // arguments leak out of scope 732 // TODO: leak to a dummy node instead 733 fallthrough 734 735 case OPROC: 736 // go f(x) - f and x escape 737 escassign(e, &e.theSink, n.Left.Left) 738 739 escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call 740 for ll := n.Left.List; ll != nil; ll = ll.Next { 741 escassign(e, &e.theSink, ll.N) 742 } 743 744 case OCALLMETH, OCALLFUNC, OCALLINTER: 745 esccall(e, n, up) 746 747 // esccall already done on n->rlist->n. tie it's escretval to n->list 748 case OAS2FUNC: // x,y = f() 749 lr := e.nodeEscState(n.Rlist.N).Escretval 750 751 var ll *NodeList 752 for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next { 753 escassign(e, ll.N, lr.N) 754 } 755 if lr != nil || ll != nil { 756 Fatalf("esc oas2func") 757 } 758 759 case ORETURN: 760 ll := n.List 761 if count(n.List) == 1 && Curfn.Type.Outtuple > 1 { 762 // OAS2FUNC in disguise 763 // esccall already done on n->list->n 764 // tie n->list->n->escretval to curfn->dcl PPARAMOUT's 765 ll = e.nodeEscState(n.List.N).Escretval 766 } 767 768 for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next { 769 if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT { 770 continue 771 } 772 escassign(e, lr.N, ll.N) 773 ll = ll.Next 774 } 775 776 if ll != nil { 777 Fatalf("esc return list") 778 } 779 780 // Argument could leak through recover. 781 case OPANIC: 782 escassign(e, &e.theSink, n.Left) 783 784 case OAPPEND: 785 if !n.Isddd { 786 for ll := n.List.Next; ll != nil; ll = ll.Next { 787 escassign(e, &e.theSink, ll.N) // lose track of assign to dereference 788 } 789 } else { 790 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. 791 slice2 := n.List.Next.N 792 escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference 793 if Debug['m'] > 2 { 794 Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort)) 795 } 796 } 797 escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too 798 799 case OCOPY: 800 escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference 801 802 case OCONV, OCONVNOP: 803 escassign(e, n, n.Left) 804 805 case OCONVIFACE: 806 e.track(n) 807 escassign(e, n, n.Left) 808 809 case OARRAYLIT: 810 if Isslice(n.Type) { 811 // Slice itself is not leaked until proven otherwise 812 e.track(n) 813 } 814 815 // Link values to array/slice 816 for ll := n.List; ll != nil; ll = ll.Next { 817 escassign(e, n, ll.N.Right) 818 } 819 820 // Link values to struct. 821 case OSTRUCTLIT: 822 for ll := n.List; ll != nil; ll = ll.Next { 823 escassign(e, n, ll.N.Right) 824 } 825 826 case OPTRLIT: 827 e.track(n) 828 829 // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. 830 escassign(e, n, n.Left) 831 832 case OCALLPART: 833 e.track(n) 834 835 // Contents make it to memory, lose track. 836 escassign(e, &e.theSink, n.Left) 837 838 case OMAPLIT: 839 e.track(n) 840 841 // Keys and values make it to memory, lose track. 842 for ll := n.List; ll != nil; ll = ll.Next { 843 escassign(e, &e.theSink, ll.N.Left) 844 escassign(e, &e.theSink, ll.N.Right) 845 } 846 847 // Link addresses of captured variables to closure. 848 case OCLOSURE: 849 var a *Node 850 var v *Node 851 for ll := n.Func.Cvars; ll != nil; ll = ll.Next { 852 v = ll.N 853 if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs 854 continue 855 } 856 a = v.Name.Param.Closure 857 if !v.Name.Byval { 858 a = Nod(OADDR, a, nil) 859 a.Lineno = v.Lineno 860 e.nodeEscState(a).Escloopdepth = e.loopdepth 861 typecheck(&a, Erv) 862 } 863 864 escassign(e, n, a) 865 } 866 fallthrough 867 868 case OMAKECHAN, 869 OMAKEMAP, 870 OMAKESLICE, 871 ONEW, 872 OARRAYRUNESTR, 873 OARRAYBYTESTR, 874 OSTRARRAYRUNE, 875 OSTRARRAYBYTE, 876 ORUNESTR: 877 e.track(n) 878 879 case OADDSTR: 880 e.track(n) 881 // Arguments of OADDSTR do not escape. 882 883 case OADDR: 884 // current loop depth is an upper bound on actual loop depth 885 // of addressed value. 886 e.track(n) 887 888 // for &x, use loop depth of x if known. 889 // it should always be known, but if not, be conservative 890 // and keep the current loop depth. 891 if n.Left.Op == ONAME { 892 switch n.Left.Class { 893 case PAUTO: 894 nE := e.nodeEscState(n) 895 leftE := e.nodeEscState(n.Left) 896 if leftE.Escloopdepth != 0 { 897 nE.Escloopdepth = leftE.Escloopdepth 898 } 899 900 // PPARAM is loop depth 1 always. 901 // PPARAMOUT is loop depth 0 for writes 902 // but considered loop depth 1 for address-of, 903 // so that writing the address of one result 904 // to another (or the same) result makes the 905 // first result move to the heap. 906 case PPARAM, PPARAMOUT: 907 nE := e.nodeEscState(n) 908 nE.Escloopdepth = 1 909 } 910 } 911 } 912 913 lineno = int32(lno) 914 } 915 916 // Assert that expr somehow gets assigned to dst, if non nil. for 917 // dst==nil, any name node expr still must be marked as being 918 // evaluated in curfn. For expr==nil, dst must still be examined for 919 // evaluations inside it (e.g *f(x) = y) 920 func escassign(e *EscState, dst *Node, src *Node) { 921 if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX { 922 return 923 } 924 925 if Debug['m'] > 1 { 926 fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n", 927 Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), 928 Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0), 929 Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0)) 930 } 931 932 setlineno(dst) 933 934 // Analyze lhs of assignment. 935 // Replace dst with e->theSink if we can't track it. 936 switch dst.Op { 937 default: 938 Dump("dst", dst) 939 Fatalf("escassign: unexpected dst") 940 941 case OARRAYLIT, 942 OCLOSURE, 943 OCONV, 944 OCONVIFACE, 945 OCONVNOP, 946 OMAPLIT, 947 OSTRUCTLIT, 948 OPTRLIT, 949 OCALLPART: 950 break 951 952 case ONAME: 953 if dst.Class == PEXTERN { 954 dst = &e.theSink 955 } 956 957 case ODOT: // treat "dst.x = src" as "dst = src" 958 escassign(e, dst.Left, src) 959 960 return 961 962 case OINDEX: 963 if Isfixedarray(dst.Left.Type) { 964 escassign(e, dst.Left, src) 965 return 966 } 967 968 dst = &e.theSink // lose track of dereference 969 970 case OIND, ODOTPTR: 971 dst = &e.theSink // lose track of dereference 972 973 // lose track of key and value 974 case OINDEXMAP: 975 escassign(e, &e.theSink, dst.Right) 976 977 dst = &e.theSink 978 } 979 980 lno := int(setlineno(src)) 981 e.pdepth++ 982 983 switch src.Op { 984 case OADDR, // dst = &x 985 OIND, // dst = *x 986 ODOTPTR, // dst = (*x).f 987 ONAME, 988 OPARAM, 989 ODDDARG, 990 OPTRLIT, 991 OARRAYLIT, 992 OMAPLIT, 993 OSTRUCTLIT, 994 OMAKECHAN, 995 OMAKEMAP, 996 OMAKESLICE, 997 OARRAYRUNESTR, 998 OARRAYBYTESTR, 999 OSTRARRAYRUNE, 1000 OSTRARRAYBYTE, 1001 OADDSTR, 1002 ONEW, 1003 OCALLPART, 1004 ORUNESTR, 1005 OCONVIFACE: 1006 escflows(e, dst, src) 1007 1008 case OCLOSURE: 1009 // OCLOSURE is lowered to OPTRLIT, 1010 // insert OADDR to account for the additional indirection. 1011 a := Nod(OADDR, src, nil) 1012 a.Lineno = src.Lineno 1013 e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth 1014 a.Type = Ptrto(src.Type) 1015 escflows(e, dst, a) 1016 1017 // Flowing multiple returns to a single dst happens when 1018 // analyzing "go f(g())": here g() flows to sink (issue 4529). 1019 case OCALLMETH, OCALLFUNC, OCALLINTER: 1020 for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next { 1021 escflows(e, dst, ll.N) 1022 } 1023 1024 // A non-pointer escaping from a struct does not concern us. 1025 case ODOT: 1026 if src.Type != nil && !haspointers(src.Type) { 1027 break 1028 } 1029 fallthrough 1030 1031 // Conversions, field access, slice all preserve the input value. 1032 case OCONV, 1033 OCONVNOP, 1034 ODOTMETH, 1035 // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 1036 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 1037 ODOTTYPE, 1038 ODOTTYPE2, 1039 OSLICE, 1040 OSLICE3, 1041 OSLICEARR, 1042 OSLICE3ARR, 1043 OSLICESTR: 1044 // Conversions, field access, slice all preserve the input value. 1045 escassign(e, dst, src.Left) 1046 1047 case OAPPEND: 1048 // Append returns first argument. 1049 // Subsequent arguments are already leaked because they are operands to append. 1050 escassign(e, dst, src.List.N) 1051 1052 case OINDEX: 1053 // Index of array preserves input value. 1054 if Isfixedarray(src.Left.Type) { 1055 escassign(e, dst, src.Left) 1056 } else { 1057 escflows(e, dst, src) 1058 } 1059 1060 // Might be pointer arithmetic, in which case 1061 // the operands flow into the result. 1062 // TODO(rsc): Decide what the story is here. This is unsettling. 1063 case OADD, 1064 OSUB, 1065 OOR, 1066 OXOR, 1067 OMUL, 1068 ODIV, 1069 OMOD, 1070 OLSH, 1071 ORSH, 1072 OAND, 1073 OANDNOT, 1074 OPLUS, 1075 OMINUS, 1076 OCOM: 1077 escassign(e, dst, src.Left) 1078 1079 escassign(e, dst, src.Right) 1080 } 1081 1082 e.pdepth-- 1083 lineno = int32(lno) 1084 } 1085 1086 // Common case for escapes is 16 bits 000000000xxxEEEE 1087 // where commonest cases for xxx encoding in-to-out pointer 1088 // flow are 000, 001, 010, 011 and EEEE is computed Esc bits. 1089 // Note width of xxx depends on value of constant 1090 // bitsPerOutputInTag -- expect 2 or 3, so in practice the 1091 // tag cache array is 64 or 128 long. Some entries will 1092 // never be populated. 1093 var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string 1094 1095 // mktag returns the string representation for an escape analysis tag. 1096 func mktag(mask int) *string { 1097 switch mask & EscMask { 1098 case EscNone, EscReturn: 1099 break 1100 1101 default: 1102 Fatalf("escape mktag") 1103 } 1104 1105 if mask < len(tags) && tags[mask] != "" { 1106 return &tags[mask] 1107 } 1108 1109 s := fmt.Sprintf("esc:0x%x", mask) 1110 if mask < len(tags) { 1111 tags[mask] = s 1112 } 1113 return &s 1114 } 1115 1116 // parsetag decodes an escape analysis tag and returns the esc value. 1117 func parsetag(note *string) uint16 { 1118 if note == nil || !strings.HasPrefix(*note, "esc:") { 1119 return EscUnknown 1120 } 1121 em := uint16(atoi((*note)[4:])) 1122 if em == 0 { 1123 return EscNone 1124 } 1125 return em 1126 } 1127 1128 // describeEscape returns a string describing the escape tag. 1129 // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation 1130 // or a description of parameter flow, which takes the form of an optional "contentToHeap" 1131 // indicating that the content of this parameter is leaked to the heap, followed by a sequence 1132 // of level encodings separated by spaces, one for each parameter, where _ means no flow, 1133 // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow. 1134 // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences) 1135 // escapes to the heap, the parameter does not leak to the first output, but does leak directly 1136 // to the second output (and if there are more than two outputs, there is no flow to those.) 1137 func describeEscape(em uint16) string { 1138 var s string 1139 if em&EscMask == EscUnknown { 1140 s = "EscUnknown" 1141 } 1142 if em&EscMask == EscNone { 1143 s = "EscNone" 1144 } 1145 if em&EscMask == EscHeap { 1146 s = "EscHeap" 1147 } 1148 if em&EscMask == EscReturn { 1149 s = "EscReturn" 1150 } 1151 if em&EscMask == EscScope { 1152 s = "EscScope" 1153 } 1154 if em&EscContentEscapes != 0 { 1155 if s != "" { 1156 s += " " 1157 } 1158 s += "contentToHeap" 1159 } 1160 for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag { 1161 // See encoding description above 1162 if s != "" { 1163 s += " " 1164 } 1165 switch embits := em & bitsMaskForTag; embits { 1166 case 0: 1167 s += "_" 1168 case 1: 1169 s += "=" 1170 default: 1171 for i := uint16(0); i < embits-1; i++ { 1172 s += "*" 1173 } 1174 } 1175 1176 } 1177 return s 1178 } 1179 1180 // escassignfromtag models the input-to-output assignment flow of one of a function 1181 // calls arguments, where the flow is encoded in "note". 1182 func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 { 1183 em := parsetag(note) 1184 if src.Op == OLITERAL { 1185 return em 1186 } 1187 1188 if Debug['m'] > 2 { 1189 fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n", 1190 Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em)) 1191 } 1192 1193 if em == EscUnknown { 1194 escassign(e, &e.theSink, src) 1195 return em 1196 } 1197 1198 if em == EscNone { 1199 return em 1200 } 1201 1202 // If content inside parameter (reached via indirection) 1203 // escapes to heap, mark as such. 1204 if em&EscContentEscapes != 0 { 1205 escassign(e, &e.theSink, e.addDereference(src)) 1206 } 1207 1208 em0 := em 1209 for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next { 1210 // Prefer the lowest-level path to the reference (for escape purposes). 1211 // Two-bit encoding (for example. 1, 3, and 4 bits are other options) 1212 // 01 = 0-level 1213 // 10 = 1-level, (content escapes), 1214 // 11 = 2-level, (content of content escapes), 1215 embits := em & bitsMaskForTag 1216 if embits > 0 { 1217 n := src 1218 for i := uint16(0); i < embits-1; i++ { 1219 n = e.addDereference(n) // encode level>0 as indirections 1220 } 1221 escassign(e, dsts.N, n) 1222 } 1223 } 1224 // If there are too many outputs to fit in the tag, 1225 // that is handled at the encoding end as EscHeap, 1226 // so there is no need to check here. 1227 1228 if em != 0 && dsts == nil { 1229 Fatalf("corrupt esc tag %q or messed up escretval list\n", note) 1230 } 1231 return em0 1232 } 1233 1234 func escassignDereference(e *EscState, dst *Node, src *Node) { 1235 if src.Op == OLITERAL { 1236 return 1237 } 1238 escassign(e, dst, e.addDereference(src)) 1239 } 1240 1241 // addDereference constructs a suitable OIND note applied to src. 1242 // Because this is for purposes of escape accounting, not execution, 1243 // some semantically dubious node combinations are (currently) possible. 1244 func (e *EscState) addDereference(n *Node) *Node { 1245 ind := Nod(OIND, n, nil) 1246 e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth 1247 ind.Lineno = n.Lineno 1248 t := n.Type 1249 if Istype(t, Tptr) { 1250 // This should model our own sloppy use of OIND to encode 1251 // decreasing levels of indirection; i.e., "indirecting" an array 1252 // might yield the type of an element. To be enhanced... 1253 t = t.Type 1254 } 1255 ind.Type = t 1256 return ind 1257 } 1258 1259 // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter. 1260 // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel. 1261 // If the encoding cannot describe the modified input level and output number, then EscHeap is returned. 1262 func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { 1263 // Flow+level is encoded in two bits. 1264 // 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel 1265 // 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful. 1266 if level.int() <= 0 && level.guaranteedDereference() > 0 { 1267 return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content. 1268 } 1269 if level.int() < 0 { 1270 return EscHeap 1271 } 1272 if level.int() > maxEncodedLevel { 1273 // Cannot encode larger values than maxEncodedLevel. 1274 level = levelFrom(maxEncodedLevel) 1275 } 1276 encoded := uint16(level.int() + 1) 1277 1278 shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits) 1279 old := (e >> shift) & bitsMaskForTag 1280 if old == 0 || encoded != 0 && encoded < old { 1281 old = encoded 1282 } 1283 1284 encodedFlow := old << shift 1285 if (encodedFlow>>shift)&bitsMaskForTag != old { 1286 // Encoding failure defaults to heap. 1287 return EscHeap 1288 } 1289 1290 return (e &^ (bitsMaskForTag << shift)) | encodedFlow 1291 } 1292 1293 func initEscretval(e *EscState, n *Node, fntype *Type) { 1294 i := 0 1295 nE := e.nodeEscState(n) 1296 nE.Escretval = nil // Suspect this is not nil for indirect calls. 1297 for t := getoutargx(fntype).Type; t != nil; t = t.Down { 1298 src := Nod(ONAME, nil, nil) 1299 buf := fmt.Sprintf(".out%d", i) 1300 i++ 1301 src.Sym = Lookup(buf) 1302 src.Type = t.Type 1303 src.Class = PAUTO 1304 src.Name.Curfn = Curfn 1305 e.nodeEscState(src).Escloopdepth = e.loopdepth 1306 src.Used = true 1307 src.Lineno = n.Lineno 1308 nE.Escretval = list(nE.Escretval, src) 1309 } 1310 } 1311 1312 // This is a bit messier than fortunate, pulled out of esc's big 1313 // switch for clarity. We either have the paramnodes, which may be 1314 // connected to other things through flows or we have the parameter type 1315 // nodes, which may be marked "noescape". Navigating the ast is slightly 1316 // different for methods vs plain functions and for imported vs 1317 // this-package 1318 func esccall(e *EscState, n *Node, up *Node) { 1319 var fntype *Type 1320 var indirect bool 1321 var fn *Node 1322 switch n.Op { 1323 default: 1324 Fatalf("esccall") 1325 1326 case OCALLFUNC: 1327 fn = n.Left 1328 fntype = fn.Type 1329 indirect = fn.Op != ONAME || fn.Class != PFUNC 1330 1331 case OCALLMETH: 1332 fn = n.Left.Right.Sym.Def 1333 if fn != nil { 1334 fntype = fn.Type 1335 } else { 1336 fntype = n.Left.Type 1337 } 1338 1339 case OCALLINTER: 1340 fntype = n.Left.Type 1341 indirect = true 1342 } 1343 1344 ll := n.List 1345 if n.List != nil && n.List.Next == nil { 1346 a := n.List.N 1347 if a.Type.Etype == TSTRUCT && a.Type.Funarg { // f(g()). 1348 ll = e.nodeEscState(a).Escretval 1349 } 1350 } 1351 1352 if indirect { 1353 // We know nothing! 1354 // Leak all the parameters 1355 for ; ll != nil; ll = ll.Next { 1356 escassign(e, &e.theSink, ll.N) 1357 if Debug['m'] > 2 { 1358 fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1359 } 1360 } 1361 // Set up bogus outputs 1362 initEscretval(e, n, fntype) 1363 // If there is a receiver, it also leaks to heap. 1364 if n.Op != OCALLFUNC { 1365 t := getthisx(fntype).Type 1366 src := n.Left.Left 1367 if haspointers(t.Type) { 1368 escassign(e, &e.theSink, src) 1369 } 1370 } 1371 return 1372 } 1373 1374 nE := e.nodeEscState(n) 1375 if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && 1376 fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged { 1377 if Debug['m'] > 2 { 1378 fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) 1379 } 1380 1381 // function in same mutually recursive group. Incorporate into flow graph. 1382 // print("esc local fn: %N\n", fn->ntype); 1383 if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil { 1384 Fatalf("graph inconsistency") 1385 } 1386 1387 // set up out list on this call node 1388 for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next { 1389 nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT) 1390 } 1391 1392 // Receiver. 1393 if n.Op != OCALLFUNC { 1394 escassign(e, fn.Name.Param.Ntype.Left.Left, n.Left.Left) 1395 } 1396 1397 var src *Node 1398 for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next { 1399 src = ll.N 1400 if lr.N.Isddd && !n.Isddd { 1401 // Introduce ODDDARG node to represent ... allocation. 1402 src = Nod(ODDDARG, nil, nil) 1403 src.Type = typ(TARRAY) 1404 src.Type.Type = lr.N.Type.Type 1405 src.Type.Bound = int64(count(ll)) 1406 src.Type = Ptrto(src.Type) // make pointer so it will be tracked 1407 src.Lineno = n.Lineno 1408 e.track(src) 1409 n.Right = src 1410 } 1411 1412 if lr.N.Left != nil { 1413 escassign(e, lr.N.Left, src) 1414 } 1415 if src != ll.N { 1416 break 1417 } 1418 } 1419 1420 // "..." arguments are untracked 1421 for ; ll != nil; ll = ll.Next { 1422 if Debug['m'] > 2 { 1423 fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1424 } 1425 escassign(e, &e.theSink, ll.N) 1426 } 1427 1428 return 1429 } 1430 1431 // Imported or completely analyzed function. Use the escape tags. 1432 if nE.Escretval != nil { 1433 Fatalf("esc already decorated call %v\n", Nconv(n, obj.FmtSign)) 1434 } 1435 1436 if Debug['m'] > 2 { 1437 fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) 1438 } 1439 1440 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 1441 initEscretval(e, n, fntype) 1442 1443 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); 1444 1445 // Receiver. 1446 if n.Op != OCALLFUNC { 1447 t := getthisx(fntype).Type 1448 src := n.Left.Left 1449 if haspointers(t.Type) { 1450 escassignfromtag(e, t.Note, nE.Escretval, src) 1451 } 1452 } 1453 1454 for t := getinargx(fntype).Type; ll != nil; ll = ll.Next { 1455 src := ll.N 1456 if t.Isddd && !n.Isddd { 1457 // Introduce ODDDARG node to represent ... allocation. 1458 src = Nod(ODDDARG, nil, nil) 1459 src.Lineno = n.Lineno 1460 src.Type = typ(TARRAY) 1461 src.Type.Type = t.Type.Type 1462 src.Type.Bound = int64(count(ll)) 1463 src.Type = Ptrto(src.Type) // make pointer so it will be tracked 1464 e.track(src) 1465 n.Right = src 1466 } 1467 1468 if haspointers(t.Type) { 1469 if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC { 1470 a := src 1471 for a.Op == OCONVNOP { 1472 a = a.Left 1473 } 1474 switch a.Op { 1475 // The callee has already been analyzed, so its arguments have esc tags. 1476 // The argument is marked as not escaping at all. 1477 // Record that fact so that any temporary used for 1478 // synthesizing this expression can be reclaimed when 1479 // the function returns. 1480 // This 'noescape' is even stronger than the usual esc == EscNone. 1481 // src->esc == EscNone means that src does not escape the current function. 1482 // src->noescape = 1 here means that src does not escape this statement 1483 // in the current function. 1484 case OCALLPART, 1485 OCLOSURE, 1486 ODDDARG, 1487 OARRAYLIT, 1488 OPTRLIT, 1489 OSTRUCTLIT: 1490 a.Noescape = true 1491 } 1492 } 1493 } 1494 1495 if src != ll.N { 1496 break 1497 } 1498 t = t.Down 1499 } 1500 1501 // "..." arguments are untracked 1502 for ; ll != nil; ll = ll.Next { 1503 escassign(e, &e.theSink, ll.N) 1504 if Debug['m'] > 2 { 1505 fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1506 } 1507 } 1508 } 1509 1510 // escflows records the link src->dst in dst, throwing out some quick wins, 1511 // and also ensuring that dst is noted as a flow destination. 1512 func escflows(e *EscState, dst *Node, src *Node) { 1513 if dst == nil || src == nil || dst == src { 1514 return 1515 } 1516 1517 // Don't bother building a graph for scalars. 1518 if src.Type != nil && !haspointers(src.Type) { 1519 return 1520 } 1521 1522 if Debug['m'] > 2 { 1523 fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort)) 1524 } 1525 1526 dstE := e.nodeEscState(dst) 1527 if dstE.Escflowsrc == nil { 1528 e.dsts = list(e.dsts, dst) 1529 e.dstcount++ 1530 } 1531 1532 e.edgecount++ 1533 1534 dstE.Escflowsrc = list(dstE.Escflowsrc, src) 1535 } 1536 1537 // Whenever we hit a reference node, the level goes up by one, and whenever 1538 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 1539 // finding an OADDR just means we're following the upstream of a dereference, 1540 // so this address doesn't leak (yet). 1541 // If level == 0, it means the /value/ of this node can reach the root of this flood. 1542 // so if this node is an OADDR, it's argument should be marked as escaping iff 1543 // it's currfn/e->loopdepth are different from the flood's root. 1544 // Once an object has been moved to the heap, all of it's upstream should be considered 1545 // escaping to the global scope. 1546 func escflood(e *EscState, dst *Node) { 1547 switch dst.Op { 1548 case ONAME, OCLOSURE: 1549 break 1550 1551 default: 1552 return 1553 } 1554 1555 dstE := e.nodeEscState(dst) 1556 if Debug['m'] > 1 { 1557 fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth) 1558 } 1559 1560 for l := dstE.Escflowsrc; l != nil; l = l.Next { 1561 e.walkgen++ 1562 escwalk(e, levelFrom(0), dst, l.N) 1563 } 1564 } 1565 1566 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function. 1567 func funcOutputAndInput(dst, src *Node) bool { 1568 // Note if dst is marked as escaping, then "returned" is too weak. 1569 return dst.Op == ONAME && dst.Class == PPARAMOUT && 1570 src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn 1571 } 1572 1573 func escwalk(e *EscState, level Level, dst *Node, src *Node) { 1574 if src.Op == OLITERAL { 1575 return 1576 } 1577 srcE := e.nodeEscState(src) 1578 if srcE.Walkgen == e.walkgen { 1579 // Esclevels are vectors, do not compare as integers, 1580 // and must use "min" of old and new to guarantee 1581 // convergence. 1582 level = level.min(srcE.Esclevel) 1583 if level == srcE.Esclevel { 1584 return 1585 } 1586 } 1587 1588 srcE.Walkgen = e.walkgen 1589 srcE.Esclevel = level 1590 1591 if Debug['m'] > 1 { 1592 fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n", 1593 level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), e.curfnSym(src), srcE.Escloopdepth) 1594 } 1595 1596 e.pdepth++ 1597 1598 // Input parameter flowing to output parameter? 1599 var leaks bool 1600 dstE := e.nodeEscState(dst) 1601 if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap { 1602 // This case handles: 1603 // 1. return in 1604 // 2. return &in 1605 // 3. tmp := in; return &tmp 1606 // 4. return *in 1607 if Debug['m'] != 0 { 1608 if Debug['m'] == 1 { 1609 Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int()) 1610 } else { 1611 Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level) 1612 } 1613 } 1614 if src.Esc&EscMask != EscReturn { 1615 src.Esc = EscReturn | src.Esc&EscContentEscapes 1616 } 1617 src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level) 1618 goto recurse 1619 } 1620 1621 // If parameter content escapes to heap, set EscContentEscapes 1622 // Note minor confusion around escape from pointer-to-struct vs escape from struct 1623 if dst.Esc == EscHeap && 1624 src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope && 1625 level.int() > 0 { 1626 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1627 if Debug['m'] != 0 { 1628 Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort)) 1629 } 1630 } 1631 1632 leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < srcE.Escloopdepth 1633 1634 switch src.Op { 1635 case ONAME: 1636 if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope { 1637 if level.guaranteedDereference() > 0 { 1638 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1639 if Debug['m'] != 0 { 1640 if Debug['m'] == 1 { 1641 Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort)) 1642 } else { 1643 Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v", 1644 Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort)) 1645 } 1646 } 1647 } else { 1648 src.Esc = EscScope 1649 if Debug['m'] != 0 { 1650 if Debug['m'] == 1 { 1651 Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort)) 1652 } else { 1653 Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v", 1654 Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort)) 1655 } 1656 } 1657 } 1658 } 1659 1660 // Treat a PPARAMREF closure variable as equivalent to the 1661 // original variable. 1662 if src.Class == PPARAMREF { 1663 if leaks && Debug['m'] != 0 { 1664 Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort)) 1665 } 1666 escwalk(e, level, dst, src.Name.Param.Closure) 1667 } 1668 1669 case OPTRLIT, OADDR: 1670 if leaks { 1671 src.Esc = EscHeap 1672 addrescapes(src.Left) 1673 if Debug['m'] != 0 { 1674 p := src 1675 if p.Left.Op == OCLOSURE { 1676 p = p.Left // merely to satisfy error messages in tests 1677 } 1678 if Debug['m'] > 1 { 1679 Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v", 1680 Nconv(p, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth) 1681 } else { 1682 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort)) 1683 } 1684 } 1685 } 1686 1687 escwalk(e, level.dec(), dst, src.Left) 1688 1689 case OAPPEND: 1690 escwalk(e, level, dst, src.List.N) 1691 1692 case OARRAYLIT: 1693 if Isfixedarray(src.Type) { 1694 break 1695 } 1696 for ll := src.List; ll != nil; ll = ll.Next { 1697 escwalk(e, level.dec(), dst, ll.N.Right) 1698 } 1699 1700 fallthrough 1701 1702 case ODDDARG, 1703 OMAKECHAN, 1704 OMAKEMAP, 1705 OMAKESLICE, 1706 OARRAYRUNESTR, 1707 OARRAYBYTESTR, 1708 OSTRARRAYRUNE, 1709 OSTRARRAYBYTE, 1710 OADDSTR, 1711 OMAPLIT, 1712 ONEW, 1713 OCLOSURE, 1714 OCALLPART, 1715 ORUNESTR, 1716 OCONVIFACE: 1717 if leaks { 1718 src.Esc = EscHeap 1719 if Debug['m'] != 0 { 1720 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort)) 1721 } 1722 } 1723 1724 case ODOT, 1725 ODOTTYPE, 1726 OSLICE, 1727 OSLICEARR, 1728 OSLICE3, 1729 OSLICE3ARR, 1730 OSLICESTR: 1731 escwalk(e, level, dst, src.Left) 1732 1733 case OINDEX: 1734 if Isfixedarray(src.Left.Type) { 1735 escwalk(e, level, dst, src.Left) 1736 break 1737 } 1738 fallthrough 1739 1740 case ODOTPTR, OINDEXMAP, OIND: 1741 escwalk(e, level.inc(), dst, src.Left) 1742 1743 // In this case a link went directly to a call, but should really go 1744 // to the dummy .outN outputs that were created for the call that 1745 // themselves link to the inputs with levels adjusted. 1746 // See e.g. #10466 1747 // This can only happen with functions returning a single result. 1748 case OCALLMETH, OCALLFUNC, OCALLINTER: 1749 if srcE.Escretval != nil { 1750 if Debug['m'] > 1 { 1751 fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n", 1752 Ctxt.Line(int(lineno)), e.loopdepth, 1753 Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort)) 1754 } 1755 src = srcE.Escretval.N 1756 srcE = e.nodeEscState(src) 1757 } 1758 } 1759 1760 recurse: 1761 level = level.copy() 1762 for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next { 1763 escwalk(e, level, dst, ll.N) 1764 } 1765 1766 e.pdepth-- 1767 } 1768 1769 func esctag(e *EscState, func_ *Node) { 1770 func_.Esc = EscFuncTagged 1771 1772 // External functions are assumed unsafe, 1773 // unless //go:noescape is given before the declaration. 1774 if func_.Nbody == nil { 1775 if func_.Noescape { 1776 for t := getinargx(func_.Type).Type; t != nil; t = t.Down { 1777 if haspointers(t.Type) { 1778 t.Note = mktag(EscNone) 1779 } 1780 } 1781 } 1782 1783 return 1784 } 1785 1786 savefn := Curfn 1787 Curfn = func_ 1788 1789 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 1790 if ll.N.Op != ONAME { 1791 continue 1792 } 1793 1794 switch ll.N.Esc & EscMask { 1795 case EscNone, // not touched by escflood 1796 EscReturn: 1797 if haspointers(ll.N.Type) { // don't bother tagging for scalars 1798 ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc)) 1799 } 1800 1801 case EscHeap, // touched by escflood, moved to heap 1802 EscScope: // touched by escflood, value leaves scope 1803 break 1804 } 1805 } 1806 1807 Curfn = savefn 1808 }