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