github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/go/pointer/analysis.go (about) 1 // Copyright 2013 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 // +build go1.5 6 7 package pointer 8 9 // This file defines the main datatypes and Analyze function of the pointer analysis. 10 11 import ( 12 "fmt" 13 "go/token" 14 "go/types" 15 "io" 16 "os" 17 "reflect" 18 "runtime" 19 "runtime/debug" 20 "sort" 21 22 "golang.org/x/tools/go/callgraph" 23 "golang.org/x/tools/go/ssa" 24 "golang.org/x/tools/go/types/typeutil" 25 ) 26 27 const ( 28 // optimization options; enable all when committing 29 optRenumber = true // enable renumbering optimization (makes logs hard to read) 30 optHVN = true // enable pointer equivalence via Hash-Value Numbering 31 32 // debugging options; disable all when committing 33 debugHVN = false // enable assertions in HVN 34 debugHVNVerbose = false // enable extra HVN logging 35 debugHVNCrossCheck = false // run solver with/without HVN and compare (caveats below) 36 debugTimers = false // show running time of each phase 37 ) 38 39 // object.flags bitmask values. 40 const ( 41 otTagged = 1 << iota // type-tagged object 42 otIndirect // type-tagged object with indirect payload 43 otFunction // function object 44 ) 45 46 // An object represents a contiguous block of memory to which some 47 // (generalized) pointer may point. 48 // 49 // (Note: most variables called 'obj' are not *objects but nodeids 50 // such that a.nodes[obj].obj != nil.) 51 // 52 type object struct { 53 // flags is a bitset of the node type (ot*) flags defined above. 54 flags uint32 55 56 // Number of following nodes belonging to the same "object" 57 // allocation. Zero for all other nodes. 58 size uint32 59 60 // data describes this object; it has one of these types: 61 // 62 // ssa.Value for an object allocated by an SSA operation. 63 // types.Type for an rtype instance object or *rtype-tagged object. 64 // string for an instrinsic object, e.g. the array behind os.Args. 65 // nil for an object allocated by an instrinsic. 66 // (cgn provides the identity of the intrinsic.) 67 data interface{} 68 69 // The call-graph node (=context) in which this object was allocated. 70 // May be nil for global objects: Global, Const, some Functions. 71 cgn *cgnode 72 } 73 74 // nodeid denotes a node. 75 // It is an index within analysis.nodes. 76 // We use small integers, not *node pointers, for many reasons: 77 // - they are smaller on 64-bit systems. 78 // - sets of them can be represented compactly in bitvectors or BDDs. 79 // - order matters; a field offset can be computed by simple addition. 80 type nodeid uint32 81 82 // A node is an equivalence class of memory locations. 83 // Nodes may be pointers, pointed-to locations, neither, or both. 84 // 85 // Nodes that are pointed-to locations ("labels") have an enclosing 86 // object (see analysis.enclosingObject). 87 // 88 type node struct { 89 // If non-nil, this node is the start of an object 90 // (addressable memory location). 91 // The following obj.size nodes implicitly belong to the object; 92 // they locate their object by scanning back. 93 obj *object 94 95 // The type of the field denoted by this node. Non-aggregate, 96 // unless this is an tagged.T node (i.e. the thing 97 // pointed to by an interface) in which case typ is that type. 98 typ types.Type 99 100 // subelement indicates which directly embedded subelement of 101 // an object of aggregate type (struct, tuple, array) this is. 102 subelement *fieldInfo // e.g. ".a.b[*].c" 103 104 // Solver state for the canonical node of this pointer- 105 // equivalence class. Each node is created with its own state 106 // but they become shared after HVN. 107 solve *solverState 108 } 109 110 // An analysis instance holds the state of a single pointer analysis problem. 111 type analysis struct { 112 config *Config // the client's control/observer interface 113 prog *ssa.Program // the program being analyzed 114 log io.Writer // log stream; nil to disable 115 panicNode nodeid // sink for panic, source for recover 116 nodes []*node // indexed by nodeid 117 flattenMemo map[types.Type][]*fieldInfo // memoization of flatten() 118 trackTypes map[types.Type]bool // memoization of shouldTrack() 119 constraints []constraint // set of constraints 120 cgnodes []*cgnode // all cgnodes 121 genq []*cgnode // queue of functions to generate constraints for 122 intrinsics map[*ssa.Function]intrinsic // non-nil values are summaries for intrinsic fns 123 globalval map[ssa.Value]nodeid // node for each global ssa.Value 124 globalobj map[ssa.Value]nodeid // maps v to sole member of pts(v), if singleton 125 localval map[ssa.Value]nodeid // node for each local ssa.Value 126 localobj map[ssa.Value]nodeid // maps v to sole member of pts(v), if singleton 127 atFuncs map[*ssa.Function]bool // address-taken functions (for presolver) 128 mapValues []nodeid // values of makemap objects (indirect in HVN) 129 work nodeset // solver's worklist 130 result *Result // results of the analysis 131 track track // pointerlike types whose aliasing we track 132 deltaSpace []int // working space for iterating over PTS deltas 133 134 // Reflection & intrinsics: 135 hasher typeutil.Hasher // cache of type hashes 136 reflectValueObj types.Object // type symbol for reflect.Value (if present) 137 reflectValueCall *ssa.Function // (reflect.Value).Call 138 reflectRtypeObj types.Object // *types.TypeName for reflect.rtype (if present) 139 reflectRtypePtr *types.Pointer // *reflect.rtype 140 reflectType *types.Named // reflect.Type 141 rtypes typeutil.Map // nodeid of canonical *rtype-tagged object for type T 142 reflectZeros typeutil.Map // nodeid of canonical T-tagged object for zero value 143 runtimeSetFinalizer *ssa.Function // runtime.SetFinalizer 144 } 145 146 // enclosingObj returns the first node of the addressable memory 147 // object that encloses node id. Panic ensues if that node does not 148 // belong to any object. 149 func (a *analysis) enclosingObj(id nodeid) nodeid { 150 // Find previous node with obj != nil. 151 for i := id; i >= 0; i-- { 152 n := a.nodes[i] 153 if obj := n.obj; obj != nil { 154 if i+nodeid(obj.size) <= id { 155 break // out of bounds 156 } 157 return i 158 } 159 } 160 panic("node has no enclosing object") 161 } 162 163 // labelFor returns the Label for node id. 164 // Panic ensues if that node is not addressable. 165 func (a *analysis) labelFor(id nodeid) *Label { 166 return &Label{ 167 obj: a.nodes[a.enclosingObj(id)].obj, 168 subelement: a.nodes[id].subelement, 169 } 170 } 171 172 func (a *analysis) warnf(pos token.Pos, format string, args ...interface{}) { 173 msg := fmt.Sprintf(format, args...) 174 if a.log != nil { 175 fmt.Fprintf(a.log, "%s: warning: %s\n", a.prog.Fset.Position(pos), msg) 176 } 177 a.result.Warnings = append(a.result.Warnings, Warning{pos, msg}) 178 } 179 180 // computeTrackBits sets a.track to the necessary 'track' bits for the pointer queries. 181 func (a *analysis) computeTrackBits() { 182 var queryTypes []types.Type 183 for v := range a.config.Queries { 184 queryTypes = append(queryTypes, v.Type()) 185 } 186 for v := range a.config.IndirectQueries { 187 queryTypes = append(queryTypes, mustDeref(v.Type())) 188 } 189 for _, t := range queryTypes { 190 switch t.Underlying().(type) { 191 case *types.Chan: 192 a.track |= trackChan 193 case *types.Map: 194 a.track |= trackMap 195 case *types.Pointer: 196 a.track |= trackPtr 197 case *types.Slice: 198 a.track |= trackSlice 199 case *types.Interface: 200 a.track = trackAll 201 return 202 } 203 if rVObj := a.reflectValueObj; rVObj != nil && types.Identical(t, rVObj.Type()) { 204 a.track = trackAll 205 return 206 } 207 } 208 } 209 210 // Analyze runs the pointer analysis with the scope and options 211 // specified by config, and returns the (synthetic) root of the callgraph. 212 // 213 // Pointer analysis of a transitively closed well-typed program should 214 // always succeed. An error can occur only due to an internal bug. 215 // 216 func Analyze(config *Config) (result *Result, err error) { 217 if config.Mains == nil { 218 return nil, fmt.Errorf("no main/test packages to analyze (check $GOROOT/$GOPATH)") 219 } 220 defer func() { 221 if p := recover(); p != nil { 222 err = fmt.Errorf("internal error in pointer analysis: %v (please report this bug)", p) 223 fmt.Fprintln(os.Stderr, "Internal panic in pointer analysis:") 224 debug.PrintStack() 225 } 226 }() 227 228 a := &analysis{ 229 config: config, 230 log: config.Log, 231 prog: config.prog(), 232 globalval: make(map[ssa.Value]nodeid), 233 globalobj: make(map[ssa.Value]nodeid), 234 flattenMemo: make(map[types.Type][]*fieldInfo), 235 trackTypes: make(map[types.Type]bool), 236 atFuncs: make(map[*ssa.Function]bool), 237 hasher: typeutil.MakeHasher(), 238 intrinsics: make(map[*ssa.Function]intrinsic), 239 result: &Result{ 240 Queries: make(map[ssa.Value]Pointer), 241 IndirectQueries: make(map[ssa.Value]Pointer), 242 }, 243 deltaSpace: make([]int, 0, 100), 244 } 245 246 if false { 247 a.log = os.Stderr // for debugging crashes; extremely verbose 248 } 249 250 if a.log != nil { 251 fmt.Fprintln(a.log, "==== Starting analysis") 252 } 253 254 // Pointer analysis requires a complete program for soundness. 255 // Check to prevent accidental misconfiguration. 256 for _, pkg := range a.prog.AllPackages() { 257 // (This only checks that the package scope is complete, 258 // not that func bodies exist, but it's a good signal.) 259 if !pkg.Pkg.Complete() { 260 return nil, fmt.Errorf(`pointer analysis requires a complete program yet package %q was incomplete`, pkg.Pkg.Path()) 261 } 262 } 263 264 if reflect := a.prog.ImportedPackage("reflect"); reflect != nil { 265 rV := reflect.Pkg.Scope().Lookup("Value") 266 a.reflectValueObj = rV 267 a.reflectValueCall = a.prog.LookupMethod(rV.Type(), nil, "Call") 268 a.reflectType = reflect.Pkg.Scope().Lookup("Type").Type().(*types.Named) 269 a.reflectRtypeObj = reflect.Pkg.Scope().Lookup("rtype") 270 a.reflectRtypePtr = types.NewPointer(a.reflectRtypeObj.Type()) 271 272 // Override flattening of reflect.Value, treating it like a basic type. 273 tReflectValue := a.reflectValueObj.Type() 274 a.flattenMemo[tReflectValue] = []*fieldInfo{{typ: tReflectValue}} 275 276 // Override shouldTrack of reflect.Value and *reflect.rtype. 277 // Always track pointers of these types. 278 a.trackTypes[tReflectValue] = true 279 a.trackTypes[a.reflectRtypePtr] = true 280 281 a.rtypes.SetHasher(a.hasher) 282 a.reflectZeros.SetHasher(a.hasher) 283 } 284 if runtime := a.prog.ImportedPackage("runtime"); runtime != nil { 285 a.runtimeSetFinalizer = runtime.Func("SetFinalizer") 286 } 287 a.computeTrackBits() 288 289 a.generate() 290 a.showCounts() 291 292 if optRenumber { 293 a.renumber() 294 } 295 296 N := len(a.nodes) // excludes solver-created nodes 297 298 if optHVN { 299 if debugHVNCrossCheck { 300 // Cross-check: run the solver once without 301 // optimization, once with, and compare the 302 // solutions. 303 savedConstraints := a.constraints 304 305 a.solve() 306 a.dumpSolution("A.pts", N) 307 308 // Restore. 309 a.constraints = savedConstraints 310 for _, n := range a.nodes { 311 n.solve = new(solverState) 312 } 313 a.nodes = a.nodes[:N] 314 315 // rtypes is effectively part of the solver state. 316 a.rtypes = typeutil.Map{} 317 a.rtypes.SetHasher(a.hasher) 318 } 319 320 a.hvn() 321 } 322 323 if debugHVNCrossCheck { 324 runtime.GC() 325 runtime.GC() 326 } 327 328 a.solve() 329 330 // Compare solutions. 331 if optHVN && debugHVNCrossCheck { 332 a.dumpSolution("B.pts", N) 333 334 if !diff("A.pts", "B.pts") { 335 return nil, fmt.Errorf("internal error: optimization changed solution") 336 } 337 } 338 339 // Create callgraph.Nodes in deterministic order. 340 if cg := a.result.CallGraph; cg != nil { 341 for _, caller := range a.cgnodes { 342 cg.CreateNode(caller.fn) 343 } 344 } 345 346 // Add dynamic edges to call graph. 347 var space [100]int 348 for _, caller := range a.cgnodes { 349 for _, site := range caller.sites { 350 for _, callee := range a.nodes[site.targets].solve.pts.AppendTo(space[:0]) { 351 a.callEdge(caller, site, nodeid(callee)) 352 } 353 } 354 } 355 356 return a.result, nil 357 } 358 359 // callEdge is called for each edge in the callgraph. 360 // calleeid is the callee's object node (has otFunction flag). 361 // 362 func (a *analysis) callEdge(caller *cgnode, site *callsite, calleeid nodeid) { 363 obj := a.nodes[calleeid].obj 364 if obj.flags&otFunction == 0 { 365 panic(fmt.Sprintf("callEdge %s -> n%d: not a function object", site, calleeid)) 366 } 367 callee := obj.cgn 368 369 if cg := a.result.CallGraph; cg != nil { 370 // TODO(adonovan): opt: I would expect duplicate edges 371 // (to wrappers) to arise due to the elimination of 372 // context information, but I haven't observed any. 373 // Understand this better. 374 callgraph.AddEdge(cg.CreateNode(caller.fn), site.instr, cg.CreateNode(callee.fn)) 375 } 376 377 if a.log != nil { 378 fmt.Fprintf(a.log, "\tcall edge %s -> %s\n", site, callee) 379 } 380 381 // Warn about calls to non-intrinsic external functions. 382 // TODO(adonovan): de-dup these messages. 383 if fn := callee.fn; fn.Blocks == nil && a.findIntrinsic(fn) == nil { 384 a.warnf(site.pos(), "unsound call to unknown intrinsic: %s", fn) 385 a.warnf(fn.Pos(), " (declared here)") 386 } 387 } 388 389 // dumpSolution writes the PTS solution to the specified file. 390 // 391 // It only dumps the nodes that existed before solving. The order in 392 // which solver-created nodes are created depends on pre-solver 393 // optimization, so we can't include them in the cross-check. 394 // 395 func (a *analysis) dumpSolution(filename string, N int) { 396 f, err := os.Create(filename) 397 if err != nil { 398 panic(err) 399 } 400 for id, n := range a.nodes[:N] { 401 if _, err := fmt.Fprintf(f, "pts(n%d) = {", id); err != nil { 402 panic(err) 403 } 404 var sep string 405 for _, l := range n.solve.pts.AppendTo(a.deltaSpace) { 406 if l >= N { 407 break 408 } 409 fmt.Fprintf(f, "%s%d", sep, l) 410 sep = " " 411 } 412 fmt.Fprintf(f, "} : %s\n", n.typ) 413 } 414 if err := f.Close(); err != nil { 415 panic(err) 416 } 417 } 418 419 // showCounts logs the size of the constraint system. A typical 420 // optimized distribution is 65% copy, 13% load, 11% addr, 5% 421 // offsetAddr, 4% store, 2% others. 422 // 423 func (a *analysis) showCounts() { 424 if a.log != nil { 425 counts := make(map[reflect.Type]int) 426 for _, c := range a.constraints { 427 counts[reflect.TypeOf(c)]++ 428 } 429 fmt.Fprintf(a.log, "# constraints:\t%d\n", len(a.constraints)) 430 var lines []string 431 for t, n := range counts { 432 line := fmt.Sprintf("%7d (%2d%%)\t%s", n, 100*n/len(a.constraints), t) 433 lines = append(lines, line) 434 } 435 sort.Sort(sort.Reverse(sort.StringSlice(lines))) 436 for _, line := range lines { 437 fmt.Fprintf(a.log, "\t%s\n", line) 438 } 439 440 fmt.Fprintf(a.log, "# nodes:\t%d\n", len(a.nodes)) 441 442 // Show number of pointer equivalence classes. 443 m := make(map[*solverState]bool) 444 for _, n := range a.nodes { 445 m[n.solve] = true 446 } 447 fmt.Fprintf(a.log, "# ptsets:\t%d\n", len(m)) 448 } 449 }