blob: bee656b623760764a0256ae1c9909dd9910b189f [file] [log] [blame]
Alan Donovan713699d2013-08-27 18:49:13 -04001// 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
Alan Donovan6643abb2013-08-22 12:27:55 -04005package pointer
6
7// This file defines the constraint generation phase.
8
Alan Donovan5b55a712013-09-27 11:33:01 -04009// TODO(adonovan): move the constraint definitions and the store() etc
10// functions which add them (and are also used by the solver) into a
11// new file, constraints.go.
12
Alan Donovan6643abb2013-08-22 12:27:55 -040013import (
14 "fmt"
Alan Donovan6643abb2013-08-22 12:27:55 -040015 "go/token"
Alan Donovan542ffc72015-12-29 13:06:30 -050016 "go/types"
Tim King36a5c6a2022-08-25 11:09:24 -040017 "strings"
Alan Donovan6643abb2013-08-22 12:27:55 -040018
Andrew Gerrand5ebbcd12014-11-10 08:50:40 +110019 "golang.org/x/tools/go/callgraph"
20 "golang.org/x/tools/go/ssa"
Tim King36a5c6a2022-08-25 11:09:24 -040021 "golang.org/x/tools/internal/typeparams"
Alan Donovan6643abb2013-08-22 12:27:55 -040022)
23
24var (
Rebecca Stambler207d3de2019-11-20 22:43:00 -050025 tEface = types.NewInterfaceType(nil, nil).Complete()
Alan Donovan6643abb2013-08-22 12:27:55 -040026 tInvalid = types.Typ[types.Invalid]
27 tUnsafePtr = types.Typ[types.UnsafePointer]
28)
29
30// ---------- Node creation ----------
31
32// nextNode returns the index of the next unused node.
33func (a *analysis) nextNode() nodeid {
34 return nodeid(len(a.nodes))
35}
36
37// addNodes creates nodes for all scalar elements in type typ, and
38// returns the id of the first one, or zero if the type was
39// analytically uninteresting.
40//
41// comment explains the origin of the nodes, as a debugging aid.
Alan Donovan6643abb2013-08-22 12:27:55 -040042func (a *analysis) addNodes(typ types.Type, comment string) nodeid {
43 id := a.nextNode()
44 for _, fi := range a.flatten(typ) {
45 a.addOneNode(fi.typ, comment, fi)
46 }
47 if id == a.nextNode() {
48 return 0 // type contained no pointers
49 }
50 return id
51}
52
53// addOneNode creates a single node with type typ, and returns its id.
54//
Alan Donovan3b5de062013-09-16 09:49:10 -040055// typ should generally be scalar (except for tagged.T nodes
Alan Donovan6643abb2013-08-22 12:27:55 -040056// and struct/array identity nodes). Use addNodes for non-scalar types.
57//
58// comment explains the origin of the nodes, as a debugging aid.
59// subelement indicates the subelement, e.g. ".a.b[*].c".
Alan Donovan6643abb2013-08-22 12:27:55 -040060func (a *analysis) addOneNode(typ types.Type, comment string, subelement *fieldInfo) nodeid {
61 id := a.nextNode()
Alan Donovan9b38eaf2014-06-16 15:46:07 -040062 a.nodes = append(a.nodes, &node{typ: typ, subelement: subelement, solve: new(solverState)})
Alan Donovan6643abb2013-08-22 12:27:55 -040063 if a.log != nil {
64 fmt.Fprintf(a.log, "\tcreate n%d %s for %s%s\n",
65 id, typ, comment, subelement.path())
66 }
67 return id
68}
69
70// setValueNode associates node id with the value v.
Alan Donovan5b55a712013-09-27 11:33:01 -040071// cgn identifies the context iff v is a local variable.
Alan Donovan5b55a712013-09-27 11:33:01 -040072func (a *analysis) setValueNode(v ssa.Value, id nodeid, cgn *cgnode) {
73 if cgn != nil {
74 a.localval[v] = id
75 } else {
76 a.globalval[v] = id
77 }
Alan Donovan6643abb2013-08-22 12:27:55 -040078 if a.log != nil {
79 fmt.Fprintf(a.log, "\tval[%s] = n%d (%T)\n", v.Name(), id, v)
80 }
81
Alan Donovan28104d22014-02-20 11:35:09 -050082 // Due to context-sensitivity, we may encounter the same Value
83 // in many contexts. We merge them to a canonical node, since
84 // that's what all clients want.
Alan Donovan5f966442014-02-18 12:40:44 -080085
Alan Donovan7f8168b2013-12-05 22:30:42 -050086 // Record the (v, id) relation if the client has queried pts(v).
87 if _, ok := a.config.Queries[v]; ok {
Alan Donovan28104d22014-02-20 11:35:09 -050088 t := v.Type()
89 ptr, ok := a.result.Queries[v]
90 if !ok {
91 // First time? Create the canonical query node.
92 ptr = Pointer{a, a.addNodes(t, "query")}
93 a.result.Queries[v] = ptr
94 }
95 a.result.Queries[v] = ptr
96 a.copy(ptr.n, id, a.sizeof(t))
Alan Donovan6643abb2013-08-22 12:27:55 -040097 }
Alan Donovan7f8168b2013-12-05 22:30:42 -050098
99 // Record the (*v, id) relation if the client has queried pts(*v).
100 if _, ok := a.config.IndirectQueries[v]; ok {
Alan Donovan28104d22014-02-20 11:35:09 -0500101 t := v.Type()
102 ptr, ok := a.result.IndirectQueries[v]
103 if !ok {
104 // First time? Create the canonical indirect query node.
105 ptr = Pointer{a, a.addNodes(v.Type(), "query.indirect")}
106 a.result.IndirectQueries[v] = ptr
107 }
108 a.genLoad(cgn, ptr.n, v, 0, a.sizeof(t))
Alan Donovan7f8168b2013-12-05 22:30:42 -0500109 }
Dominik Honnefa99f4ec2017-03-01 20:43:03 +0100110
111 for _, query := range a.config.extendedQueries[v] {
112 t, nid := a.evalExtendedQuery(v.Type().Underlying(), id, query.ops)
113
114 if query.ptr.a == nil {
115 query.ptr.a = a
116 query.ptr.n = a.addNodes(t, "query.extended")
117 }
118 a.copy(query.ptr.n, nid, a.sizeof(t))
119 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400120}
121
122// endObject marks the end of a sequence of calls to addNodes denoting
123// a single object allocation.
124//
125// obj is the start node of the object, from a prior call to nextNode.
Alan Donovanae060fe2013-10-01 09:46:33 -0400126// Its size, flags and optional data will be updated.
Alan Donovanae060fe2013-10-01 09:46:33 -0400127func (a *analysis) endObject(obj nodeid, cgn *cgnode, data interface{}) *object {
Alan Donovan6643abb2013-08-22 12:27:55 -0400128 // Ensure object is non-empty by padding;
129 // the pad will be the object node.
130 size := uint32(a.nextNode() - obj)
131 if size == 0 {
132 a.addOneNode(tInvalid, "padding", nil)
133 }
134 objNode := a.nodes[obj]
Alan Donovan3b5de062013-09-16 09:49:10 -0400135 o := &object{
136 size: size, // excludes padding
137 cgn: cgn,
Alan Donovanae060fe2013-10-01 09:46:33 -0400138 data: data,
Alan Donovan6643abb2013-08-22 12:27:55 -0400139 }
Alan Donovan3b5de062013-09-16 09:49:10 -0400140 objNode.obj = o
Alan Donovan3b5de062013-09-16 09:49:10 -0400141
142 return o
Alan Donovan6643abb2013-08-22 12:27:55 -0400143}
144
Alan Donovan2299ac62013-10-09 12:41:55 -0400145// makeFunctionObject creates and returns a new function object
146// (contour) for fn, and returns the id of its first node. It also
147// enqueues fn for subsequent constraint generation.
Alan Donovan6643abb2013-08-22 12:27:55 -0400148//
Alan Donovan2299ac62013-10-09 12:41:55 -0400149// For a context-sensitive contour, callersite identifies the sole
150// callsite; for shared contours, caller is nil.
Alan Donovan2299ac62013-10-09 12:41:55 -0400151func (a *analysis) makeFunctionObject(fn *ssa.Function, callersite *callsite) nodeid {
Alan Donovan6643abb2013-08-22 12:27:55 -0400152 if a.log != nil {
153 fmt.Fprintf(a.log, "\t---- makeFunctionObject %s\n", fn)
154 }
155
156 // obj is the function object (identity, params, results).
157 obj := a.nextNode()
Alan Donovan2299ac62013-10-09 12:41:55 -0400158 cgn := a.makeCGNode(fn, obj, callersite)
Alan Donovan6643abb2013-08-22 12:27:55 -0400159 sig := fn.Signature
160 a.addOneNode(sig, "func.cgnode", nil) // (scalar with Signature type)
161 if recv := sig.Recv(); recv != nil {
162 a.addNodes(recv.Type(), "func.recv")
163 }
164 a.addNodes(sig.Params(), "func.params")
165 a.addNodes(sig.Results(), "func.results")
Alan Donovan3b5de062013-09-16 09:49:10 -0400166 a.endObject(obj, cgn, fn).flags |= otFunction
Alan Donovan6643abb2013-08-22 12:27:55 -0400167
168 if a.log != nil {
169 fmt.Fprintf(a.log, "\t----\n")
170 }
171
Alan Donovan6643abb2013-08-22 12:27:55 -0400172 // Queue it up for constraint processing.
173 a.genq = append(a.genq, cgn)
174
175 return obj
176}
177
Alan Donovan3b5de062013-09-16 09:49:10 -0400178// makeTagged creates a tagged object of type typ.
Alan Donovanae060fe2013-10-01 09:46:33 -0400179func (a *analysis) makeTagged(typ types.Type, cgn *cgnode, data interface{}) nodeid {
Alan Donovan3b5de062013-09-16 09:49:10 -0400180 obj := a.addOneNode(typ, "tagged.T", nil) // NB: type may be non-scalar!
181 a.addNodes(typ, "tagged.v")
Alan Donovanae060fe2013-10-01 09:46:33 -0400182 a.endObject(obj, cgn, data).flags |= otTagged
Alan Donovan3b5de062013-09-16 09:49:10 -0400183 return obj
184}
185
186// makeRtype returns the canonical tagged object of type *rtype whose
187// payload points to the sole rtype object for T.
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400188//
189// TODO(adonovan): move to reflect.go; it's part of the solver really.
Alan Donovan3b5de062013-09-16 09:49:10 -0400190func (a *analysis) makeRtype(T types.Type) nodeid {
191 if v := a.rtypes.At(T); v != nil {
192 return v.(nodeid)
193 }
194
195 // Create the object for the reflect.rtype itself, which is
196 // ordinarily a large struct but here a single node will do.
197 obj := a.nextNode()
198 a.addOneNode(T, "reflect.rtype", nil)
Alan Donovanae060fe2013-10-01 09:46:33 -0400199 a.endObject(obj, nil, T)
Alan Donovan3b5de062013-09-16 09:49:10 -0400200
Alan Donovanae060fe2013-10-01 09:46:33 -0400201 id := a.makeTagged(a.reflectRtypePtr, nil, T)
Alan Donovan3b5de062013-09-16 09:49:10 -0400202 a.nodes[id+1].typ = T // trick (each *rtype tagged object is a singleton)
Alan Donovan5f966442014-02-18 12:40:44 -0800203 a.addressOf(a.reflectRtypePtr, id+1, obj)
Alan Donovan3b5de062013-09-16 09:49:10 -0400204
205 a.rtypes.Set(T, id)
206 return id
207}
208
Alan Donovan3371b792013-09-23 16:13:01 -0400209// rtypeValue returns the type of the *reflect.rtype-tagged object obj.
210func (a *analysis) rtypeTaggedValue(obj nodeid) types.Type {
211 tDyn, t, _ := a.taggedValue(obj)
212 if tDyn != a.reflectRtypePtr {
Alan Donovan94c387c2013-10-29 21:57:53 -0400213 panic(fmt.Sprintf("not a *reflect.rtype-tagged object: obj=n%d tag=%v payload=n%d", obj, tDyn, t))
Alan Donovan3371b792013-09-23 16:13:01 -0400214 }
215 return a.nodes[t].typ
216}
217
Alan Donovan6643abb2013-08-22 12:27:55 -0400218// valueNode returns the id of the value node for v, creating it (and
219// the association) as needed. It may return zero for uninteresting
220// values containing no pointers.
Alan Donovan6643abb2013-08-22 12:27:55 -0400221func (a *analysis) valueNode(v ssa.Value) nodeid {
Alan Donovan5b55a712013-09-27 11:33:01 -0400222 // Value nodes for locals are created en masse by genFunc.
223 if id, ok := a.localval[v]; ok {
224 return id
225 }
226
227 // Value nodes for globals are created on demand.
228 id, ok := a.globalval[v]
Alan Donovan6643abb2013-08-22 12:27:55 -0400229 if !ok {
Alan Donovan5b55a712013-09-27 11:33:01 -0400230 var comment string
231 if a.log != nil {
232 comment = v.String()
Alan Donovan6643abb2013-08-22 12:27:55 -0400233 }
Alan Donovan5c5c4f42014-06-19 15:30:51 -0400234 id = a.addNodes(v.Type(), comment)
Alan Donovan5b55a712013-09-27 11:33:01 -0400235 if obj := a.objectNode(nil, v); obj != 0 {
Alan Donovan5f966442014-02-18 12:40:44 -0800236 a.addressOf(v.Type(), id, obj)
Alan Donovan5b55a712013-09-27 11:33:01 -0400237 }
238 a.setValueNode(v, id, nil)
Alan Donovan6643abb2013-08-22 12:27:55 -0400239 }
240 return id
241}
242
243// valueOffsetNode ascertains the node for tuple/struct value v,
244// then returns the node for its subfield #index.
Alan Donovan6643abb2013-08-22 12:27:55 -0400245func (a *analysis) valueOffsetNode(v ssa.Value, index int) nodeid {
246 id := a.valueNode(v)
247 if id == 0 {
248 panic(fmt.Sprintf("cannot offset within n0: %s = %s", v.Name(), v))
249 }
250 return id + nodeid(a.offsetOf(v.Type(), index))
251}
252
Alan Donovan94c387c2013-10-29 21:57:53 -0400253// isTaggedObject reports whether object obj is a tagged object.
254func (a *analysis) isTaggedObject(obj nodeid) bool {
255 return a.nodes[obj].obj.flags&otTagged != 0
256}
257
Alan Donovan3b5de062013-09-16 09:49:10 -0400258// taggedValue returns the dynamic type tag, the (first node of the)
259// payload, and the indirect flag of the tagged object starting at id.
Alan Donovan94c387c2013-10-29 21:57:53 -0400260// Panic ensues if !isTaggedObject(id).
Alan Donovan94c387c2013-10-29 21:57:53 -0400261func (a *analysis) taggedValue(obj nodeid) (tDyn types.Type, v nodeid, indirect bool) {
262 n := a.nodes[obj]
Alan Donovan3b5de062013-09-16 09:49:10 -0400263 flags := n.obj.flags
Alan Donovan94c387c2013-10-29 21:57:53 -0400264 if flags&otTagged == 0 {
265 panic(fmt.Sprintf("not a tagged object: n%d", obj))
Alan Donovan6643abb2013-08-22 12:27:55 -0400266 }
Alan Donovan94c387c2013-10-29 21:57:53 -0400267 return n.typ, obj + 1, flags&otIndirect != 0
Alan Donovan6643abb2013-08-22 12:27:55 -0400268}
269
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400270// funcParams returns the first node of the params (P) block of the
Alan Donovan3b5de062013-09-16 09:49:10 -0400271// function whose object node (obj.flags&otFunction) is id.
Alan Donovan6643abb2013-08-22 12:27:55 -0400272func (a *analysis) funcParams(id nodeid) nodeid {
Alan Donovan3b5de062013-09-16 09:49:10 -0400273 n := a.nodes[id]
274 if n.obj == nil || n.obj.flags&otFunction == 0 {
Alan Donovan6643abb2013-08-22 12:27:55 -0400275 panic(fmt.Sprintf("funcParams(n%d): not a function object block", id))
276 }
277 return id + 1
278}
279
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400280// funcResults returns the first node of the results (R) block of the
Alan Donovan3b5de062013-09-16 09:49:10 -0400281// function whose object node (obj.flags&otFunction) is id.
Alan Donovan6643abb2013-08-22 12:27:55 -0400282func (a *analysis) funcResults(id nodeid) nodeid {
283 n := a.nodes[id]
Alan Donovan3b5de062013-09-16 09:49:10 -0400284 if n.obj == nil || n.obj.flags&otFunction == 0 {
Alan Donovan6643abb2013-08-22 12:27:55 -0400285 panic(fmt.Sprintf("funcResults(n%d): not a function object block", id))
286 }
287 sig := n.typ.(*types.Signature)
288 id += 1 + nodeid(a.sizeof(sig.Params()))
289 if sig.Recv() != nil {
290 id += nodeid(a.sizeof(sig.Recv().Type()))
291 }
292 return id
293}
294
295// ---------- Constraint creation ----------
296
297// copy creates a constraint of the form dst = src.
298// sizeof is the width (in logical fields) of the copied type.
Alan Donovan6643abb2013-08-22 12:27:55 -0400299func (a *analysis) copy(dst, src nodeid, sizeof uint32) {
300 if src == dst || sizeof == 0 {
301 return // trivial
302 }
303 if src == 0 || dst == 0 {
304 panic(fmt.Sprintf("ill-typed copy dst=n%d src=n%d", dst, src))
305 }
306 for i := uint32(0); i < sizeof; i++ {
307 a.addConstraint(&copyConstraint{dst, src})
308 src++
309 dst++
310 }
311}
312
313// addressOf creates a constraint of the form id = &obj.
Alan Donovan5f966442014-02-18 12:40:44 -0800314// T is the type of the address.
315func (a *analysis) addressOf(T types.Type, id, obj nodeid) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400316 if id == 0 {
317 panic("addressOf: zero id")
318 }
319 if obj == 0 {
320 panic("addressOf: zero obj")
321 }
Alan Donovan5f966442014-02-18 12:40:44 -0800322 if a.shouldTrack(T) {
323 a.addConstraint(&addrConstraint{id, obj})
324 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400325}
326
Alan Donovan5b55a712013-09-27 11:33:01 -0400327// load creates a load constraint of the form dst = src[offset].
Alan Donovan6643abb2013-08-22 12:27:55 -0400328// offset is the pointer offset in logical fields.
329// sizeof is the width (in logical fields) of the loaded type.
Alan Donovan5b55a712013-09-27 11:33:01 -0400330func (a *analysis) load(dst, src nodeid, offset, sizeof uint32) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400331 if dst == 0 {
332 return // load of non-pointerlike value
333 }
334 if src == 0 && dst == 0 {
335 return // non-pointerlike operation
336 }
337 if src == 0 || dst == 0 {
338 panic(fmt.Sprintf("ill-typed load dst=n%d src=n%d", dst, src))
339 }
340 for i := uint32(0); i < sizeof; i++ {
341 a.addConstraint(&loadConstraint{offset, dst, src})
342 offset++
343 dst++
344 }
345}
346
Alan Donovan5b55a712013-09-27 11:33:01 -0400347// store creates a store constraint of the form dst[offset] = src.
Alan Donovan6643abb2013-08-22 12:27:55 -0400348// offset is the pointer offset in logical fields.
349// sizeof is the width (in logical fields) of the stored type.
Alan Donovan5b55a712013-09-27 11:33:01 -0400350func (a *analysis) store(dst, src nodeid, offset uint32, sizeof uint32) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400351 if src == 0 {
352 return // store of non-pointerlike value
353 }
354 if src == 0 && dst == 0 {
355 return // non-pointerlike operation
356 }
357 if src == 0 || dst == 0 {
358 panic(fmt.Sprintf("ill-typed store dst=n%d src=n%d", dst, src))
359 }
360 for i := uint32(0); i < sizeof; i++ {
361 a.addConstraint(&storeConstraint{offset, dst, src})
362 offset++
363 src++
364 }
365}
366
367// offsetAddr creates an offsetAddr constraint of the form dst = &src.#offset.
368// offset is the field offset in logical fields.
Alan Donovan5f966442014-02-18 12:40:44 -0800369// T is the type of the address.
Alan Donovan5f966442014-02-18 12:40:44 -0800370func (a *analysis) offsetAddr(T types.Type, dst, src nodeid, offset uint32) {
371 if !a.shouldTrack(T) {
372 return
373 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400374 if offset == 0 {
375 // Simplify dst = &src->f0
376 // to dst = src
377 // (NB: this optimisation is defeated by the identity
378 // field prepended to struct and array objects.)
379 a.copy(dst, src, 1)
380 } else {
381 a.addConstraint(&offsetAddrConstraint{offset, dst, src})
382 }
383}
384
Alan Donovan94c387c2013-10-29 21:57:53 -0400385// typeAssert creates a typeFilter or untag constraint of the form dst = src.(T):
386// typeFilter for an interface, untag for a concrete type.
387// The exact flag is specified as for untagConstraint.
Alan Donovan94c387c2013-10-29 21:57:53 -0400388func (a *analysis) typeAssert(T types.Type, dst, src nodeid, exact bool) {
389 if isInterface(T) {
390 a.addConstraint(&typeFilterConstraint{T, dst, src})
391 } else {
392 a.addConstraint(&untagConstraint{T, dst, src, exact})
393 }
Alan Donovan3371b792013-09-23 16:13:01 -0400394}
395
Alan Donovan6643abb2013-08-22 12:27:55 -0400396// addConstraint adds c to the constraint set.
397func (a *analysis) addConstraint(c constraint) {
398 a.constraints = append(a.constraints, c)
399 if a.log != nil {
400 fmt.Fprintf(a.log, "\t%s\n", c)
401 }
402}
403
404// copyElems generates load/store constraints for *dst = *src,
405// where src and dst are slices or *arrays.
Alan Donovan5b55a712013-09-27 11:33:01 -0400406func (a *analysis) copyElems(cgn *cgnode, typ types.Type, dst, src ssa.Value) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400407 tmp := a.addNodes(typ, "copy")
408 sz := a.sizeof(typ)
Alan Donovan5b55a712013-09-27 11:33:01 -0400409 a.genLoad(cgn, tmp, src, 1, sz)
410 a.genStore(cgn, dst, tmp, 1, sz)
Alan Donovan6643abb2013-08-22 12:27:55 -0400411}
412
413// ---------- Constraint generation ----------
414
415// genConv generates constraints for the conversion operation conv.
Alan Donovan3b5de062013-09-16 09:49:10 -0400416func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400417 res := a.valueNode(conv)
418 if res == 0 {
419 return // result is non-pointerlike
420 }
421
422 tSrc := conv.X.Type()
423 tDst := conv.Type()
424
425 switch utSrc := tSrc.Underlying().(type) {
426 case *types.Slice:
427 // []byte/[]rune -> string?
428 return
429
430 case *types.Pointer:
431 // *T -> unsafe.Pointer?
Alan Donovan02dba5d2014-06-18 18:02:07 -0400432 if tDst.Underlying() == tUnsafePtr {
Alan Donovan79e0c7b2014-07-08 10:11:36 -0400433 return // we don't model unsafe aliasing (unsound)
Alan Donovan6643abb2013-08-22 12:27:55 -0400434 }
435
436 case *types.Basic:
Alan Donovan79e0c7b2014-07-08 10:11:36 -0400437 switch tDst.Underlying().(type) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400438 case *types.Pointer:
Alan Donovan79e0c7b2014-07-08 10:11:36 -0400439 // Treat unsafe.Pointer->*T conversions like
440 // new(T) and create an unaliased object.
Alan Donovan6643abb2013-08-22 12:27:55 -0400441 if utSrc == tUnsafePtr {
Alan Donovan6643abb2013-08-22 12:27:55 -0400442 obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion")
Alan Donovan3b5de062013-09-16 09:49:10 -0400443 a.endObject(obj, cgn, conv)
Alan Donovan5f966442014-02-18 12:40:44 -0800444 a.addressOf(tDst, res, obj)
Alan Donovan6643abb2013-08-22 12:27:55 -0400445 return
446 }
447
448 case *types.Slice:
449 // string -> []byte/[]rune (or named aliases)?
450 if utSrc.Info()&types.IsString != 0 {
451 obj := a.addNodes(sliceToArray(tDst), "convert")
Alan Donovan3b5de062013-09-16 09:49:10 -0400452 a.endObject(obj, cgn, conv)
Alan Donovan5f966442014-02-18 12:40:44 -0800453 a.addressOf(tDst, res, obj)
Alan Donovan6643abb2013-08-22 12:27:55 -0400454 return
455 }
456
457 case *types.Basic:
Alan Donovan79e0c7b2014-07-08 10:11:36 -0400458 // All basic-to-basic type conversions are no-ops.
459 // This includes uintptr<->unsafe.Pointer conversions,
460 // which we (unsoundly) ignore.
461 return
Alan Donovan6643abb2013-08-22 12:27:55 -0400462 }
463 }
464
465 panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent()))
466}
467
468// genAppend generates constraints for a call to append.
Alan Donovan3b5de062013-09-16 09:49:10 -0400469func (a *analysis) genAppend(instr *ssa.Call, cgn *cgnode) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400470 // Consider z = append(x, y). y is optional.
471 // This may allocate a new [1]T array; call its object w.
472 // We get the following constraints:
473 // z = x
474 // z = &w
475 // *z = *y
476
Alan Donovan5b55a712013-09-27 11:33:01 -0400477 x := instr.Call.Args[0]
Alan Donovan6643abb2013-08-22 12:27:55 -0400478
Alan Donovan5b55a712013-09-27 11:33:01 -0400479 z := instr
480 a.copy(a.valueNode(z), a.valueNode(x), 1) // z = x
Alan Donovan6643abb2013-08-22 12:27:55 -0400481
482 if len(instr.Call.Args) == 1 {
483 return // no allocation for z = append(x) or _ = append(x).
484 }
485
486 // TODO(adonovan): test append([]byte, ...string) []byte.
487
Alan Donovan5b55a712013-09-27 11:33:01 -0400488 y := instr.Call.Args[1]
Alan Donovan6643abb2013-08-22 12:27:55 -0400489 tArray := sliceToArray(instr.Call.Args[0].Type())
490
Rebecca Stambler207d3de2019-11-20 22:43:00 -0500491 w := a.nextNode()
Alan Donovan6643abb2013-08-22 12:27:55 -0400492 a.addNodes(tArray, "append")
Alan Donovan3b5de062013-09-16 09:49:10 -0400493 a.endObject(w, cgn, instr)
Alan Donovan6643abb2013-08-22 12:27:55 -0400494
Alan Donovan5f966442014-02-18 12:40:44 -0800495 a.copyElems(cgn, tArray.Elem(), z, y) // *z = *y
496 a.addressOf(instr.Type(), a.valueNode(z), w) // z = &w
Alan Donovan6643abb2013-08-22 12:27:55 -0400497}
498
Ainar Garipovfeee8ac2019-09-11 09:14:36 +0300499// genBuiltinCall generates constraints for a call to a built-in.
Alan Donovan3b5de062013-09-16 09:49:10 -0400500func (a *analysis) genBuiltinCall(instr ssa.CallInstruction, cgn *cgnode) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400501 call := instr.Common()
Alan Donovande23e2b2014-06-13 17:34:07 -0400502 switch call.Value.(*ssa.Builtin).Name() {
Alan Donovan6643abb2013-08-22 12:27:55 -0400503 case "append":
504 // Safe cast: append cannot appear in a go or defer statement.
Alan Donovan3b5de062013-09-16 09:49:10 -0400505 a.genAppend(instr.(*ssa.Call), cgn)
Alan Donovan6643abb2013-08-22 12:27:55 -0400506
507 case "copy":
508 tElem := call.Args[0].Type().Underlying().(*types.Slice).Elem()
Alan Donovan5b55a712013-09-27 11:33:01 -0400509 a.copyElems(cgn, tElem, call.Args[0], call.Args[1])
Alan Donovan6643abb2013-08-22 12:27:55 -0400510
511 case "panic":
512 a.copy(a.panicNode, a.valueNode(call.Args[0]), 1)
513
514 case "recover":
515 if v := instr.Value(); v != nil {
516 a.copy(a.valueNode(v), a.panicNode, 1)
517 }
518
Alan Donovanfec25222014-06-11 13:10:26 -0400519 case "print":
520 // In the tests, the probe might be the sole reference
521 // to its arg, so make sure we create nodes for it.
Alan Donovance7df392014-11-20 13:33:20 -0500522 if len(call.Args) > 0 {
523 a.valueNode(call.Args[0])
524 }
Alan Donovanfec25222014-06-11 13:10:26 -0400525
Alan Donovande23e2b2014-06-13 17:34:07 -0400526 case "ssa:wrapnilchk":
527 a.copy(a.valueNode(instr.Value()), a.valueNode(call.Args[0]), 1)
528
Alan Donovan6643abb2013-08-22 12:27:55 -0400529 default:
Alan Donovan5f966442014-02-18 12:40:44 -0800530 // No-ops: close len cap real imag complex print println delete.
Alan Donovan6643abb2013-08-22 12:27:55 -0400531 }
532}
533
534// shouldUseContext defines the context-sensitivity policy. It
535// returns true if we should analyse all static calls to fn anew.
536//
537// Obviously this interface rather limits how much freedom we have to
538// choose a policy. The current policy, rather arbitrarily, is true
539// for intrinsics and accessor methods (actually: short, single-block,
540// call-free functions). This is just a starting point.
Alan Donovan6643abb2013-08-22 12:27:55 -0400541func (a *analysis) shouldUseContext(fn *ssa.Function) bool {
542 if a.findIntrinsic(fn) != nil {
543 return true // treat intrinsics context-sensitively
544 }
545 if len(fn.Blocks) != 1 {
546 return false // too expensive
547 }
548 blk := fn.Blocks[0]
549 if len(blk.Instrs) > 10 {
550 return false // too expensive
551 }
552 if fn.Synthetic != "" && (fn.Pkg == nil || fn != fn.Pkg.Func("init")) {
553 return true // treat synthetic wrappers context-sensitively
554 }
555 for _, instr := range blk.Instrs {
556 switch instr := instr.(type) {
557 case ssa.CallInstruction:
558 // Disallow function calls (except to built-ins)
559 // because of the danger of unbounded recursion.
560 if _, ok := instr.Common().Value.(*ssa.Builtin); !ok {
561 return false
562 }
563 }
564 }
565 return true
566}
567
Alan Donovan2299ac62013-10-09 12:41:55 -0400568// genStaticCall generates constraints for a statically dispatched function call.
569func (a *analysis) genStaticCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
Alan Donovan6643abb2013-08-22 12:27:55 -0400570 fn := call.StaticCallee()
Alan Donovan8bb20b82013-10-17 09:26:44 -0400571
572 // Special cases for inlined intrinsics.
573 switch fn {
574 case a.runtimeSetFinalizer:
575 // Inline SetFinalizer so the call appears direct.
576 site.targets = a.addOneNode(tInvalid, "SetFinalizer.targets", nil)
577 a.addConstraint(&runtimeSetFinalizerConstraint{
578 targets: site.targets,
579 x: a.valueNode(call.Args[0]),
580 f: a.valueNode(call.Args[1]),
581 })
582 return
Alan Donovan94c387c2013-10-29 21:57:53 -0400583
584 case a.reflectValueCall:
585 // Inline (reflect.Value).Call so the call appears direct.
586 dotdotdot := false
587 ret := reflectCallImpl(a, caller, site, a.valueNode(call.Args[0]), a.valueNode(call.Args[1]), dotdotdot)
588 if result != 0 {
Alan Donovan5f966442014-02-18 12:40:44 -0800589 a.addressOf(fn.Signature.Results().At(0).Type(), result, ret)
Alan Donovan94c387c2013-10-29 21:57:53 -0400590 }
591 return
Alan Donovan8bb20b82013-10-17 09:26:44 -0400592 }
593
594 // Ascertain the context (contour/cgnode) for a particular call.
595 var obj nodeid
Alan Donovan6643abb2013-08-22 12:27:55 -0400596 if a.shouldUseContext(fn) {
Alan Donovan2299ac62013-10-09 12:41:55 -0400597 obj = a.makeFunctionObject(fn, site) // new contour
Alan Donovan6643abb2013-08-22 12:27:55 -0400598 } else {
Alan Donovan2299ac62013-10-09 12:41:55 -0400599 obj = a.objectNode(nil, fn) // shared contour
Alan Donovan6643abb2013-08-22 12:27:55 -0400600 }
Alan Donovan829d52f2014-02-20 11:57:48 -0500601 a.callEdge(caller, site, obj)
Alan Donovan6643abb2013-08-22 12:27:55 -0400602
603 sig := call.Signature()
Alan Donovan6643abb2013-08-22 12:27:55 -0400604
605 // Copy receiver, if any.
606 params := a.funcParams(obj)
607 args := call.Args
608 if sig.Recv() != nil {
609 sz := a.sizeof(sig.Recv().Type())
610 a.copy(params, a.valueNode(args[0]), sz)
611 params += nodeid(sz)
612 args = args[1:]
613 }
614
615 // Copy actual parameters into formal params block.
616 // Must loop, since the actuals aren't contiguous.
617 for i, arg := range args {
618 sz := a.sizeof(sig.Params().At(i).Type())
619 a.copy(params, a.valueNode(arg), sz)
620 params += nodeid(sz)
621 }
622
623 // Copy formal results block to actual result.
624 if result != 0 {
625 a.copy(result, a.funcResults(obj), a.sizeof(sig.Results()))
626 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400627}
628
629// genDynamicCall generates constraints for a dynamic function call.
Alan Donovan2299ac62013-10-09 12:41:55 -0400630func (a *analysis) genDynamicCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
Alan Donovan8bb20b82013-10-17 09:26:44 -0400631 // pts(targets) will be the set of possible call targets.
632 site.targets = a.valueNode(call.Value)
Alan Donovan6643abb2013-08-22 12:27:55 -0400633
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400634 // We add dynamic closure rules that store the arguments into
635 // the P-block and load the results from the R-block of each
636 // function discovered in pts(targets).
Alan Donovan6643abb2013-08-22 12:27:55 -0400637
Alan Donovan8bb20b82013-10-17 09:26:44 -0400638 sig := call.Signature()
Alan Donovan6643abb2013-08-22 12:27:55 -0400639 var offset uint32 = 1 // P/R block starts at offset 1
640 for i, arg := range call.Args {
641 sz := a.sizeof(sig.Params().At(i).Type())
Alan Donovan5b55a712013-09-27 11:33:01 -0400642 a.genStore(caller, call.Value, a.valueNode(arg), offset, sz)
Alan Donovan6643abb2013-08-22 12:27:55 -0400643 offset += sz
644 }
645 if result != 0 {
Alan Donovan5b55a712013-09-27 11:33:01 -0400646 a.genLoad(caller, result, call.Value, offset, a.sizeof(sig.Results()))
Alan Donovan6643abb2013-08-22 12:27:55 -0400647 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400648}
649
650// genInvoke generates constraints for a dynamic method invocation.
Alan Donovan2299ac62013-10-09 12:41:55 -0400651func (a *analysis) genInvoke(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
Alan Donovan3371b792013-09-23 16:13:01 -0400652 if call.Value.Type() == a.reflectType {
Alan Donovan2299ac62013-10-09 12:41:55 -0400653 a.genInvokeReflectType(caller, site, call, result)
654 return
Alan Donovan3371b792013-09-23 16:13:01 -0400655 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400656
Alan Donovan3371b792013-09-23 16:13:01 -0400657 sig := call.Signature()
Alan Donovan3b5de062013-09-16 09:49:10 -0400658
Alan Donovan6643abb2013-08-22 12:27:55 -0400659 // Allocate a contiguous targets/params/results block for this call.
660 block := a.nextNode()
Alan Donovan2299ac62013-10-09 12:41:55 -0400661 // pts(targets) will be the set of possible call targets
662 site.targets = a.addOneNode(sig, "invoke.targets", nil)
Alan Donovan6643abb2013-08-22 12:27:55 -0400663 p := a.addNodes(sig.Params(), "invoke.params")
664 r := a.addNodes(sig.Results(), "invoke.results")
665
666 // Copy the actual parameters into the call's params block.
667 for i, n := 0, sig.Params().Len(); i < n; i++ {
668 sz := a.sizeof(sig.Params().At(i).Type())
669 a.copy(p, a.valueNode(call.Args[i]), sz)
670 p += nodeid(sz)
671 }
672 // Copy the call's results block to the actual results.
673 if result != 0 {
674 a.copy(result, r, a.sizeof(sig.Results()))
675 }
676
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400677 // We add a dynamic invoke constraint that will connect the
678 // caller's and the callee's P/R blocks for each discovered
679 // call target.
Alan Donovan6643abb2013-08-22 12:27:55 -0400680 a.addConstraint(&invokeConstraint{call.Method, a.valueNode(call.Value), block})
Alan Donovan6643abb2013-08-22 12:27:55 -0400681}
682
Alan Donovan3371b792013-09-23 16:13:01 -0400683// genInvokeReflectType is a specialization of genInvoke where the
684// receiver type is a reflect.Type, under the assumption that there
685// can be at most one implementation of this interface, *reflect.rtype.
686//
687// (Though this may appear to be an instance of a pattern---method
688// calls on interfaces known to have exactly one implementation---in
689// practice it occurs rarely, so we special case for reflect.Type.)
690//
691// In effect we treat this:
Alan Donovan3371b792013-09-23 16:13:01 -0400692//
Russ Coxf9c13bb2022-04-11 22:40:33 -0400693// var rt reflect.Type = ...
694// rt.F()
695//
696// as this:
697//
698// rt.(*reflect.rtype).F()
Alan Donovan2299ac62013-10-09 12:41:55 -0400699func (a *analysis) genInvokeReflectType(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
Alan Donovan3371b792013-09-23 16:13:01 -0400700 // Unpack receiver into rtype
701 rtype := a.addOneNode(a.reflectRtypePtr, "rtype.recv", nil)
702 recv := a.valueNode(call.Value)
Alan Donovan94c387c2013-10-29 21:57:53 -0400703 a.typeAssert(a.reflectRtypePtr, rtype, recv, true)
Alan Donovan3371b792013-09-23 16:13:01 -0400704
705 // Look up the concrete method.
Alan Donovan5f966442014-02-18 12:40:44 -0800706 fn := a.prog.LookupMethod(a.reflectRtypePtr, call.Method.Pkg(), call.Method.Name())
Alan Donovan3371b792013-09-23 16:13:01 -0400707
Alan Donovan2299ac62013-10-09 12:41:55 -0400708 obj := a.makeFunctionObject(fn, site) // new contour for this call
Alan Donovan829d52f2014-02-20 11:57:48 -0500709 a.callEdge(caller, site, obj)
Alan Donovan3371b792013-09-23 16:13:01 -0400710
711 // From now on, it's essentially a static call, but little is
712 // gained by factoring together the code for both cases.
713
714 sig := fn.Signature // concrete method
715 targets := a.addOneNode(sig, "call.targets", nil)
Alan Donovan5f966442014-02-18 12:40:44 -0800716 a.addressOf(sig, targets, obj) // (a singleton)
Alan Donovan3371b792013-09-23 16:13:01 -0400717
718 // Copy receiver.
719 params := a.funcParams(obj)
720 a.copy(params, rtype, 1)
721 params++
722
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400723 // Copy actual parameters into formal P-block.
Alan Donovan3371b792013-09-23 16:13:01 -0400724 // Must loop, since the actuals aren't contiguous.
725 for i, arg := range call.Args {
726 sz := a.sizeof(sig.Params().At(i).Type())
727 a.copy(params, a.valueNode(arg), sz)
728 params += nodeid(sz)
729 }
730
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400731 // Copy formal R-block to actual R-block.
Alan Donovan3371b792013-09-23 16:13:01 -0400732 if result != 0 {
733 a.copy(result, a.funcResults(obj), a.sizeof(sig.Results()))
734 }
Alan Donovan3371b792013-09-23 16:13:01 -0400735}
736
Robert Griesemer30b1abe2014-05-02 14:38:08 -0700737// genCall generates constraints for call instruction instr.
Alan Donovan6643abb2013-08-22 12:27:55 -0400738func (a *analysis) genCall(caller *cgnode, instr ssa.CallInstruction) {
739 call := instr.Common()
740
741 // Intrinsic implementations of built-in functions.
742 if _, ok := call.Value.(*ssa.Builtin); ok {
Alan Donovan3b5de062013-09-16 09:49:10 -0400743 a.genBuiltinCall(instr, caller)
Alan Donovan6643abb2013-08-22 12:27:55 -0400744 return
745 }
746
747 var result nodeid
748 if v := instr.Value(); v != nil {
749 result = a.valueNode(v)
750 }
751
Alan Donovan2299ac62013-10-09 12:41:55 -0400752 site := &callsite{instr: instr}
Alan Donovan8bb20b82013-10-17 09:26:44 -0400753 if call.StaticCallee() != nil {
Alan Donovan2299ac62013-10-09 12:41:55 -0400754 a.genStaticCall(caller, site, call, result)
Alan Donovan8bb20b82013-10-17 09:26:44 -0400755 } else if call.IsInvoke() {
Alan Donovan2299ac62013-10-09 12:41:55 -0400756 a.genInvoke(caller, site, call, result)
Alan Donovan8bb20b82013-10-17 09:26:44 -0400757 } else {
Alan Donovan2299ac62013-10-09 12:41:55 -0400758 a.genDynamicCall(caller, site, call, result)
Alan Donovan6643abb2013-08-22 12:27:55 -0400759 }
760
Alan Donovan785cfaa2013-09-25 17:17:42 -0400761 caller.sites = append(caller.sites, site)
Alan Donovan2299ac62013-10-09 12:41:55 -0400762
Alan Donovan6643abb2013-08-22 12:27:55 -0400763 if a.log != nil {
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400764 // TODO(adonovan): debug: improve log message.
Alan Donovan785cfaa2013-09-25 17:17:42 -0400765 fmt.Fprintf(a.log, "\t%s to targets %s from %s\n", site, site.targets, caller)
Alan Donovan6643abb2013-08-22 12:27:55 -0400766 }
767}
768
Alan Donovan5b55a712013-09-27 11:33:01 -0400769// objectNode returns the object to which v points, if known.
770// In other words, if the points-to set of v is a singleton, it
771// returns the sole label, zero otherwise.
772//
773// We exploit this information to make the generated constraints less
774// dynamic. For example, a complex load constraint can be replaced by
775// a simple copy constraint when the sole destination is known a priori.
776//
777// Some SSA instructions always have singletons points-to sets:
Russ Coxf9c13bb2022-04-11 22:40:33 -0400778//
779// Alloc, Function, Global, MakeChan, MakeClosure, MakeInterface, MakeMap, MakeSlice.
780//
Alan Donovan5b55a712013-09-27 11:33:01 -0400781// Others may be singletons depending on their operands:
Russ Coxf9c13bb2022-04-11 22:40:33 -0400782//
783// FreeVar, Const, Convert, FieldAddr, IndexAddr, Slice, SliceToArrayPointer.
Alan Donovan5b55a712013-09-27 11:33:01 -0400784//
785// Idempotent. Objects are created as needed, possibly via recursion
786// down the SSA value graph, e.g IndexAddr(FieldAddr(Alloc))).
Alan Donovan5b55a712013-09-27 11:33:01 -0400787func (a *analysis) objectNode(cgn *cgnode, v ssa.Value) nodeid {
Alan Donovan94d15892014-06-11 13:19:52 -0400788 switch v.(type) {
Alan Donovancc02c5b2014-06-11 14:04:45 -0400789 case *ssa.Global, *ssa.Function, *ssa.Const, *ssa.FreeVar:
Alan Donovan5b55a712013-09-27 11:33:01 -0400790 // Global object.
791 obj, ok := a.globalobj[v]
792 if !ok {
793 switch v := v.(type) {
794 case *ssa.Global:
795 obj = a.nextNode()
796 a.addNodes(mustDeref(v.Type()), "global")
797 a.endObject(obj, nil, v)
798
799 case *ssa.Function:
Alan Donovan2299ac62013-10-09 12:41:55 -0400800 obj = a.makeFunctionObject(v, nil)
Alan Donovan5b55a712013-09-27 11:33:01 -0400801
802 case *ssa.Const:
Alan Donovan94d15892014-06-11 13:19:52 -0400803 // not addressable
Alan Donovan5b55a712013-09-27 11:33:01 -0400804
Alan Donovancc02c5b2014-06-11 14:04:45 -0400805 case *ssa.FreeVar:
Alan Donovan94d15892014-06-11 13:19:52 -0400806 // not addressable
Alan Donovan5b55a712013-09-27 11:33:01 -0400807 }
Alan Donovanae060fe2013-10-01 09:46:33 -0400808
809 if a.log != nil {
Alan Donovand7a98052013-10-14 13:53:41 -0400810 fmt.Fprintf(a.log, "\tglobalobj[%s] = n%d\n", v, obj)
Alan Donovanae060fe2013-10-01 09:46:33 -0400811 }
Alan Donovan5b55a712013-09-27 11:33:01 -0400812 a.globalobj[v] = obj
813 }
814 return obj
815 }
816
817 // Local object.
818 obj, ok := a.localobj[v]
819 if !ok {
820 switch v := v.(type) {
821 case *ssa.Alloc:
822 obj = a.nextNode()
823 a.addNodes(mustDeref(v.Type()), "alloc")
824 a.endObject(obj, cgn, v)
825
826 case *ssa.MakeSlice:
827 obj = a.nextNode()
828 a.addNodes(sliceToArray(v.Type()), "makeslice")
829 a.endObject(obj, cgn, v)
830
831 case *ssa.MakeChan:
832 obj = a.nextNode()
833 a.addNodes(v.Type().Underlying().(*types.Chan).Elem(), "makechan")
834 a.endObject(obj, cgn, v)
835
836 case *ssa.MakeMap:
837 obj = a.nextNode()
838 tmap := v.Type().Underlying().(*types.Map)
839 a.addNodes(tmap.Key(), "makemap.key")
Alan Donovan9b38eaf2014-06-16 15:46:07 -0400840 elem := a.addNodes(tmap.Elem(), "makemap.value")
841
842 // To update the value field, MapUpdate
843 // generates store-with-offset constraints which
844 // the presolver can't model, so we must mark
845 // those nodes indirect.
846 for id, end := elem, elem+nodeid(a.sizeof(tmap.Elem())); id < end; id++ {
847 a.mapValues = append(a.mapValues, id)
848 }
Alan Donovan5b55a712013-09-27 11:33:01 -0400849 a.endObject(obj, cgn, v)
850
851 case *ssa.MakeInterface:
852 tConc := v.X.Type()
Alan Donovan5b55a712013-09-27 11:33:01 -0400853 obj = a.makeTagged(tConc, cgn, v)
854
855 // Copy the value into it, if nontrivial.
856 if x := a.valueNode(v.X); x != 0 {
857 a.copy(obj+1, x, a.sizeof(tConc))
858 }
859
860 case *ssa.FieldAddr:
861 if xobj := a.objectNode(cgn, v.X); xobj != 0 {
862 obj = xobj + nodeid(a.offsetOf(mustDeref(v.X.Type()), v.Field))
863 }
864
865 case *ssa.IndexAddr:
866 if xobj := a.objectNode(cgn, v.X); xobj != 0 {
867 obj = xobj + 1
868 }
869
870 case *ssa.Slice:
871 obj = a.objectNode(cgn, v.X)
872
Tim King03a91dd2021-08-04 15:10:29 -0700873 case *ssa.SliceToArrayPointer:
874 // Going from a []T to a *[k]T for some k.
875 // A slice []T is treated as if it were a *T pointer.
876 obj = a.objectNode(cgn, v.X)
877
Alan Donovan5b55a712013-09-27 11:33:01 -0400878 case *ssa.Convert:
879 // TODO(adonovan): opt: handle these cases too:
880 // - unsafe.Pointer->*T conversion acts like Alloc
881 // - string->[]byte/[]rune conversion acts like MakeSlice
882 }
Alan Donovanae060fe2013-10-01 09:46:33 -0400883
884 if a.log != nil {
Alan Donovand7a98052013-10-14 13:53:41 -0400885 fmt.Fprintf(a.log, "\tlocalobj[%s] = n%d\n", v.Name(), obj)
Alan Donovanae060fe2013-10-01 09:46:33 -0400886 }
Alan Donovan5b55a712013-09-27 11:33:01 -0400887 a.localobj[v] = obj
888 }
889 return obj
890}
891
892// genLoad generates constraints for result = *(ptr + val).
893func (a *analysis) genLoad(cgn *cgnode, result nodeid, ptr ssa.Value, offset, sizeof uint32) {
894 if obj := a.objectNode(cgn, ptr); obj != 0 {
895 // Pre-apply loadConstraint.solve().
896 a.copy(result, obj+nodeid(offset), sizeof)
897 } else {
898 a.load(result, a.valueNode(ptr), offset, sizeof)
899 }
900}
901
902// genOffsetAddr generates constraints for a 'v=ptr.field' (FieldAddr)
903// or 'v=ptr[*]' (IndexAddr) instruction v.
904func (a *analysis) genOffsetAddr(cgn *cgnode, v ssa.Value, ptr nodeid, offset uint32) {
905 dst := a.valueNode(v)
906 if obj := a.objectNode(cgn, v); obj != 0 {
907 // Pre-apply offsetAddrConstraint.solve().
Alan Donovan5f966442014-02-18 12:40:44 -0800908 a.addressOf(v.Type(), dst, obj)
Alan Donovan5b55a712013-09-27 11:33:01 -0400909 } else {
Alan Donovan5f966442014-02-18 12:40:44 -0800910 a.offsetAddr(v.Type(), dst, ptr, offset)
Alan Donovan5b55a712013-09-27 11:33:01 -0400911 }
912}
913
914// genStore generates constraints for *(ptr + offset) = val.
915func (a *analysis) genStore(cgn *cgnode, ptr ssa.Value, val nodeid, offset, sizeof uint32) {
916 if obj := a.objectNode(cgn, ptr); obj != 0 {
917 // Pre-apply storeConstraint.solve().
918 a.copy(obj+nodeid(offset), val, sizeof)
919 } else {
920 a.store(a.valueNode(ptr), val, offset, sizeof)
921 }
922}
923
Robert Griesemer30b1abe2014-05-02 14:38:08 -0700924// genInstr generates constraints for instruction instr in context cgn.
Alan Donovan6643abb2013-08-22 12:27:55 -0400925func (a *analysis) genInstr(cgn *cgnode, instr ssa.Instruction) {
926 if a.log != nil {
927 var prefix string
928 if val, ok := instr.(ssa.Value); ok {
929 prefix = val.Name() + " = "
930 }
931 fmt.Fprintf(a.log, "; %s%s\n", prefix, instr)
932 }
933
934 switch instr := instr.(type) {
935 case *ssa.DebugRef:
936 // no-op.
937
938 case *ssa.UnOp:
939 switch instr.Op {
940 case token.ARROW: // <-x
941 // We can ignore instr.CommaOk because the node we're
Alan Donovan5b55a712013-09-27 11:33:01 -0400942 // altering is always at zero offset relative to instr
Alan Donovan11451552014-10-27 13:55:52 -0400943 tElem := instr.X.Type().Underlying().(*types.Chan).Elem()
944 a.genLoad(cgn, a.valueNode(instr), instr.X, 0, a.sizeof(tElem))
Alan Donovan6643abb2013-08-22 12:27:55 -0400945
946 case token.MUL: // *x
Alan Donovan5b55a712013-09-27 11:33:01 -0400947 a.genLoad(cgn, a.valueNode(instr), instr.X, 0, a.sizeof(instr.Type()))
Alan Donovan6643abb2013-08-22 12:27:55 -0400948
949 default:
950 // NOT, SUB, XOR: no-op.
951 }
952
953 case *ssa.BinOp:
954 // All no-ops.
955
956 case ssa.CallInstruction: // *ssa.Call, *ssa.Go, *ssa.Defer
957 a.genCall(cgn, instr)
958
959 case *ssa.ChangeType:
960 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
961
962 case *ssa.Convert:
Alan Donovan3b5de062013-09-16 09:49:10 -0400963 a.genConv(instr, cgn)
Alan Donovan6643abb2013-08-22 12:27:55 -0400964
965 case *ssa.Extract:
966 a.copy(a.valueNode(instr),
967 a.valueOffsetNode(instr.Tuple, instr.Index),
968 a.sizeof(instr.Type()))
969
970 case *ssa.FieldAddr:
Alan Donovan5b55a712013-09-27 11:33:01 -0400971 a.genOffsetAddr(cgn, instr, a.valueNode(instr.X),
Alan Donovan6643abb2013-08-22 12:27:55 -0400972 a.offsetOf(mustDeref(instr.X.Type()), instr.Field))
973
974 case *ssa.IndexAddr:
Alan Donovan5b55a712013-09-27 11:33:01 -0400975 a.genOffsetAddr(cgn, instr, a.valueNode(instr.X), 1)
Alan Donovan6643abb2013-08-22 12:27:55 -0400976
977 case *ssa.Field:
978 a.copy(a.valueNode(instr),
979 a.valueOffsetNode(instr.X, instr.Field),
980 a.sizeof(instr.Type()))
981
982 case *ssa.Index:
Tim King36a5c6a2022-08-25 11:09:24 -0400983 _, isstring := typeparams.CoreType(instr.X.Type()).(*types.Basic)
984 if !isstring {
985 a.copy(a.valueNode(instr), 1+a.valueNode(instr.X), a.sizeof(instr.Type()))
986 }
Alan Donovan6643abb2013-08-22 12:27:55 -0400987
988 case *ssa.Select:
989 recv := a.valueOffsetNode(instr, 2) // instr : (index, recvOk, recv0, ... recv_n-1)
990 for _, st := range instr.States {
991 elemSize := a.sizeof(st.Chan.Type().Underlying().(*types.Chan).Elem())
992 switch st.Dir {
Robert Griesemer74d33a92013-12-17 15:45:01 -0800993 case types.RecvOnly:
Alan Donovan5b55a712013-09-27 11:33:01 -0400994 a.genLoad(cgn, recv, st.Chan, 0, elemSize)
Alan Donovan70692d32013-11-13 09:13:42 -0500995 recv += nodeid(elemSize)
Alan Donovan6643abb2013-08-22 12:27:55 -0400996
Robert Griesemer74d33a92013-12-17 15:45:01 -0800997 case types.SendOnly:
Alan Donovan5b55a712013-09-27 11:33:01 -0400998 a.genStore(cgn, st.Chan, a.valueNode(st.Send), 0, elemSize)
Alan Donovan6643abb2013-08-22 12:27:55 -0400999 }
1000 }
1001
Alan Donovan068f0172013-10-08 12:31:39 -04001002 case *ssa.Return:
Alan Donovan6643abb2013-08-22 12:27:55 -04001003 results := a.funcResults(cgn.obj)
1004 for _, r := range instr.Results {
1005 sz := a.sizeof(r.Type())
1006 a.copy(results, a.valueNode(r), sz)
1007 results += nodeid(sz)
1008 }
1009
1010 case *ssa.Send:
Alan Donovan5b55a712013-09-27 11:33:01 -04001011 a.genStore(cgn, instr.Chan, a.valueNode(instr.X), 0, a.sizeof(instr.X.Type()))
Alan Donovan6643abb2013-08-22 12:27:55 -04001012
1013 case *ssa.Store:
Alan Donovan5b55a712013-09-27 11:33:01 -04001014 a.genStore(cgn, instr.Addr, a.valueNode(instr.Val), 0, a.sizeof(instr.Val.Type()))
Alan Donovan6643abb2013-08-22 12:27:55 -04001015
Alan Donovan5b55a712013-09-27 11:33:01 -04001016 case *ssa.Alloc, *ssa.MakeSlice, *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeInterface:
1017 v := instr.(ssa.Value)
Alan Donovan5f966442014-02-18 12:40:44 -08001018 a.addressOf(v.Type(), a.valueNode(v), a.objectNode(cgn, v))
Alan Donovan6643abb2013-08-22 12:27:55 -04001019
1020 case *ssa.ChangeInterface:
1021 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1022
1023 case *ssa.TypeAssert:
Alan Donovan94c387c2013-10-29 21:57:53 -04001024 a.typeAssert(instr.AssertedType, a.valueNode(instr), a.valueNode(instr.X), true)
Alan Donovan6643abb2013-08-22 12:27:55 -04001025
1026 case *ssa.Slice:
1027 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1028
Tim King03a91dd2021-08-04 15:10:29 -07001029 case *ssa.SliceToArrayPointer:
1030 // Going from a []T to a *[k]T (for some k) is a single `dst = src` constraint.
1031 // Both []T and *[k]T are modelled as an *IdArrayT where IdArrayT is the identity
1032 // node for an array of type T, i.e `type IdArrayT struct{elem T}`.
1033 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1034
Alan Donovan6643abb2013-08-22 12:27:55 -04001035 case *ssa.If, *ssa.Jump:
1036 // no-op.
1037
1038 case *ssa.Phi:
1039 sz := a.sizeof(instr.Type())
1040 for _, e := range instr.Edges {
1041 a.copy(a.valueNode(instr), a.valueNode(e), sz)
1042 }
1043
1044 case *ssa.MakeClosure:
1045 fn := instr.Fn.(*ssa.Function)
1046 a.copy(a.valueNode(instr), a.valueNode(fn), 1)
1047 // Free variables are treated like global variables.
1048 for i, b := range instr.Bindings {
1049 a.copy(a.valueNode(fn.FreeVars[i]), a.valueNode(b), a.sizeof(b.Type()))
1050 }
1051
1052 case *ssa.RunDefers:
1053 // The analysis is flow insensitive, so we just "call"
1054 // defers as we encounter them.
1055
1056 case *ssa.Range:
1057 // Do nothing. Next{Iter: *ssa.Range} handles this case.
1058
1059 case *ssa.Next:
Scott Cottonab1fe722021-07-23 22:26:53 +02001060 if !instr.IsString {
1061 // Assumes that Next is always directly applied to a Range result
1062 // for a map.
1063
1064 // Next results in a destination tuple (ok, dk, dv).
1065 // Recall a map is modeled as type *M where M = struct{sk K; sv V}.
1066 // Next copies from a src map struct{sk K; sv V} to a dst tuple (ok, dk, dv)
1067 //
1068 // When keys or value is a blank identifier in a range statement, e.g
1069 // for _, v := range m { ... }
1070 // or
1071 // for _, _ = range m { ... }
1072 // we skip copying from sk or dk as there is no use. dk and dv will have
1073 // Invalid types if they are blank identifiers. This means that the
1074 // size( (ok, dk, dv) ) may differ from 1 + size(struct{sk K; sv V}).
1075 //
1076 // We encode Next using one load of size sz from an offset in src osrc to an
1077 // offset in dst odst. There are 4 cases to consider:
1078 // odst | osrc | sz
1079 // k, v | 1 | 0 | size(sk) + size(sv)
1080 // k, _ | 1 | 0 | size(sk)
1081 // _, v | 1+size(dk) | size(sk) | size(sv)
1082 // _, _ | 1+size(dk) | size(sk) | 0
1083
1084 // get the source key and value size. Note the source types
1085 // may be different than the 3-tuple types, but if this is the
1086 // case then the source is assignable to the destination.
Alan Donovan6643abb2013-08-22 12:27:55 -04001087 theMap := instr.Iter.(*ssa.Range).X
1088 tMap := theMap.Type().Underlying().(*types.Map)
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001089
Scott Cottonab1fe722021-07-23 22:26:53 +02001090 sksize := a.sizeof(tMap.Key())
1091 svsize := a.sizeof(tMap.Elem())
Alan Donovan6643abb2013-08-22 12:27:55 -04001092
Scott Cottonab1fe722021-07-23 22:26:53 +02001093 // get the key size of the destination tuple.
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001094 tTuple := instr.Type().(*types.Tuple)
Scott Cottonab1fe722021-07-23 22:26:53 +02001095 dksize := a.sizeof(tTuple.At(1).Type())
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001096
Alan Donovan6643abb2013-08-22 12:27:55 -04001097 // Load from the map's (k,v) into the tuple's (ok, k, v).
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001098 osrc := uint32(0) // offset within map object
1099 odst := uint32(1) // offset within tuple (initially just after 'ok bool')
1100 sz := uint32(0) // amount to copy
1101
1102 // Is key valid?
1103 if tTuple.At(1).Type() != tInvalid {
Scott Cottonab1fe722021-07-23 22:26:53 +02001104 sz += sksize
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001105 } else {
Scott Cottonab1fe722021-07-23 22:26:53 +02001106 odst += dksize
1107 osrc += sksize
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001108 }
1109
1110 // Is value valid?
1111 if tTuple.At(2).Type() != tInvalid {
Scott Cottonab1fe722021-07-23 22:26:53 +02001112 sz += svsize
Alan Donovan0f9d71c2015-10-26 09:55:02 -04001113 }
1114
1115 a.genLoad(cgn, a.valueNode(instr)+nodeid(odst), theMap, osrc, sz)
Alan Donovan6643abb2013-08-22 12:27:55 -04001116 }
1117
1118 case *ssa.Lookup:
1119 if tMap, ok := instr.X.Type().Underlying().(*types.Map); ok {
1120 // CommaOk can be ignored: field 0 is a no-op.
1121 ksize := a.sizeof(tMap.Key())
1122 vsize := a.sizeof(tMap.Elem())
Alan Donovan5b55a712013-09-27 11:33:01 -04001123 a.genLoad(cgn, a.valueNode(instr), instr.X, ksize, vsize)
Alan Donovan6643abb2013-08-22 12:27:55 -04001124 }
1125
1126 case *ssa.MapUpdate:
1127 tmap := instr.Map.Type().Underlying().(*types.Map)
1128 ksize := a.sizeof(tmap.Key())
1129 vsize := a.sizeof(tmap.Elem())
Alan Donovan5b55a712013-09-27 11:33:01 -04001130 a.genStore(cgn, instr.Map, a.valueNode(instr.Key), 0, ksize)
1131 a.genStore(cgn, instr.Map, a.valueNode(instr.Value), ksize, vsize)
Alan Donovan6643abb2013-08-22 12:27:55 -04001132
1133 case *ssa.Panic:
1134 a.copy(a.panicNode, a.valueNode(instr.X), 1)
1135
1136 default:
1137 panic(fmt.Sprintf("unimplemented: %T", instr))
1138 }
1139}
1140
Alan Donovan2299ac62013-10-09 12:41:55 -04001141func (a *analysis) makeCGNode(fn *ssa.Function, obj nodeid, callersite *callsite) *cgnode {
1142 cgn := &cgnode{fn: fn, obj: obj, callersite: callersite}
Alan Donovan785cfaa2013-09-25 17:17:42 -04001143 a.cgnodes = append(a.cgnodes, cgn)
1144 return cgn
1145}
1146
Alan Donovan6643abb2013-08-22 12:27:55 -04001147// genRootCalls generates the synthetic root of the callgraph and the
1148// initial calls from it to the analysis scope, such as main, a test
1149// or a library.
Alan Donovan6643abb2013-08-22 12:27:55 -04001150func (a *analysis) genRootCalls() *cgnode {
Alan Donovan1edc7502014-06-11 14:03:40 -04001151 r := a.prog.NewFunction("<root>", new(types.Signature), "root of callgraph")
Alan Donovan2299ac62013-10-09 12:41:55 -04001152 root := a.makeCGNode(r, 0, nil)
Alan Donovan6643abb2013-08-22 12:27:55 -04001153
Alan Donovanba9c8012014-03-11 18:24:39 -04001154 // TODO(adonovan): make an ssa utility to construct an actual
1155 // root function so we don't need to special-case site-less
1156 // call edges.
1157
Alan Donovan6643abb2013-08-22 12:27:55 -04001158 // For each main package, call main.init(), main.main().
1159 for _, mainPkg := range a.config.Mains {
1160 main := mainPkg.Func("main")
1161 if main == nil {
1162 panic(fmt.Sprintf("%s has no main function", mainPkg))
1163 }
1164
1165 targets := a.addOneNode(main.Signature, "root.targets", nil)
Alan Donovan785cfaa2013-09-25 17:17:42 -04001166 site := &callsite{targets: targets}
1167 root.sites = append(root.sites, site)
Alan Donovan6643abb2013-08-22 12:27:55 -04001168 for _, fn := range [2]*ssa.Function{mainPkg.Func("init"), main} {
1169 if a.log != nil {
1170 fmt.Fprintf(a.log, "\troot call to %s:\n", fn)
1171 }
1172 a.copy(targets, a.valueNode(fn), 1)
1173 }
1174 }
1175
1176 return root
1177}
1178
1179// genFunc generates constraints for function fn.
1180func (a *analysis) genFunc(cgn *cgnode) {
1181 fn := cgn.fn
Alan Donovan3b5de062013-09-16 09:49:10 -04001182
1183 impl := a.findIntrinsic(fn)
1184
Alan Donovan6643abb2013-08-22 12:27:55 -04001185 if a.log != nil {
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001186 fmt.Fprintf(a.log, "\n\n==== Generating constraints for %s, %s\n", cgn, cgn.contour())
Alan Donovan3b5de062013-09-16 09:49:10 -04001187
1188 // Hack: don't display body if intrinsic.
1189 if impl != nil {
1190 fn2 := *cgn.fn // copy
1191 fn2.Locals = nil
1192 fn2.Blocks = nil
Alan Donovan744d7e62014-01-28 17:48:10 -05001193 fn2.WriteTo(a.log)
Alan Donovan3b5de062013-09-16 09:49:10 -04001194 } else {
Alan Donovan744d7e62014-01-28 17:48:10 -05001195 cgn.fn.WriteTo(a.log)
Alan Donovan3b5de062013-09-16 09:49:10 -04001196 }
Alan Donovan6643abb2013-08-22 12:27:55 -04001197 }
1198
Alan Donovan3b5de062013-09-16 09:49:10 -04001199 if impl != nil {
Alan Donovan6643abb2013-08-22 12:27:55 -04001200 impl(a, cgn)
1201 return
1202 }
1203
1204 if fn.Blocks == nil {
1205 // External function with no intrinsic treatment.
1206 // We'll warn about calls to such functions at the end.
1207 return
1208 }
1209
Tim King36a5c6a2022-08-25 11:09:24 -04001210 if fn.TypeParams().Len() > 0 && len(fn.TypeArgs()) == 0 {
1211 // Body of generic function.
1212 // We'll warn about calls to such functions at the end.
1213 return
1214 }
1215
1216 if strings.HasPrefix(fn.Synthetic, "instantiation wrapper ") {
1217 // instantiation wrapper of a generic function.
1218 // These may contain type coercions which are not currently supported.
1219 // We'll warn about calls to such functions at the end.
1220 return
1221 }
1222
Alan Donovan5b55a712013-09-27 11:33:01 -04001223 if a.log != nil {
1224 fmt.Fprintln(a.log, "; Creating nodes for local values")
1225 }
1226
1227 a.localval = make(map[ssa.Value]nodeid)
1228 a.localobj = make(map[ssa.Value]nodeid)
1229
Alan Donovan6643abb2013-08-22 12:27:55 -04001230 // The value nodes for the params are in the func object block.
1231 params := a.funcParams(cgn.obj)
1232 for _, p := range fn.Params {
Alan Donovan5b55a712013-09-27 11:33:01 -04001233 a.setValueNode(p, params, cgn)
Alan Donovan6643abb2013-08-22 12:27:55 -04001234 params += nodeid(a.sizeof(p.Type()))
1235 }
1236
Alan Donovan94d15892014-06-11 13:19:52 -04001237 // Free variables have global cardinality:
Alan Donovan6643abb2013-08-22 12:27:55 -04001238 // the outer function sets them with MakeClosure;
Alan Donovancc02c5b2014-06-11 14:04:45 -04001239 // the inner function accesses them with FreeVar.
Alan Donovan94d15892014-06-11 13:19:52 -04001240 //
Alan Donovancc02c5b2014-06-11 14:04:45 -04001241 // TODO(adonovan): treat free vars context-sensitively.
Alan Donovan6643abb2013-08-22 12:27:55 -04001242
Alan Donovan5b55a712013-09-27 11:33:01 -04001243 // Create value nodes for all value instructions
1244 // since SSA may contain forward references.
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001245 var space [10]*ssa.Value
Alan Donovan6643abb2013-08-22 12:27:55 -04001246 for _, b := range fn.Blocks {
1247 for _, instr := range b.Instrs {
1248 switch instr := instr.(type) {
1249 case *ssa.Range:
Alan Donovan5b55a712013-09-27 11:33:01 -04001250 // do nothing: it has a funky type,
1251 // and *ssa.Next does all the work.
Alan Donovan6643abb2013-08-22 12:27:55 -04001252
1253 case ssa.Value:
1254 var comment string
1255 if a.log != nil {
1256 comment = instr.Name()
1257 }
1258 id := a.addNodes(instr.Type(), comment)
Alan Donovan5b55a712013-09-27 11:33:01 -04001259 a.setValueNode(instr, id, cgn)
Alan Donovan6643abb2013-08-22 12:27:55 -04001260 }
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001261
1262 // Record all address-taken functions (for presolver).
1263 rands := instr.Operands(space[:0])
1264 if call, ok := instr.(ssa.CallInstruction); ok && !call.Common().IsInvoke() {
1265 // Skip CallCommon.Value in "call" mode.
1266 // TODO(adonovan): fix: relies on unspecified ordering. Specify it.
1267 rands = rands[1:]
1268 }
1269 for _, rand := range rands {
1270 if atf, ok := (*rand).(*ssa.Function); ok {
1271 a.atFuncs[atf] = true
1272 }
1273 }
Alan Donovan6643abb2013-08-22 12:27:55 -04001274 }
1275 }
1276
1277 // Generate constraints for instructions.
1278 for _, b := range fn.Blocks {
1279 for _, instr := range b.Instrs {
1280 a.genInstr(cgn, instr)
1281 }
1282 }
1283
Alan Donovan5b55a712013-09-27 11:33:01 -04001284 a.localval = nil
1285 a.localobj = nil
Alan Donovan6643abb2013-08-22 12:27:55 -04001286}
1287
Alan Donovan87ced822013-10-23 17:07:52 -04001288// genMethodsOf generates nodes and constraints for all methods of type T.
1289func (a *analysis) genMethodsOf(T types.Type) {
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001290 itf := isInterface(T)
1291
1292 // TODO(adonovan): can we skip this entirely if itf is true?
1293 // I think so, but the answer may depend on reflection.
Alan Donovan1f29e742014-02-11 16:49:27 -05001294 mset := a.prog.MethodSets.MethodSet(T)
Alan Donovan87ced822013-10-23 17:07:52 -04001295 for i, n := 0, mset.Len(); i < n; i++ {
Alan Donovanafcda552015-08-31 17:50:03 -04001296 m := a.prog.MethodValue(mset.At(i))
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001297 a.valueNode(m)
1298
1299 if !itf {
1300 // Methods of concrete types are address-taken functions.
1301 a.atFuncs[m] = true
1302 }
Alan Donovan87ced822013-10-23 17:07:52 -04001303 }
1304}
1305
Alan Donovan6643abb2013-08-22 12:27:55 -04001306// generate generates offline constraints for the entire program.
Alan Donovan829d52f2014-02-20 11:57:48 -05001307func (a *analysis) generate() {
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001308 start("Constraint generation")
1309 if a.log != nil {
1310 fmt.Fprintln(a.log, "==== Generating constraints")
1311 }
1312
Alan Donovan6643abb2013-08-22 12:27:55 -04001313 // Create a dummy node since we use the nodeid 0 for
1314 // non-pointerlike variables.
1315 a.addNodes(tInvalid, "(zero)")
1316
1317 // Create the global node for panic values.
1318 a.panicNode = a.addNodes(tEface, "panic")
1319
Alan Donovan3b5de062013-09-16 09:49:10 -04001320 // Create nodes and constraints for all methods of reflect.rtype.
Alan Donovan3371b792013-09-23 16:13:01 -04001321 // (Shared contours are used by dynamic calls to reflect.Type
1322 // methods---typically just String().)
1323 if rtype := a.reflectRtypePtr; rtype != nil {
Alan Donovan87ced822013-10-23 17:07:52 -04001324 a.genMethodsOf(rtype)
Alan Donovan3b5de062013-09-16 09:49:10 -04001325 }
1326
Alan Donovan6643abb2013-08-22 12:27:55 -04001327 root := a.genRootCalls()
1328
Alan Donovan829d52f2014-02-20 11:57:48 -05001329 if a.config.BuildCallGraph {
1330 a.result.CallGraph = callgraph.New(root.fn)
1331 }
1332
Alan Donovan87ced822013-10-23 17:07:52 -04001333 // Create nodes and constraints for all methods of all types
1334 // that are dynamically accessible via reflection or interfaces.
Alan Donovanf0116312014-12-29 13:20:22 -05001335 for _, T := range a.prog.RuntimeTypes() {
Alan Donovan87ced822013-10-23 17:07:52 -04001336 a.genMethodsOf(T)
1337 }
1338
Alan Donovan6361b572016-04-01 10:32:03 -04001339 // Generate constraints for functions as they become reachable
1340 // from the roots. (No constraints are generated for functions
1341 // that are dead in this analysis scope.)
Alan Donovan6643abb2013-08-22 12:27:55 -04001342 for len(a.genq) > 0 {
1343 cgn := a.genq[0]
1344 a.genq = a.genq[1:]
1345 a.genFunc(cgn)
1346 }
1347
Alan Donovanae060fe2013-10-01 09:46:33 -04001348 // The runtime magically allocates os.Args; so should we.
1349 if os := a.prog.ImportedPackage("os"); os != nil {
1350 // In effect: os.Args = new([1]string)[:]
Alan Donovan5f966442014-02-18 12:40:44 -08001351 T := types.NewSlice(types.Typ[types.String])
1352 obj := a.addNodes(sliceToArray(T), "<command-line args>")
Alan Donovanae060fe2013-10-01 09:46:33 -04001353 a.endObject(obj, nil, "<command-line args>")
Alan Donovan5f966442014-02-18 12:40:44 -08001354 a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj)
Alan Donovanae060fe2013-10-01 09:46:33 -04001355 }
Alan Donovan98ed3d32014-03-11 18:37:19 -04001356
1357 // Discard generation state, to avoid confusion after node renumbering.
1358 a.panicNode = 0
1359 a.globalval = nil
1360 a.localval = nil
1361 a.localobj = nil
Alan Donovan9b38eaf2014-06-16 15:46:07 -04001362
1363 stop("Constraint generation")
Alan Donovan6643abb2013-08-22 12:27:55 -04001364}