github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/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 case ORANGE: 654 if n.List != nil && n.List.Next != nil { 655 // Everything but fixed array is a dereference. 656 657 // If fixed array is really the address of fixed array, 658 // it is also a dereference, because it is implicitly 659 // dereferenced (see #12588) 660 if Isfixedarray(n.Type) && 661 !(Isptr[n.Right.Type.Etype] && Eqtype(n.Right.Type.Type, n.Type)) { 662 escassign(e, n.List.Next.N, n.Right) 663 } else { 664 escassignDereference(e, n.List.Next.N, n.Right) 665 } 666 } 667 668 case OSWITCH: 669 if n.Left != nil && n.Left.Op == OTYPESW { 670 for ll := n.List; ll != nil; ll = ll.Next { 671 // cases 672 // n.Left.Right is the argument of the .(type), 673 // ll.N.Rlist is the variable per case 674 if ll.N.Rlist != nil { 675 escassign(e, ll.N.Rlist.N, n.Left.Right) 676 } 677 } 678 } 679 680 // Filter out the following special case. 681 // 682 // func (b *Buffer) Foo() { 683 // n, m := ... 684 // b.buf = b.buf[n:m] 685 // } 686 // 687 // This assignment is a no-op for escape analysis, 688 // it does not store any new pointers into b that were not already there. 689 // However, without this special case b will escape, because we assign to OIND/ODOTPTR. 690 case OAS, OASOP, OASWB: 691 if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference 692 (n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation 693 (n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference 694 n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME 695 696 // Here we also assume that the statement will not contain calls, 697 // that is, that order will move any calls to init. 698 // Otherwise base ONAME value could change between the moments 699 // when we evaluate it for dst and for src. 700 // 701 // Note, this optimization does not apply to OSLICEARR, 702 // because it does introduce a new pointer into b that was not already there 703 // (pointer to b itself). After such assignment, if b contents escape, 704 // b escapes as well. If we ignore such OSLICEARR, we will conclude 705 // that b does not escape when b contents do. 706 if Debug['m'] != 0 { 707 Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, obj.FmtShort)) 708 } 709 710 break 711 } 712 713 escassign(e, n.Left, n.Right) 714 715 case OAS2: // x,y = a,b 716 if count(n.List) == count(n.Rlist) { 717 ll := n.List 718 lr := n.Rlist 719 for ; ll != nil; ll, lr = ll.Next, lr.Next { 720 escassign(e, ll.N, lr.N) 721 } 722 } 723 724 case OAS2RECV, // v, ok = <-ch 725 OAS2MAPR, // v, ok = m[k] 726 OAS2DOTTYPE: // v, ok = x.(type) 727 escassign(e, n.List.N, n.Rlist.N) 728 729 case OSEND: // ch <- x 730 escassign(e, &e.theSink, n.Right) 731 732 case ODEFER: 733 if e.loopdepth == 1 { // top level 734 break 735 } 736 // arguments leak out of scope 737 // TODO: leak to a dummy node instead 738 fallthrough 739 740 case OPROC: 741 // go f(x) - f and x escape 742 escassign(e, &e.theSink, n.Left.Left) 743 744 escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call 745 for ll := n.Left.List; ll != nil; ll = ll.Next { 746 escassign(e, &e.theSink, ll.N) 747 } 748 749 case OCALLMETH, OCALLFUNC, OCALLINTER: 750 esccall(e, n, up) 751 752 // esccall already done on n->rlist->n. tie it's escretval to n->list 753 case OAS2FUNC: // x,y = f() 754 lr := e.nodeEscState(n.Rlist.N).Escretval 755 756 var ll *NodeList 757 for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next { 758 escassign(e, ll.N, lr.N) 759 } 760 if lr != nil || ll != nil { 761 Fatalf("esc oas2func") 762 } 763 764 case ORETURN: 765 ll := n.List 766 if count(n.List) == 1 && Curfn.Type.Outtuple > 1 { 767 // OAS2FUNC in disguise 768 // esccall already done on n->list->n 769 // tie n->list->n->escretval to curfn->dcl PPARAMOUT's 770 ll = e.nodeEscState(n.List.N).Escretval 771 } 772 773 for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next { 774 if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT { 775 continue 776 } 777 escassign(e, lr.N, ll.N) 778 ll = ll.Next 779 } 780 781 if ll != nil { 782 Fatalf("esc return list") 783 } 784 785 // Argument could leak through recover. 786 case OPANIC: 787 escassign(e, &e.theSink, n.Left) 788 789 case OAPPEND: 790 if !n.Isddd { 791 for ll := n.List.Next; ll != nil; ll = ll.Next { 792 escassign(e, &e.theSink, ll.N) // lose track of assign to dereference 793 } 794 } else { 795 // append(slice1, slice2...) -- slice2 itself does not escape, but contents do. 796 slice2 := n.List.Next.N 797 escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference 798 if Debug['m'] > 2 { 799 Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort)) 800 } 801 } 802 escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too 803 804 case OCOPY: 805 escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference 806 807 case OCONV, OCONVNOP: 808 escassign(e, n, n.Left) 809 810 case OCONVIFACE: 811 e.track(n) 812 escassign(e, n, n.Left) 813 814 case OARRAYLIT: 815 if Isslice(n.Type) { 816 // Slice itself is not leaked until proven otherwise 817 e.track(n) 818 } 819 820 // Link values to array/slice 821 for ll := n.List; ll != nil; ll = ll.Next { 822 escassign(e, n, ll.N.Right) 823 } 824 825 // Link values to struct. 826 case OSTRUCTLIT: 827 for ll := n.List; ll != nil; ll = ll.Next { 828 escassign(e, n, ll.N.Right) 829 } 830 831 case OPTRLIT: 832 e.track(n) 833 834 // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. 835 escassign(e, n, n.Left) 836 837 case OCALLPART: 838 e.track(n) 839 840 // Contents make it to memory, lose track. 841 escassign(e, &e.theSink, n.Left) 842 843 case OMAPLIT: 844 e.track(n) 845 846 // Keys and values make it to memory, lose track. 847 for ll := n.List; ll != nil; ll = ll.Next { 848 escassign(e, &e.theSink, ll.N.Left) 849 escassign(e, &e.theSink, ll.N.Right) 850 } 851 852 // Link addresses of captured variables to closure. 853 case OCLOSURE: 854 var a *Node 855 var v *Node 856 for ll := n.Func.Cvars; ll != nil; ll = ll.Next { 857 v = ll.N 858 if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs 859 continue 860 } 861 a = v.Name.Param.Closure 862 if !v.Name.Byval { 863 a = Nod(OADDR, a, nil) 864 a.Lineno = v.Lineno 865 e.nodeEscState(a).Escloopdepth = e.loopdepth 866 typecheck(&a, Erv) 867 } 868 869 escassign(e, n, a) 870 } 871 fallthrough 872 873 case OMAKECHAN, 874 OMAKEMAP, 875 OMAKESLICE, 876 ONEW, 877 OARRAYRUNESTR, 878 OARRAYBYTESTR, 879 OSTRARRAYRUNE, 880 OSTRARRAYBYTE, 881 ORUNESTR: 882 e.track(n) 883 884 case OADDSTR: 885 e.track(n) 886 // Arguments of OADDSTR do not escape. 887 888 case OADDR: 889 // current loop depth is an upper bound on actual loop depth 890 // of addressed value. 891 e.track(n) 892 893 // for &x, use loop depth of x if known. 894 // it should always be known, but if not, be conservative 895 // and keep the current loop depth. 896 if n.Left.Op == ONAME { 897 switch n.Left.Class { 898 case PAUTO: 899 nE := e.nodeEscState(n) 900 leftE := e.nodeEscState(n.Left) 901 if leftE.Escloopdepth != 0 { 902 nE.Escloopdepth = leftE.Escloopdepth 903 } 904 905 // PPARAM is loop depth 1 always. 906 // PPARAMOUT is loop depth 0 for writes 907 // but considered loop depth 1 for address-of, 908 // so that writing the address of one result 909 // to another (or the same) result makes the 910 // first result move to the heap. 911 case PPARAM, PPARAMOUT: 912 nE := e.nodeEscState(n) 913 nE.Escloopdepth = 1 914 } 915 } 916 } 917 918 lineno = int32(lno) 919 } 920 921 // Assert that expr somehow gets assigned to dst, if non nil. for 922 // dst==nil, any name node expr still must be marked as being 923 // evaluated in curfn. For expr==nil, dst must still be examined for 924 // evaluations inside it (e.g *f(x) = y) 925 func escassign(e *EscState, dst *Node, src *Node) { 926 if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX { 927 return 928 } 929 930 if Debug['m'] > 1 { 931 fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n", 932 Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), 933 Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0), 934 Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0)) 935 } 936 937 setlineno(dst) 938 939 // Analyze lhs of assignment. 940 // Replace dst with e->theSink if we can't track it. 941 switch dst.Op { 942 default: 943 Dump("dst", dst) 944 Fatalf("escassign: unexpected dst") 945 946 case OARRAYLIT, 947 OCLOSURE, 948 OCONV, 949 OCONVIFACE, 950 OCONVNOP, 951 OMAPLIT, 952 OSTRUCTLIT, 953 OPTRLIT, 954 ODDDARG, 955 OCALLPART: 956 break 957 958 case ONAME: 959 if dst.Class == PEXTERN { 960 dst = &e.theSink 961 } 962 963 case ODOT: // treat "dst.x = src" as "dst = src" 964 escassign(e, dst.Left, src) 965 966 return 967 968 case OINDEX: 969 if Isfixedarray(dst.Left.Type) { 970 escassign(e, dst.Left, src) 971 return 972 } 973 974 dst = &e.theSink // lose track of dereference 975 976 case OIND, ODOTPTR: 977 dst = &e.theSink // lose track of dereference 978 979 // lose track of key and value 980 case OINDEXMAP: 981 escassign(e, &e.theSink, dst.Right) 982 983 dst = &e.theSink 984 } 985 986 lno := int(setlineno(src)) 987 e.pdepth++ 988 989 switch src.Op { 990 case OADDR, // dst = &x 991 OIND, // dst = *x 992 ODOTPTR, // dst = (*x).f 993 ONAME, 994 OPARAM, 995 ODDDARG, 996 OPTRLIT, 997 OARRAYLIT, 998 OMAPLIT, 999 OSTRUCTLIT, 1000 OMAKECHAN, 1001 OMAKEMAP, 1002 OMAKESLICE, 1003 OARRAYRUNESTR, 1004 OARRAYBYTESTR, 1005 OSTRARRAYRUNE, 1006 OSTRARRAYBYTE, 1007 OADDSTR, 1008 ONEW, 1009 OCALLPART, 1010 ORUNESTR, 1011 OCONVIFACE: 1012 escflows(e, dst, src) 1013 1014 case OCLOSURE: 1015 // OCLOSURE is lowered to OPTRLIT, 1016 // insert OADDR to account for the additional indirection. 1017 a := Nod(OADDR, src, nil) 1018 a.Lineno = src.Lineno 1019 e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth 1020 a.Type = Ptrto(src.Type) 1021 escflows(e, dst, a) 1022 1023 // Flowing multiple returns to a single dst happens when 1024 // analyzing "go f(g())": here g() flows to sink (issue 4529). 1025 case OCALLMETH, OCALLFUNC, OCALLINTER: 1026 for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next { 1027 escflows(e, dst, ll.N) 1028 } 1029 1030 // A non-pointer escaping from a struct does not concern us. 1031 case ODOT: 1032 if src.Type != nil && !haspointers(src.Type) { 1033 break 1034 } 1035 fallthrough 1036 1037 // Conversions, field access, slice all preserve the input value. 1038 case OCONV, 1039 OCONVNOP, 1040 ODOTMETH, 1041 // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC 1042 // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here 1043 ODOTTYPE, 1044 ODOTTYPE2, 1045 OSLICE, 1046 OSLICE3, 1047 OSLICEARR, 1048 OSLICE3ARR, 1049 OSLICESTR: 1050 // Conversions, field access, slice all preserve the input value. 1051 escassign(e, dst, src.Left) 1052 1053 case OAPPEND: 1054 // Append returns first argument. 1055 // Subsequent arguments are already leaked because they are operands to append. 1056 escassign(e, dst, src.List.N) 1057 1058 case OINDEX: 1059 // Index of array preserves input value. 1060 if Isfixedarray(src.Left.Type) { 1061 escassign(e, dst, src.Left) 1062 } else { 1063 escflows(e, dst, src) 1064 } 1065 1066 // Might be pointer arithmetic, in which case 1067 // the operands flow into the result. 1068 // TODO(rsc): Decide what the story is here. This is unsettling. 1069 case OADD, 1070 OSUB, 1071 OOR, 1072 OXOR, 1073 OMUL, 1074 ODIV, 1075 OMOD, 1076 OLSH, 1077 ORSH, 1078 OAND, 1079 OANDNOT, 1080 OPLUS, 1081 OMINUS, 1082 OCOM: 1083 escassign(e, dst, src.Left) 1084 1085 escassign(e, dst, src.Right) 1086 } 1087 1088 e.pdepth-- 1089 lineno = int32(lno) 1090 } 1091 1092 // Common case for escapes is 16 bits 000000000xxxEEEE 1093 // where commonest cases for xxx encoding in-to-out pointer 1094 // flow are 000, 001, 010, 011 and EEEE is computed Esc bits. 1095 // Note width of xxx depends on value of constant 1096 // bitsPerOutputInTag -- expect 2 or 3, so in practice the 1097 // tag cache array is 64 or 128 long. Some entries will 1098 // never be populated. 1099 var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string 1100 1101 // mktag returns the string representation for an escape analysis tag. 1102 func mktag(mask int) *string { 1103 switch mask & EscMask { 1104 case EscNone, EscReturn: 1105 break 1106 1107 default: 1108 Fatalf("escape mktag") 1109 } 1110 1111 if mask < len(tags) && tags[mask] != "" { 1112 return &tags[mask] 1113 } 1114 1115 s := fmt.Sprintf("esc:0x%x", mask) 1116 if mask < len(tags) { 1117 tags[mask] = s 1118 } 1119 return &s 1120 } 1121 1122 // parsetag decodes an escape analysis tag and returns the esc value. 1123 func parsetag(note *string) uint16 { 1124 if note == nil || !strings.HasPrefix(*note, "esc:") { 1125 return EscUnknown 1126 } 1127 em := uint16(atoi((*note)[4:])) 1128 if em == 0 { 1129 return EscNone 1130 } 1131 return em 1132 } 1133 1134 // describeEscape returns a string describing the escape tag. 1135 // The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation 1136 // or a description of parameter flow, which takes the form of an optional "contentToHeap" 1137 // indicating that the content of this parameter is leaked to the heap, followed by a sequence 1138 // of level encodings separated by spaces, one for each parameter, where _ means no flow, 1139 // = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow. 1140 // e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences) 1141 // escapes to the heap, the parameter does not leak to the first output, but does leak directly 1142 // to the second output (and if there are more than two outputs, there is no flow to those.) 1143 func describeEscape(em uint16) string { 1144 var s string 1145 if em&EscMask == EscUnknown { 1146 s = "EscUnknown" 1147 } 1148 if em&EscMask == EscNone { 1149 s = "EscNone" 1150 } 1151 if em&EscMask == EscHeap { 1152 s = "EscHeap" 1153 } 1154 if em&EscMask == EscReturn { 1155 s = "EscReturn" 1156 } 1157 if em&EscMask == EscScope { 1158 s = "EscScope" 1159 } 1160 if em&EscContentEscapes != 0 { 1161 if s != "" { 1162 s += " " 1163 } 1164 s += "contentToHeap" 1165 } 1166 for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag { 1167 // See encoding description above 1168 if s != "" { 1169 s += " " 1170 } 1171 switch embits := em & bitsMaskForTag; embits { 1172 case 0: 1173 s += "_" 1174 case 1: 1175 s += "=" 1176 default: 1177 for i := uint16(0); i < embits-1; i++ { 1178 s += "*" 1179 } 1180 } 1181 1182 } 1183 return s 1184 } 1185 1186 // escassignfromtag models the input-to-output assignment flow of one of a function 1187 // calls arguments, where the flow is encoded in "note". 1188 func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 { 1189 em := parsetag(note) 1190 if src.Op == OLITERAL { 1191 return em 1192 } 1193 1194 if Debug['m'] > 2 { 1195 fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n", 1196 Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em)) 1197 } 1198 1199 if em == EscUnknown { 1200 escassign(e, &e.theSink, src) 1201 return em 1202 } 1203 1204 if em == EscNone { 1205 return em 1206 } 1207 1208 // If content inside parameter (reached via indirection) 1209 // escapes to heap, mark as such. 1210 if em&EscContentEscapes != 0 { 1211 escassign(e, &e.theSink, e.addDereference(src)) 1212 } 1213 1214 em0 := em 1215 for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next { 1216 // Prefer the lowest-level path to the reference (for escape purposes). 1217 // Two-bit encoding (for example. 1, 3, and 4 bits are other options) 1218 // 01 = 0-level 1219 // 10 = 1-level, (content escapes), 1220 // 11 = 2-level, (content of content escapes), 1221 embits := em & bitsMaskForTag 1222 if embits > 0 { 1223 n := src 1224 for i := uint16(0); i < embits-1; i++ { 1225 n = e.addDereference(n) // encode level>0 as indirections 1226 } 1227 escassign(e, dsts.N, n) 1228 } 1229 } 1230 // If there are too many outputs to fit in the tag, 1231 // that is handled at the encoding end as EscHeap, 1232 // so there is no need to check here. 1233 1234 if em != 0 && dsts == nil { 1235 Fatalf("corrupt esc tag %q or messed up escretval list\n", note) 1236 } 1237 return em0 1238 } 1239 1240 func escassignDereference(e *EscState, dst *Node, src *Node) { 1241 if src.Op == OLITERAL { 1242 return 1243 } 1244 escassign(e, dst, e.addDereference(src)) 1245 } 1246 1247 // addDereference constructs a suitable OIND note applied to src. 1248 // Because this is for purposes of escape accounting, not execution, 1249 // some semantically dubious node combinations are (currently) possible. 1250 func (e *EscState) addDereference(n *Node) *Node { 1251 ind := Nod(OIND, n, nil) 1252 e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth 1253 ind.Lineno = n.Lineno 1254 t := n.Type 1255 if Istype(t, Tptr) { 1256 // This should model our own sloppy use of OIND to encode 1257 // decreasing levels of indirection; i.e., "indirecting" an array 1258 // might yield the type of an element. To be enhanced... 1259 t = t.Type 1260 } 1261 ind.Type = t 1262 return ind 1263 } 1264 1265 // escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter. 1266 // Levels greater than maxEncodedLevel are replaced with maxEncodedLevel. 1267 // If the encoding cannot describe the modified input level and output number, then EscHeap is returned. 1268 func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 { 1269 // Flow+level is encoded in two bits. 1270 // 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel 1271 // 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful. 1272 if level.int() <= 0 && level.guaranteedDereference() > 0 { 1273 return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content. 1274 } 1275 if level.int() < 0 { 1276 return EscHeap 1277 } 1278 if level.int() > maxEncodedLevel { 1279 // Cannot encode larger values than maxEncodedLevel. 1280 level = levelFrom(maxEncodedLevel) 1281 } 1282 encoded := uint16(level.int() + 1) 1283 1284 shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits) 1285 old := (e >> shift) & bitsMaskForTag 1286 if old == 0 || encoded != 0 && encoded < old { 1287 old = encoded 1288 } 1289 1290 encodedFlow := old << shift 1291 if (encodedFlow>>shift)&bitsMaskForTag != old { 1292 // Encoding failure defaults to heap. 1293 return EscHeap 1294 } 1295 1296 return (e &^ (bitsMaskForTag << shift)) | encodedFlow 1297 } 1298 1299 func initEscretval(e *EscState, n *Node, fntype *Type) { 1300 i := 0 1301 nE := e.nodeEscState(n) 1302 nE.Escretval = nil // Suspect this is not nil for indirect calls. 1303 for t := getoutargx(fntype).Type; t != nil; t = t.Down { 1304 src := Nod(ONAME, nil, nil) 1305 buf := fmt.Sprintf(".out%d", i) 1306 i++ 1307 src.Sym = Lookup(buf) 1308 src.Type = t.Type 1309 src.Class = PAUTO 1310 src.Name.Curfn = Curfn 1311 e.nodeEscState(src).Escloopdepth = e.loopdepth 1312 src.Used = true 1313 src.Lineno = n.Lineno 1314 nE.Escretval = list(nE.Escretval, src) 1315 } 1316 } 1317 1318 // This is a bit messier than fortunate, pulled out of esc's big 1319 // switch for clarity. We either have the paramnodes, which may be 1320 // connected to other things through flows or we have the parameter type 1321 // nodes, which may be marked "noescape". Navigating the ast is slightly 1322 // different for methods vs plain functions and for imported vs 1323 // this-package 1324 func esccall(e *EscState, n *Node, up *Node) { 1325 var fntype *Type 1326 var indirect bool 1327 var fn *Node 1328 switch n.Op { 1329 default: 1330 Fatalf("esccall") 1331 1332 case OCALLFUNC: 1333 fn = n.Left 1334 fntype = fn.Type 1335 indirect = fn.Op != ONAME || fn.Class != PFUNC 1336 1337 case OCALLMETH: 1338 fn = n.Left.Right.Sym.Def 1339 if fn != nil { 1340 fntype = fn.Type 1341 } else { 1342 fntype = n.Left.Type 1343 } 1344 1345 case OCALLINTER: 1346 fntype = n.Left.Type 1347 indirect = true 1348 } 1349 1350 ll := n.List 1351 if n.List != nil && n.List.Next == nil { 1352 a := n.List.N 1353 if a.Type.Etype == TSTRUCT && a.Type.Funarg { // f(g()). 1354 ll = e.nodeEscState(a).Escretval 1355 } 1356 } 1357 1358 if indirect { 1359 // We know nothing! 1360 // Leak all the parameters 1361 for ; ll != nil; ll = ll.Next { 1362 escassign(e, &e.theSink, ll.N) 1363 if Debug['m'] > 2 { 1364 fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1365 } 1366 } 1367 // Set up bogus outputs 1368 initEscretval(e, n, fntype) 1369 // If there is a receiver, it also leaks to heap. 1370 if n.Op != OCALLFUNC { 1371 t := getthisx(fntype).Type 1372 src := n.Left.Left 1373 if haspointers(t.Type) { 1374 escassign(e, &e.theSink, src) 1375 } 1376 } 1377 return 1378 } 1379 1380 nE := e.nodeEscState(n) 1381 if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && 1382 fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged { 1383 if Debug['m'] > 2 { 1384 fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) 1385 } 1386 1387 // function in same mutually recursive group. Incorporate into flow graph. 1388 // print("esc local fn: %N\n", fn->ntype); 1389 if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil { 1390 Fatalf("graph inconsistency") 1391 } 1392 1393 // set up out list on this call node 1394 for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next { 1395 nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT) 1396 } 1397 1398 // Receiver. 1399 if n.Op != OCALLFUNC { 1400 escassign(e, fn.Name.Param.Ntype.Left.Left, n.Left.Left) 1401 } 1402 1403 var src *Node 1404 for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next { 1405 src = ll.N 1406 if lr.N.Isddd && !n.Isddd { 1407 // Introduce ODDDARG node to represent ... allocation. 1408 src = Nod(ODDDARG, nil, nil) 1409 src.Type = typ(TARRAY) 1410 src.Type.Type = lr.N.Type.Type 1411 src.Type.Bound = int64(count(ll)) 1412 src.Type = Ptrto(src.Type) // make pointer so it will be tracked 1413 src.Lineno = n.Lineno 1414 e.track(src) 1415 n.Right = src 1416 } 1417 1418 if lr.N.Left != nil { 1419 escassign(e, lr.N.Left, src) 1420 } 1421 if src != ll.N { 1422 break 1423 } 1424 } 1425 1426 // "..." arguments are untracked 1427 for ; ll != nil; ll = ll.Next { 1428 if Debug['m'] > 2 { 1429 fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1430 } 1431 escassign(e, &e.theSink, ll.N) 1432 } 1433 1434 return 1435 } 1436 1437 // Imported or completely analyzed function. Use the escape tags. 1438 if nE.Escretval != nil { 1439 Fatalf("esc already decorated call %v\n", Nconv(n, obj.FmtSign)) 1440 } 1441 1442 if Debug['m'] > 2 { 1443 fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort)) 1444 } 1445 1446 // set up out list on this call node with dummy auto ONAMES in the current (calling) function. 1447 initEscretval(e, n, fntype) 1448 1449 // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); 1450 1451 // Receiver. 1452 if n.Op != OCALLFUNC { 1453 t := getthisx(fntype).Type 1454 src := n.Left.Left 1455 if haspointers(t.Type) { 1456 escassignfromtag(e, t.Note, nE.Escretval, src) 1457 } 1458 } 1459 1460 var src *Node 1461 for t := getinargx(fntype).Type; ll != nil; ll = ll.Next { 1462 src = ll.N 1463 if t.Isddd && !n.Isddd { 1464 // Introduce ODDDARG node to represent ... allocation. 1465 src = Nod(ODDDARG, nil, nil) 1466 src.Lineno = n.Lineno 1467 src.Type = typ(TARRAY) 1468 src.Type.Type = t.Type.Type 1469 src.Type.Bound = int64(count(ll)) 1470 src.Type = Ptrto(src.Type) // make pointer so it will be tracked 1471 e.track(src) 1472 n.Right = src 1473 } 1474 1475 if haspointers(t.Type) { 1476 if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC { 1477 a := src 1478 for a.Op == OCONVNOP { 1479 a = a.Left 1480 } 1481 switch a.Op { 1482 // The callee has already been analyzed, so its arguments have esc tags. 1483 // The argument is marked as not escaping at all. 1484 // Record that fact so that any temporary used for 1485 // synthesizing this expression can be reclaimed when 1486 // the function returns. 1487 // This 'noescape' is even stronger than the usual esc == EscNone. 1488 // src->esc == EscNone means that src does not escape the current function. 1489 // src->noescape = 1 here means that src does not escape this statement 1490 // in the current function. 1491 case OCALLPART, 1492 OCLOSURE, 1493 ODDDARG, 1494 OARRAYLIT, 1495 OPTRLIT, 1496 OSTRUCTLIT: 1497 a.Noescape = true 1498 } 1499 } 1500 } 1501 1502 if src != ll.N { 1503 // This occurs when function parameter type Isddd and n not Isddd 1504 break 1505 } 1506 t = t.Down 1507 } 1508 1509 for ; ll != nil; ll = ll.Next { 1510 if Debug['m'] > 2 { 1511 fmt.Printf("%v::esccall:: ... <- %v\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort)) 1512 } 1513 escassign(e, src, ll.N) // args to slice 1514 } 1515 } 1516 1517 // escflows records the link src->dst in dst, throwing out some quick wins, 1518 // and also ensuring that dst is noted as a flow destination. 1519 func escflows(e *EscState, dst *Node, src *Node) { 1520 if dst == nil || src == nil || dst == src { 1521 return 1522 } 1523 1524 // Don't bother building a graph for scalars. 1525 if src.Type != nil && !haspointers(src.Type) { 1526 return 1527 } 1528 1529 if Debug['m'] > 2 { 1530 fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort)) 1531 } 1532 1533 dstE := e.nodeEscState(dst) 1534 if dstE.Escflowsrc == nil { 1535 e.dsts = list(e.dsts, dst) 1536 e.dstcount++ 1537 } 1538 1539 e.edgecount++ 1540 1541 dstE.Escflowsrc = list(dstE.Escflowsrc, src) 1542 } 1543 1544 // Whenever we hit a reference node, the level goes up by one, and whenever 1545 // we hit an OADDR, the level goes down by one. as long as we're on a level > 0 1546 // finding an OADDR just means we're following the upstream of a dereference, 1547 // so this address doesn't leak (yet). 1548 // If level == 0, it means the /value/ of this node can reach the root of this flood. 1549 // so if this node is an OADDR, it's argument should be marked as escaping iff 1550 // it's currfn/e->loopdepth are different from the flood's root. 1551 // Once an object has been moved to the heap, all of it's upstream should be considered 1552 // escaping to the global scope. 1553 func escflood(e *EscState, dst *Node) { 1554 switch dst.Op { 1555 case ONAME, OCLOSURE: 1556 break 1557 1558 default: 1559 return 1560 } 1561 1562 dstE := e.nodeEscState(dst) 1563 if Debug['m'] > 1 { 1564 fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth) 1565 } 1566 1567 for l := dstE.Escflowsrc; l != nil; l = l.Next { 1568 e.walkgen++ 1569 escwalk(e, levelFrom(0), dst, l.N) 1570 } 1571 } 1572 1573 // funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function. 1574 func funcOutputAndInput(dst, src *Node) bool { 1575 // Note if dst is marked as escaping, then "returned" is too weak. 1576 return dst.Op == ONAME && dst.Class == PPARAMOUT && 1577 src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn 1578 } 1579 1580 func escwalk(e *EscState, level Level, dst *Node, src *Node) { 1581 if src.Op == OLITERAL { 1582 return 1583 } 1584 srcE := e.nodeEscState(src) 1585 if srcE.Walkgen == e.walkgen { 1586 // Esclevels are vectors, do not compare as integers, 1587 // and must use "min" of old and new to guarantee 1588 // convergence. 1589 level = level.min(srcE.Esclevel) 1590 if level == srcE.Esclevel { 1591 return 1592 } 1593 } 1594 1595 srcE.Walkgen = e.walkgen 1596 srcE.Esclevel = level 1597 1598 if Debug['m'] > 1 { 1599 fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n", 1600 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) 1601 } 1602 1603 e.pdepth++ 1604 1605 // Input parameter flowing to output parameter? 1606 var leaks bool 1607 dstE := e.nodeEscState(dst) 1608 if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap { 1609 // This case handles: 1610 // 1. return in 1611 // 2. return &in 1612 // 3. tmp := in; return &tmp 1613 // 4. return *in 1614 if Debug['m'] != 0 { 1615 if Debug['m'] == 1 { 1616 Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int()) 1617 } else { 1618 Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level) 1619 } 1620 } 1621 if src.Esc&EscMask != EscReturn { 1622 src.Esc = EscReturn | src.Esc&EscContentEscapes 1623 } 1624 src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level) 1625 goto recurse 1626 } 1627 1628 // If parameter content escapes to heap, set EscContentEscapes 1629 // Note minor confusion around escape from pointer-to-struct vs escape from struct 1630 if dst.Esc == EscHeap && 1631 src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope && 1632 level.int() > 0 { 1633 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1634 if Debug['m'] != 0 { 1635 Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort)) 1636 } 1637 } 1638 1639 leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < srcE.Escloopdepth 1640 1641 switch src.Op { 1642 case ONAME: 1643 if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope { 1644 if level.guaranteedDereference() > 0 { 1645 src.Esc = escMax(EscContentEscapes|src.Esc, EscNone) 1646 if Debug['m'] != 0 { 1647 if Debug['m'] == 1 { 1648 Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort)) 1649 } else { 1650 Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v", 1651 Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort)) 1652 } 1653 } 1654 } else { 1655 src.Esc = EscScope 1656 if Debug['m'] != 0 { 1657 if Debug['m'] == 1 { 1658 Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort)) 1659 } else { 1660 Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v", 1661 Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort)) 1662 } 1663 } 1664 } 1665 } 1666 1667 // Treat a PPARAMREF closure variable as equivalent to the 1668 // original variable. 1669 if src.Class == PPARAMREF { 1670 if leaks && Debug['m'] != 0 { 1671 Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort)) 1672 } 1673 escwalk(e, level, dst, src.Name.Param.Closure) 1674 } 1675 1676 case OPTRLIT, OADDR: 1677 if leaks { 1678 src.Esc = EscHeap 1679 addrescapes(src.Left) 1680 if Debug['m'] != 0 { 1681 p := src 1682 if p.Left.Op == OCLOSURE { 1683 p = p.Left // merely to satisfy error messages in tests 1684 } 1685 if Debug['m'] > 1 { 1686 Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v", 1687 Nconv(p, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth) 1688 } else { 1689 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort)) 1690 } 1691 } 1692 } 1693 1694 escwalk(e, level.dec(), dst, src.Left) 1695 1696 case OAPPEND: 1697 escwalk(e, level, dst, src.List.N) 1698 1699 case ODDDARG: 1700 if leaks { 1701 src.Esc = EscHeap 1702 if Debug['m'] != 0 { 1703 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort)) 1704 } 1705 } 1706 // similar to a slice arraylit and its args. 1707 level = level.dec() 1708 1709 case OARRAYLIT: 1710 if Isfixedarray(src.Type) { 1711 break 1712 } 1713 for ll := src.List; ll != nil; ll = ll.Next { 1714 escwalk(e, level.dec(), dst, ll.N.Right) 1715 } 1716 1717 fallthrough 1718 1719 case OMAKECHAN, 1720 OMAKEMAP, 1721 OMAKESLICE, 1722 OARRAYRUNESTR, 1723 OARRAYBYTESTR, 1724 OSTRARRAYRUNE, 1725 OSTRARRAYBYTE, 1726 OADDSTR, 1727 OMAPLIT, 1728 ONEW, 1729 OCLOSURE, 1730 OCALLPART, 1731 ORUNESTR, 1732 OCONVIFACE: 1733 if leaks { 1734 src.Esc = EscHeap 1735 if Debug['m'] != 0 { 1736 Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort)) 1737 } 1738 } 1739 1740 case ODOT, 1741 ODOTTYPE, 1742 OSLICE, 1743 OSLICEARR, 1744 OSLICE3, 1745 OSLICE3ARR, 1746 OSLICESTR: 1747 escwalk(e, level, dst, src.Left) 1748 1749 case OINDEX: 1750 if Isfixedarray(src.Left.Type) { 1751 escwalk(e, level, dst, src.Left) 1752 break 1753 } 1754 fallthrough 1755 1756 case ODOTPTR, OINDEXMAP, OIND: 1757 escwalk(e, level.inc(), dst, src.Left) 1758 1759 // In this case a link went directly to a call, but should really go 1760 // to the dummy .outN outputs that were created for the call that 1761 // themselves link to the inputs with levels adjusted. 1762 // See e.g. #10466 1763 // This can only happen with functions returning a single result. 1764 case OCALLMETH, OCALLFUNC, OCALLINTER: 1765 if srcE.Escretval != nil { 1766 if Debug['m'] > 1 { 1767 fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n", 1768 Ctxt.Line(int(lineno)), e.loopdepth, 1769 Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort)) 1770 } 1771 src = srcE.Escretval.N 1772 srcE = e.nodeEscState(src) 1773 } 1774 } 1775 1776 recurse: 1777 level = level.copy() 1778 for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next { 1779 escwalk(e, level, dst, ll.N) 1780 } 1781 1782 e.pdepth-- 1783 } 1784 1785 func esctag(e *EscState, func_ *Node) { 1786 func_.Esc = EscFuncTagged 1787 1788 // External functions are assumed unsafe, 1789 // unless //go:noescape is given before the declaration. 1790 if func_.Nbody == nil { 1791 if func_.Noescape { 1792 for t := getinargx(func_.Type).Type; t != nil; t = t.Down { 1793 if haspointers(t.Type) { 1794 t.Note = mktag(EscNone) 1795 } 1796 } 1797 } 1798 1799 return 1800 } 1801 1802 savefn := Curfn 1803 Curfn = func_ 1804 1805 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 1806 if ll.N.Op != ONAME { 1807 continue 1808 } 1809 1810 switch ll.N.Esc & EscMask { 1811 case EscNone, // not touched by escflood 1812 EscReturn: 1813 if haspointers(ll.N.Type) { // don't bother tagging for scalars 1814 ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc)) 1815 } 1816 1817 case EscHeap, // touched by escflood, moved to heap 1818 EscScope: // touched by escflood, value leaves scope 1819 break 1820 } 1821 } 1822 1823 Curfn = savefn 1824 }