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