GoPLS Viewer

Home|gopls/go/pointer/doc.go
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/*
6Package pointer implements Andersen's analysis, an inclusion-based
7pointer analysis algorithm first described in (Andersen, 1994).
8
9A pointer analysis relates every pointer expression in a whole program
10to the set of memory locations to which it might point.  This
11information can be used to construct a call graph of the program that
12precisely represents the destinations of dynamic function and method
13calls.  It can also be used to determine, for example, which pairs of
14channel operations operate on the same channel.
15
16The package allows the client to request a set of expressions of
17interest for which the points-to information will be returned once the
18analysis is complete.  In addition, the client may request that a
19callgraph is constructed.  The example program in example_test.go
20demonstrates both of these features.  Clients should not request more
21information than they need since it may increase the cost of the
22analysis significantly.
23
24# CLASSIFICATION
25
26Our algorithm is INCLUSION-BASED: the points-to sets for x and y will
27be related by pts(y) ⊇ pts(x) if the program contains the statement
28y = x.
29
30It is FLOW-INSENSITIVE: it ignores all control flow constructs and the
31order of statements in a program.  It is therefore a "MAY ALIAS"
32analysis: its facts are of the form "P may/may not point to L",
33not "P must point to L".
34
35It is FIELD-SENSITIVE: it builds separate points-to sets for distinct
36fields, such as x and y in struct { x, y *int }.
37
38It is mostly CONTEXT-INSENSITIVE: most functions are analyzed once,
39so values can flow in at one call to the function and return out at
40another.  Only some smaller functions are analyzed with consideration
41of their calling context.
42
43It has a CONTEXT-SENSITIVE HEAP: objects are named by both allocation
44site and context, so the objects returned by two distinct calls to f:
45
46    func f() *T { return new(T) }
47
48are distinguished up to the limits of the calling context.
49
50It is a WHOLE PROGRAM analysis: it requires SSA-form IR for the
51complete Go program and summaries for native code.
52
53See the (Hind, PASTE'01) survey paper for an explanation of these terms.
54
55# SOUNDNESS
56
57The analysis is fully sound when invoked on pure Go programs that do not
58use reflection or unsafe.Pointer conversions.  In other words, if there
59is any possible execution of the program in which pointer P may point to
60object O, the analysis will report that fact.
61
62# REFLECTION
63
64By default, the "reflect" library is ignored by the analysis, as if all
65its functions were no-ops, but if the client enables the Reflection flag,
66the analysis will make a reasonable attempt to model the effects of
67calls into this library.  However, this comes at a significant
68performance cost, and not all features of that library are yet
69implemented.  In addition, some simplifying approximations must be made
70to ensure that the analysis terminates; for example, reflection can be
71used to construct an infinite set of types and values of those types,
72but the analysis arbitrarily bounds the depth of such types.
73
74Most but not all reflection operations are supported.
75In particular, addressable reflect.Values are not yet implemented, so
76operations such as (reflect.Value).Set have no analytic effect.
77
78# UNSAFE POINTER CONVERSIONS
79
80The pointer analysis makes no attempt to understand aliasing between the
81operand x and result y of an unsafe.Pointer conversion:
82
83    y = (*T)(unsafe.Pointer(x))
84
85It is as if the conversion allocated an entirely new object:
86
87    y = new(T)
88
89# NATIVE CODE
90
91The analysis cannot model the aliasing effects of functions written in
92languages other than Go, such as runtime intrinsics in C or assembly, or
93code accessed via cgo.  The result is as if such functions are no-ops.
94However, various important intrinsics are understood by the analysis,
95along with built-ins such as append.
96
97The analysis currently provides no way for users to specify the aliasing
98effects of native code.
99
100------------------------------------------------------------------------
101
102# IMPLEMENTATION
103
104The remaining documentation is intended for package maintainers and
105pointer analysis specialists.  Maintainers should have a solid
106understanding of the referenced papers (especially those by H&L and PKH)
107before making making significant changes.
108
109The implementation is similar to that described in (Pearce et al,
110PASTE'04).  Unlike many algorithms which interleave constraint
111generation and solving, constructing the callgraph as they go, this
112implementation for the most part observes a phase ordering (generation
113before solving), with only simple (copy) constraints being generated
114during solving.  (The exception is reflection, which creates various
115constraints during solving as new types flow to reflect.Value
116operations.)  This improves the traction of presolver optimisations,
117but imposes certain restrictions, e.g. potential context sensitivity
118is limited since all variants must be created a priori.
119
120# TERMINOLOGY
121
122A type is said to be "pointer-like" if it is a reference to an object.
123Pointer-like types include pointers and also interfaces, maps, channels,
124functions and slices.
125
126We occasionally use C's x->f notation to distinguish the case where x
127is a struct pointer from x.f where is a struct value.
128
129Pointer analysis literature (and our comments) often uses the notation
130dst=*src+offset to mean something different than what it means in Go.
131It means: for each node index p in pts(src), the node index p+offset is
132in pts(dst).  Similarly *dst+offset=src is used for store constraints
133and dst=src+offset for offset-address constraints.
134
135# NODES
136
137Nodes are the key datastructure of the analysis, and have a dual role:
138they represent both constraint variables (equivalence classes of
139pointers) and members of points-to sets (things that can be pointed
140at, i.e. "labels").
141
142Nodes are naturally numbered.  The numbering enables compact
143representations of sets of nodes such as bitvectors (or BDDs); and the
144ordering enables a very cheap way to group related nodes together.  For
145example, passing n parameters consists of generating n parallel
146constraints from caller+i to callee+i for 0<=i<n.
147
148The zero nodeid means "not a pointer".  For simplicity, we generate flow
149constraints even for non-pointer types such as int.  The pointer
150equivalence (PE) presolver optimization detects which variables cannot
151point to anything; this includes not only all variables of non-pointer
152types (such as int) but also variables of pointer-like types if they are
153always nil, or are parameters to a function that is never called.
154
155Each node represents a scalar part of a value or object.
156Aggregate types (structs, tuples, arrays) are recursively flattened
157out into a sequential list of scalar component types, and all the
158elements of an array are represented by a single node.  (The
159flattening of a basic type is a list containing a single node.)
160
161Nodes are connected into a graph with various kinds of labelled edges:
162simple edges (or copy constraints) represent value flow.  Complex
163edges (load, store, etc) trigger the creation of new simple edges
164during the solving phase.
165
166# OBJECTS
167
168Conceptually, an "object" is a contiguous sequence of nodes denoting
169an addressable location: something that a pointer can point to.  The
170first node of an object has a non-nil obj field containing information
171about the allocation: its size, context, and ssa.Value.
172
173Objects include:
174  - functions and globals;
175  - variable allocations in the stack frame or heap;
176  - maps, channels and slices created by calls to make();
177  - allocations to construct an interface;
178  - allocations caused by conversions, e.g. []byte(str).
179  - arrays allocated by calls to append();
180
181Many objects have no Go types.  For example, the func, map and chan type
182kinds in Go are all varieties of pointers, but their respective objects
183are actual functions (executable code), maps (hash tables), and channels
184(synchronized queues).  Given the way we model interfaces, they too are
185pointers to "tagged" objects with no Go type.  And an *ssa.Global denotes
186the address of a global variable, but the object for a Global is the
187actual data.  So, the types of an ssa.Value that creates an object is
188"off by one indirection": a pointer to the object.
189
190The individual nodes of an object are sometimes referred to as "labels".
191
192For uniformity, all objects have a non-zero number of fields, even those
193of the empty type struct{}.  (All arrays are treated as if of length 1,
194so there are no empty arrays.  The empty tuple is never address-taken,
195so is never an object.)
196
197# TAGGED OBJECTS
198
199An tagged object has the following layout:
200
201    T          -- obj.flags ⊇ {otTagged}
202    v
203    ...
204
205The T node's typ field is the dynamic type of the "payload": the value
206v which follows, flattened out.  The T node's obj has the otTagged
207flag.
208
209Tagged objects are needed when generalizing across types: interfaces,
210reflect.Values, reflect.Types.  Each of these three types is modelled
211as a pointer that exclusively points to tagged objects.
212
213Tagged objects may be indirect (obj.flags ⊇ {otIndirect}) meaning that
214the value v is not of type T but *T; this is used only for
215reflect.Values that represent lvalues.  (These are not implemented yet.)
216
217# ANALYSIS ABSTRACTION OF EACH TYPE
218
219Variables of the following "scalar" types may be represented by a
220single node: basic types, pointers, channels, maps, slices, 'func'
221pointers, interfaces.
222
223Pointers:
224
225Nothing to say here, oddly.
226
227Basic types (bool, string, numbers, unsafe.Pointer):
228
229Currently all fields in the flattening of a type, including
230non-pointer basic types such as int, are represented in objects and
231values.  Though non-pointer nodes within values are uninteresting,
232non-pointer nodes in objects may be useful (if address-taken)
233because they permit the analysis to deduce, in this example,
234
235    var s struct{ ...; x int; ... }
236    p := &s.x
237
238that p points to s.x.  If we ignored such object fields, we could only
239say that p points somewhere within s.
240
241All other basic types are ignored.  Expressions of these types have
242zero nodeid, and fields of these types within aggregate other types
243are omitted.
244
245unsafe.Pointers are not modelled as pointers, so a conversion of an
246unsafe.Pointer to *T is (unsoundly) treated equivalent to new(T).
247
248Channels:
249
250An expression of type 'chan T' is a kind of pointer that points
251exclusively to channel objects, i.e. objects created by MakeChan (or
252reflection).
253
254'chan T' is treated like *T.
255*ssa.MakeChan is treated as equivalent to new(T).
256*ssa.Send and receive (*ssa.UnOp(ARROW)) and are equivalent to store
257
258    and load.
259
260Maps:
261
262An expression of type 'map[K]V' is a kind of pointer that points
263exclusively to map objects, i.e. objects created by MakeMap (or
264reflection).
265
266map K[V] is treated like *M where M = struct{k K; v V}.
267*ssa.MakeMap is equivalent to new(M).
268*ssa.MapUpdate is equivalent to *y=x where *y and x have type M.
269*ssa.Lookup is equivalent to y=x.v where x has type *M.
270
271Slices:
272
273A slice []T, which dynamically resembles a struct{array *T, len, cap int},
274is treated as if it were just a *T pointer; the len and cap fields are
275ignored.
276
277*ssa.MakeSlice is treated like new([1]T): an allocation of a
278
279    singleton array.
280
281*ssa.Index on a slice is equivalent to a load.
282*ssa.IndexAddr on a slice returns the address of the sole element of the
283slice, i.e. the same address.
284*ssa.Slice is treated as a simple copy.
285
286Functions:
287
288An expression of type 'func...' is a kind of pointer that points
289exclusively to function objects.
290
291A function object has the following layout:
292
293    identity         -- typ:*types.Signature; obj.flags ⊇ {otFunction}
294    params_0         -- (the receiver, if a method)
295    ...
296    params_n-1
297    results_0
298    ...
299    results_m-1
300
301There may be multiple function objects for the same *ssa.Function
302due to context-sensitive treatment of some functions.
303
304The first node is the function's identity node.
305Associated with every callsite is a special "targets" variable,
306whose pts() contains the identity node of each function to which
307the call may dispatch.  Identity words are not otherwise used during
308the analysis, but we construct the call graph from the pts()
309solution for such nodes.
310
311The following block of contiguous nodes represents the flattened-out
312types of the parameters ("P-block") and results ("R-block") of the
313function object.
314
315The treatment of free variables of closures (*ssa.FreeVar) is like
316that of global variables; it is not context-sensitive.
317*ssa.MakeClosure instructions create copy edges to Captures.
318
319A Go value of type 'func' (i.e. a pointer to one or more functions)
320is a pointer whose pts() contains function objects.  The valueNode()
321for an *ssa.Function returns a singleton for that function.
322
323Interfaces:
324
325An expression of type 'interface{...}' is a kind of pointer that
326points exclusively to tagged objects.  All tagged objects pointed to
327by an interface are direct (the otIndirect flag is clear) and
328concrete (the tag type T is not itself an interface type).  The
329associated ssa.Value for an interface's tagged objects may be an
330*ssa.MakeInterface instruction, or nil if the tagged object was
331created by an instrinsic (e.g. reflection).
332
333Constructing an interface value causes generation of constraints for
334all of the concrete type's methods; we can't tell a priori which
335ones may be called.
336
337TypeAssert y = x.(T) is implemented by a dynamic constraint
338triggered by each tagged object O added to pts(x): a typeFilter
339constraint if T is an interface type, or an untag constraint if T is
340a concrete type.  A typeFilter tests whether O.typ implements T; if
341so, O is added to pts(y).  An untagFilter tests whether O.typ is
342assignable to T,and if so, a copy edge O.v -> y is added.
343
344ChangeInterface is a simple copy because the representation of
345tagged objects is independent of the interface type (in contrast
346to the "method tables" approach used by the gc runtime).
347
348y := Invoke x.m(...) is implemented by allocating contiguous P/R
349blocks for the callsite and adding a dynamic rule triggered by each
350tagged object added to pts(x).  The rule adds param/results copy
351edges to/from each discovered concrete method.
352
353(Q. Why do we model an interface as a pointer to a pair of type and
354value, rather than as a pair of a pointer to type and a pointer to
355value?
356A. Control-flow joins would merge interfaces ({T1}, {V1}) and ({T2},
357{V2}) to make ({T1,T2}, {V1,V2}), leading to the infeasible and
358type-unsafe combination (T1,V2).  Treating the value and its concrete
359type as inseparable makes the analysis type-safe.)
360
361Type parameters:
362
363Type parameters are not directly supported by the analysis.
364Calls to generic functions will be left as if they had empty bodies.
365Users of the package are expected to use the ssa.InstantiateGenerics
366builder mode when building code that uses or depends on code
367containing generics.
368
369reflect.Value:
370
371A reflect.Value is modelled very similar to an interface{}, i.e. as
372a pointer exclusively to tagged objects, but with two generalizations.
373
3741. a reflect.Value that represents an lvalue points to an indirect
375(obj.flags ⊇ {otIndirect}) tagged object, which has a similar
376layout to an tagged object except that the value is a pointer to
377the dynamic type.  Indirect tagged objects preserve the correct
378aliasing so that mutations made by (reflect.Value).Set can be
379observed.
380
381Indirect objects only arise when an lvalue is derived from an
382rvalue by indirection, e.g. the following code:
383
384    type S struct { X T }
385    var s S
386    var i interface{} = &s    // i points to a *S-tagged object (from MakeInterface)
387    v1 := reflect.ValueOf(i)  // v1 points to same *S-tagged object as i
388    v2 := v1.Elem()           // v2 points to an indirect S-tagged object, pointing to s
389    v3 := v2.FieldByName("X") // v3 points to an indirect int-tagged object, pointing to s.X
390    v3.Set(y)                 // pts(s.X) ⊇ pts(y)
391
392Whether indirect or not, the concrete type of the tagged object
393corresponds to the user-visible dynamic type, and the existence
394of a pointer is an implementation detail.
395
396(NB: indirect tagged objects are not yet implemented)
397
3982. The dynamic type tag of a tagged object pointed to by a
399reflect.Value may be an interface type; it need not be concrete.
400
401This arises in code such as this:
402
403    tEface := reflect.TypeOf(new(interface{}).Elem() // interface{}
404    eface := reflect.Zero(tEface)
405
406pts(eface) is a singleton containing an interface{}-tagged
407object.  That tagged object's payload is an interface{} value,
408i.e. the pts of the payload contains only concrete-tagged
409objects, although in this example it's the zero interface{} value,
410so its pts is empty.
411
412reflect.Type:
413
414Just as in the real "reflect" library, we represent a reflect.Type
415as an interface whose sole implementation is the concrete type,
416*reflect.rtype.  (This choice is forced on us by go/types: clients
417cannot fabricate types with arbitrary method sets.)
418
419rtype instances are canonical: there is at most one per dynamic
420type.  (rtypes are in fact large structs but since identity is all
421that matters, we represent them by a single node.)
422
423The payload of each *rtype-tagged object is an *rtype pointer that
424points to exactly one such canonical rtype object.  We exploit this
425by setting the node.typ of the payload to the dynamic type, not
426'*rtype'.  This saves us an indirection in each resolution rule.  As
427an optimisation, *rtype-tagged objects are canonicalized too.
428
429Aggregate types:
430
431Aggregate types are treated as if all directly contained
432aggregates are recursively flattened out.
433
434Structs:
435
436*ssa.Field y = x.f creates a simple edge to y from x's node at f's offset.
437
438*ssa.FieldAddr y = &x->f requires a dynamic closure rule to create
439
440    simple edges for each struct discovered in pts(x).
441
442The nodes of a struct consist of a special 'identity' node (whose
443type is that of the struct itself), followed by the nodes for all
444the struct's fields, recursively flattened out.  A pointer to the
445struct is a pointer to its identity node.  That node allows us to
446distinguish a pointer to a struct from a pointer to its first field.
447
448Field offsets are logical field offsets (plus one for the identity
449node), so the sizes of the fields can be ignored by the analysis.
450
451(The identity node is non-traditional but enables the distinction
452described above, which is valuable for code comprehension tools.
453Typical pointer analyses for C, whose purpose is compiler
454optimization, must soundly model unsafe.Pointer (void*) conversions,
455and this requires fidelity to the actual memory layout using physical
456field offsets.)
457
458*ssa.Field y = x.f creates a simple edge to y from x's node at f's offset.
459
460*ssa.FieldAddr y = &x->f requires a dynamic closure rule to create
461
462    simple edges for each struct discovered in pts(x).
463
464Arrays:
465
466We model an array by an identity node (whose type is that of the
467array itself) followed by a node representing all the elements of
468the array; the analysis does not distinguish elements with different
469indices.  Effectively, an array is treated like struct{elem T}, a
470load y=x[i] like y=x.elem, and a store x[i]=y like x.elem=y; the
471index i is ignored.
472
473A pointer to an array is pointer to its identity node.  (A slice is
474also a pointer to an array's identity node.)  The identity node
475allows us to distinguish a pointer to an array from a pointer to one
476of its elements, but it is rather costly because it introduces more
477offset constraints into the system.  Furthermore, sound treatment of
478unsafe.Pointer would require us to dispense with this node.
479
480Arrays may be allocated by Alloc, by make([]T), by calls to append,
481and via reflection.
482
483Tuples (T, ...):
484
485Tuples are treated like structs with naturally numbered fields.
486*ssa.Extract is analogous to *ssa.Field.
487
488However, tuples have no identity field since by construction, they
489cannot be address-taken.
490
491# FUNCTION CALLS
492
493There are three kinds of function call:
494 1. static "call"-mode calls of functions.
495 2. dynamic "call"-mode calls of functions.
496 3. dynamic "invoke"-mode calls of interface methods.
497
498Cases 1 and 2 apply equally to methods and standalone functions.
499
500Static calls:
501
502A static call consists three steps:
503  - finding the function object of the callee;
504  - creating copy edges from the actual parameter value nodes to the
505    P-block in the function object (this includes the receiver if
506    the callee is a method);
507  - creating copy edges from the R-block in the function object to
508    the value nodes for the result of the call.
509
510A static function call is little more than two struct value copies
511between the P/R blocks of caller and callee:
512
513    callee.P = caller.P
514    caller.R = callee.R
515
516Context sensitivity: Static calls (alone) may be treated context sensitively,
517i.e. each callsite may cause a distinct re-analysis of the
518callee, improving precision.  Our current context-sensitivity
519policy treats all intrinsics and getter/setter methods in this
520manner since such functions are small and seem like an obvious
521source of spurious confluences, though this has not yet been
522evaluated.
523
524Dynamic function calls:
525
526Dynamic calls work in a similar manner except that the creation of
527copy edges occurs dynamically, in a similar fashion to a pair of
528struct copies in which the callee is indirect:
529
530    callee->P = caller.P
531    caller.R = callee->R
532
533(Recall that the function object's P- and R-blocks are contiguous.)
534
535Interface method invocation:
536
537For invoke-mode calls, we create a params/results block for the
538callsite and attach a dynamic closure rule to the interface.  For
539each new tagged object that flows to the interface, we look up
540the concrete method, find its function object, and connect its P/R
541blocks to the callsite's P/R blocks, adding copy edges to the graph
542during solving.
543
544Recording call targets:
545
546The analysis notifies its clients of each callsite it encounters,
547passing a CallSite interface.  Among other things, the CallSite
548contains a synthetic constraint variable ("targets") whose
549points-to solution includes the set of all function objects to
550which the call may dispatch.
551
552It is via this mechanism that the callgraph is made available.
553Clients may also elect to be notified of callgraph edges directly;
554internally this just iterates all "targets" variables' pts(·)s.
555
556# PRESOLVER
557
558We implement Hash-Value Numbering (HVN), a pre-solver constraint
559optimization described in Hardekopf & Lin, SAS'07.  This is documented
560in more detail in hvn.go.  We intend to add its cousins HR and HU in
561future.
562
563# SOLVER
564
565The solver is currently a naive Andersen-style implementation; it does
566not perform online cycle detection, though we plan to add solver
567optimisations such as Hybrid- and Lazy- Cycle Detection from (Hardekopf
568& Lin, PLDI'07).
569
570It uses difference propagation (Pearce et al, SQC'04) to avoid
571redundant re-triggering of closure rules for values already seen.
572
573Points-to sets are represented using sparse bit vectors (similar to
574those used in LLVM and gcc), which are more space- and time-efficient
575than sets based on Go's built-in map type or dense bit vectors.
576
577Nodes are permuted prior to solving so that object nodes (which may
578appear in points-to sets) are lower numbered than non-object (var)
579nodes.  This improves the density of the set over which the PTSs
580range, and thus the efficiency of the representation.
581
582Partly thanks to avoiding map iteration, the execution of the solver is
583100% deterministic, a great help during debugging.
584
585# FURTHER READING
586
587Andersen, L. O. 1994. Program analysis and specialization for the C
588programming language. Ph.D. dissertation. DIKU, University of
589Copenhagen.
590
591David J. Pearce, Paul H. J. Kelly, and Chris Hankin. 2004.  Efficient
592field-sensitive pointer analysis for C. In Proceedings of the 5th ACM
593SIGPLAN-SIGSOFT workshop on Program analysis for software tools and
594engineering (PASTE '04). ACM, New York, NY, USA, 37-42.
595http://doi.acm.org/10.1145/996821.996835
596
597David J. Pearce, Paul H. J. Kelly, and Chris Hankin. 2004. Online
598Cycle Detection and Difference Propagation: Applications to Pointer
599Analysis. Software Quality Control 12, 4 (December 2004), 311-337.
600http://dx.doi.org/10.1023/B:SQJO.0000039791.93071.a2
601
602David Grove and Craig Chambers. 2001. A framework for call graph
603construction algorithms. ACM Trans. Program. Lang. Syst. 23, 6
604(November 2001), 685-746.
605http://doi.acm.org/10.1145/506315.506316
606
607Ben Hardekopf and Calvin Lin. 2007. The ant and the grasshopper: fast
608and accurate pointer analysis for millions of lines of code. In
609Proceedings of the 2007 ACM SIGPLAN conference on Programming language
610design and implementation (PLDI '07). ACM, New York, NY, USA, 290-299.
611http://doi.acm.org/10.1145/1250734.1250767
612
613Ben Hardekopf and Calvin Lin. 2007. Exploiting pointer and location
614equivalence to optimize pointer analysis. In Proceedings of the 14th
615international conference on Static Analysis (SAS'07), Hanne Riis
616Nielson and Gilberto Filé (Eds.). Springer-Verlag, Berlin, Heidelberg,
617265-280.
618
619Atanas Rountev and Satish Chandra. 2000. Off-line variable substitution
620for scaling points-to analysis. In Proceedings of the ACM SIGPLAN 2000
621conference on Programming language design and implementation (PLDI '00).
622ACM, New York, NY, USA, 47-56. DOI=10.1145/349299.349310
623http://doi.acm.org/10.1145/349299.349310
624*/
625package pointer // import "golang.org/x/tools/go/pointer"
626
MembersX
Members
X