1
2
3
4
5 package pointer
6
7
8
9
10
11
12
13 import (
14 "fmt"
15 "go/token"
16 "go/types"
17 "strings"
18
19 "golang.org/x/tools/go/callgraph"
20 "golang.org/x/tools/go/ssa"
21 "golang.org/x/tools/internal/typeparams"
22 )
23
24 var (
25 tEface = types.NewInterfaceType(nil, nil).Complete()
26 tInvalid = types.Typ[types.Invalid]
27 tUnsafePtr = types.Typ[types.UnsafePointer]
28 )
29
30
31
32
33 func (a *analysis) nextNode() nodeid {
34 return nodeid(len(a.nodes))
35 }
36
37
38
39
40
41
42 func (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
49 }
50 return id
51 }
52
53
54
55
56
57
58
59
60 func (a *analysis) addOneNode(typ types.Type, comment string, subelement *fieldInfo) nodeid {
61 id := a.nextNode()
62 a.nodes = append(a.nodes, &node{typ: typ, subelement: subelement, solve: new(solverState)})
63 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
71
72 func (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 }
78 if a.log != nil {
79 fmt.Fprintf(a.log, "\tval[%s] = n%d (%T)\n", v.Name(), id, v)
80 }
81
82
83
84
85
86
87 if _, ok := a.config.Queries[v]; ok {
88 t := v.Type()
89 ptr, ok := a.result.Queries[v]
90 if !ok {
91
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))
97 }
98
99
100 if _, ok := a.config.IndirectQueries[v]; ok {
101 t := v.Type()
102 ptr, ok := a.result.IndirectQueries[v]
103 if !ok {
104
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))
109 }
110
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 }
120 }
121
122
123
124
125
126
127 func (a *analysis) endObject(obj nodeid, cgn *cgnode, data interface{}) *object {
128
129
130 size := uint32(a.nextNode() - obj)
131 if size == 0 {
132 a.addOneNode(tInvalid, "padding", nil)
133 }
134 objNode := a.nodes[obj]
135 o := &object{
136 size: size,
137 cgn: cgn,
138 data: data,
139 }
140 objNode.obj = o
141
142 return o
143 }
144
145
146
147
148
149
150
151 func (a *analysis) makeFunctionObject(fn *ssa.Function, callersite *callsite) nodeid {
152 if a.log != nil {
153 fmt.Fprintf(a.log, "\t---- makeFunctionObject %s\n", fn)
154 }
155
156
157 obj := a.nextNode()
158 cgn := a.makeCGNode(fn, obj, callersite)
159 sig := fn.Signature
160 a.addOneNode(sig, "func.cgnode", nil)
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")
166 a.endObject(obj, cgn, fn).flags |= otFunction
167
168 if a.log != nil {
169 fmt.Fprintf(a.log, "\t----\n")
170 }
171
172
173 a.genq = append(a.genq, cgn)
174
175 return obj
176 }
177
178
179 func (a *analysis) makeTagged(typ types.Type, cgn *cgnode, data interface{}) nodeid {
180 obj := a.addOneNode(typ, "tagged.T", nil)
181 a.addNodes(typ, "tagged.v")
182 a.endObject(obj, cgn, data).flags |= otTagged
183 return obj
184 }
185
186
187
188
189
190 func (a *analysis) makeRtype(T types.Type) nodeid {
191 if v := a.rtypes.At(T); v != nil {
192 return v.(nodeid)
193 }
194
195
196
197 obj := a.nextNode()
198 a.addOneNode(T, "reflect.rtype", nil)
199 a.endObject(obj, nil, T)
200
201 id := a.makeTagged(a.reflectRtypePtr, nil, T)
202 a.nodes[id+1].typ = T
203 a.addressOf(a.reflectRtypePtr, id+1, obj)
204
205 a.rtypes.Set(T, id)
206 return id
207 }
208
209
210 func (a *analysis) rtypeTaggedValue(obj nodeid) types.Type {
211 tDyn, t, _ := a.taggedValue(obj)
212 if tDyn != a.reflectRtypePtr {
213 panic(fmt.Sprintf("not a *reflect.rtype-tagged object: obj=n%d tag=%v payload=n%d", obj, tDyn, t))
214 }
215 return a.nodes[t].typ
216 }
217
218
219
220
221 func (a *analysis) valueNode(v ssa.Value) nodeid {
222
223 if id, ok := a.localval[v]; ok {
224 return id
225 }
226
227
228 id, ok := a.globalval[v]
229 if !ok {
230 var comment string
231 if a.log != nil {
232 comment = v.String()
233 }
234 id = a.addNodes(v.Type(), comment)
235 if obj := a.objectNode(nil, v); obj != 0 {
236 a.addressOf(v.Type(), id, obj)
237 }
238 a.setValueNode(v, id, nil)
239 }
240 return id
241 }
242
243
244
245 func (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
253
254 func (a *analysis) isTaggedObject(obj nodeid) bool {
255 return a.nodes[obj].obj.flags&otTagged != 0
256 }
257
258
259
260
261 func (a *analysis) taggedValue(obj nodeid) (tDyn types.Type, v nodeid, indirect bool) {
262 n := a.nodes[obj]
263 flags := n.obj.flags
264 if flags&otTagged == 0 {
265 panic(fmt.Sprintf("not a tagged object: n%d", obj))
266 }
267 return n.typ, obj + 1, flags&otIndirect != 0
268 }
269
270
271
272 func (a *analysis) funcParams(id nodeid) nodeid {
273 n := a.nodes[id]
274 if n.obj == nil || n.obj.flags&otFunction == 0 {
275 panic(fmt.Sprintf("funcParams(n%d): not a function object block", id))
276 }
277 return id + 1
278 }
279
280
281
282 func (a *analysis) funcResults(id nodeid) nodeid {
283 n := a.nodes[id]
284 if n.obj == nil || n.obj.flags&otFunction == 0 {
285 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
296
297
298
299 func (a *analysis) copy(dst, src nodeid, sizeof uint32) {
300 if src == dst || sizeof == 0 {
301 return
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(©Constraint{dst, src})
308 src++
309 dst++
310 }
311 }
312
313
314
315 func (a *analysis) addressOf(T types.Type, id, obj nodeid) {
316 if id == 0 {
317 panic("addressOf: zero id")
318 }
319 if obj == 0 {
320 panic("addressOf: zero obj")
321 }
322 if a.shouldTrack(T) {
323 a.addConstraint(&addrConstraint{id, obj})
324 }
325 }
326
327
328
329
330 func (a *analysis) load(dst, src nodeid, offset, sizeof uint32) {
331 if dst == 0 {
332 return
333 }
334 if src == 0 && dst == 0 {
335 return
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
347
348
349
350 func (a *analysis) store(dst, src nodeid, offset uint32, sizeof uint32) {
351 if src == 0 {
352 return
353 }
354 if src == 0 && dst == 0 {
355 return
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
368
369
370 func (a *analysis) offsetAddr(T types.Type, dst, src nodeid, offset uint32) {
371 if !a.shouldTrack(T) {
372 return
373 }
374 if offset == 0 {
375
376
377
378
379 a.copy(dst, src, 1)
380 } else {
381 a.addConstraint(&offsetAddrConstraint{offset, dst, src})
382 }
383 }
384
385
386
387
388 func (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 }
394 }
395
396
397 func (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
405
406 func (a *analysis) copyElems(cgn *cgnode, typ types.Type, dst, src ssa.Value) {
407 tmp := a.addNodes(typ, "copy")
408 sz := a.sizeof(typ)
409 a.genLoad(cgn, tmp, src, 1, sz)
410 a.genStore(cgn, dst, tmp, 1, sz)
411 }
412
413
414
415
416 func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) {
417 res := a.valueNode(conv)
418 if res == 0 {
419 return
420 }
421
422 tSrc := conv.X.Type()
423 tDst := conv.Type()
424
425 switch utSrc := tSrc.Underlying().(type) {
426 case *types.Slice:
427
428 return
429
430 case *types.Pointer:
431
432 if tDst.Underlying() == tUnsafePtr {
433 return
434 }
435
436 case *types.Basic:
437 switch tDst.Underlying().(type) {
438 case *types.Pointer:
439
440
441 if utSrc == tUnsafePtr {
442 obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion")
443 a.endObject(obj, cgn, conv)
444 a.addressOf(tDst, res, obj)
445 return
446 }
447
448 case *types.Slice:
449
450 if utSrc.Info()&types.IsString != 0 {
451 obj := a.addNodes(sliceToArray(tDst), "convert")
452 a.endObject(obj, cgn, conv)
453 a.addressOf(tDst, res, obj)
454 return
455 }
456
457 case *types.Basic:
458
459
460
461 return
462 }
463 }
464
465 panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent()))
466 }
467
468
469 func (a *analysis) genAppend(instr *ssa.Call, cgn *cgnode) {
470
471
472
473
474
475
476
477 x := instr.Call.Args[0]
478
479 z := instr
480 a.copy(a.valueNode(z), a.valueNode(x), 1)
481
482 if len(instr.Call.Args) == 1 {
483 return
484 }
485
486
487
488 y := instr.Call.Args[1]
489 tArray := sliceToArray(instr.Call.Args[0].Type())
490
491 w := a.nextNode()
492 a.addNodes(tArray, "append")
493 a.endObject(w, cgn, instr)
494
495 a.copyElems(cgn, tArray.Elem(), z, y)
496 a.addressOf(instr.Type(), a.valueNode(z), w)
497 }
498
499
500 func (a *analysis) genBuiltinCall(instr ssa.CallInstruction, cgn *cgnode) {
501 call := instr.Common()
502 switch call.Value.(*ssa.Builtin).Name() {
503 case "append":
504
505 a.genAppend(instr.(*ssa.Call), cgn)
506
507 case "copy":
508 tElem := call.Args[0].Type().Underlying().(*types.Slice).Elem()
509 a.copyElems(cgn, tElem, call.Args[0], call.Args[1])
510
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
519 case "print":
520
521
522 if len(call.Args) > 0 {
523 a.valueNode(call.Args[0])
524 }
525
526 case "ssa:wrapnilchk":
527 a.copy(a.valueNode(instr.Value()), a.valueNode(call.Args[0]), 1)
528
529 default:
530
531 }
532 }
533
534
535
536
537
538
539
540
541 func (a *analysis) shouldUseContext(fn *ssa.Function) bool {
542 if a.findIntrinsic(fn) != nil {
543 return true
544 }
545 if len(fn.Blocks) != 1 {
546 return false
547 }
548 blk := fn.Blocks[0]
549 if len(blk.Instrs) > 10 {
550 return false
551 }
552 if fn.Synthetic != "" && (fn.Pkg == nil || fn != fn.Pkg.Func("init")) {
553 return true
554 }
555 for _, instr := range blk.Instrs {
556 switch instr := instr.(type) {
557 case ssa.CallInstruction:
558
559
560 if _, ok := instr.Common().Value.(*ssa.Builtin); !ok {
561 return false
562 }
563 }
564 }
565 return true
566 }
567
568
569 func (a *analysis) genStaticCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
570 fn := call.StaticCallee()
571
572
573 switch fn {
574 case a.runtimeSetFinalizer:
575
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
583
584 case a.reflectValueCall:
585
586 dotdotdot := false
587 ret := reflectCallImpl(a, caller, site, a.valueNode(call.Args[0]), a.valueNode(call.Args[1]), dotdotdot)
588 if result != 0 {
589 a.addressOf(fn.Signature.Results().At(0).Type(), result, ret)
590 }
591 return
592 }
593
594
595 var obj nodeid
596 if a.shouldUseContext(fn) {
597 obj = a.makeFunctionObject(fn, site)
598 } else {
599 obj = a.objectNode(nil, fn)
600 }
601 a.callEdge(caller, site, obj)
602
603 sig := call.Signature()
604
605
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
616
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
624 if result != 0 {
625 a.copy(result, a.funcResults(obj), a.sizeof(sig.Results()))
626 }
627 }
628
629
630 func (a *analysis) genDynamicCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
631
632 site.targets = a.valueNode(call.Value)
633
634
635
636
637
638 sig := call.Signature()
639 var offset uint32 = 1
640 for i, arg := range call.Args {
641 sz := a.sizeof(sig.Params().At(i).Type())
642 a.genStore(caller, call.Value, a.valueNode(arg), offset, sz)
643 offset += sz
644 }
645 if result != 0 {
646 a.genLoad(caller, result, call.Value, offset, a.sizeof(sig.Results()))
647 }
648 }
649
650
651 func (a *analysis) genInvoke(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
652 if call.Value.Type() == a.reflectType {
653 a.genInvokeReflectType(caller, site, call, result)
654 return
655 }
656
657 sig := call.Signature()
658
659
660 block := a.nextNode()
661
662 site.targets = a.addOneNode(sig, "invoke.targets", nil)
663 p := a.addNodes(sig.Params(), "invoke.params")
664 r := a.addNodes(sig.Results(), "invoke.results")
665
666
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
673 if result != 0 {
674 a.copy(result, r, a.sizeof(sig.Results()))
675 }
676
677
678
679
680 a.addConstraint(&invokeConstraint{call.Method, a.valueNode(call.Value), block})
681 }
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699 func (a *analysis) genInvokeReflectType(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) {
700
701 rtype := a.addOneNode(a.reflectRtypePtr, "rtype.recv", nil)
702 recv := a.valueNode(call.Value)
703 a.typeAssert(a.reflectRtypePtr, rtype, recv, true)
704
705
706 fn := a.prog.LookupMethod(a.reflectRtypePtr, call.Method.Pkg(), call.Method.Name())
707
708 obj := a.makeFunctionObject(fn, site)
709 a.callEdge(caller, site, obj)
710
711
712
713
714 sig := fn.Signature
715 targets := a.addOneNode(sig, "call.targets", nil)
716 a.addressOf(sig, targets, obj)
717
718
719 params := a.funcParams(obj)
720 a.copy(params, rtype, 1)
721 params++
722
723
724
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
731
732 if result != 0 {
733 a.copy(result, a.funcResults(obj), a.sizeof(sig.Results()))
734 }
735 }
736
737
738 func (a *analysis) genCall(caller *cgnode, instr ssa.CallInstruction) {
739 call := instr.Common()
740
741
742 if _, ok := call.Value.(*ssa.Builtin); ok {
743 a.genBuiltinCall(instr, caller)
744 return
745 }
746
747 var result nodeid
748 if v := instr.Value(); v != nil {
749 result = a.valueNode(v)
750 }
751
752 site := &callsite{instr: instr}
753 if call.StaticCallee() != nil {
754 a.genStaticCall(caller, site, call, result)
755 } else if call.IsInvoke() {
756 a.genInvoke(caller, site, call, result)
757 } else {
758 a.genDynamicCall(caller, site, call, result)
759 }
760
761 caller.sites = append(caller.sites, site)
762
763 if a.log != nil {
764
765 fmt.Fprintf(a.log, "\t%s to targets %s from %s\n", site, site.targets, caller)
766 }
767 }
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 func (a *analysis) objectNode(cgn *cgnode, v ssa.Value) nodeid {
788 switch v.(type) {
789 case *ssa.Global, *ssa.Function, *ssa.Const, *ssa.FreeVar:
790
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:
800 obj = a.makeFunctionObject(v, nil)
801
802 case *ssa.Const:
803
804
805 case *ssa.FreeVar:
806
807 }
808
809 if a.log != nil {
810 fmt.Fprintf(a.log, "\tglobalobj[%s] = n%d\n", v, obj)
811 }
812 a.globalobj[v] = obj
813 }
814 return obj
815 }
816
817
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")
840 elem := a.addNodes(tmap.Elem(), "makemap.value")
841
842
843
844
845
846 for id, end := elem, elem+nodeid(a.sizeof(tmap.Elem())); id < end; id++ {
847 a.mapValues = append(a.mapValues, id)
848 }
849 a.endObject(obj, cgn, v)
850
851 case *ssa.MakeInterface:
852 tConc := v.X.Type()
853 obj = a.makeTagged(tConc, cgn, v)
854
855
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
873 case *ssa.SliceToArrayPointer:
874
875
876 obj = a.objectNode(cgn, v.X)
877
878 case *ssa.Convert:
879
880
881
882 }
883
884 if a.log != nil {
885 fmt.Fprintf(a.log, "\tlocalobj[%s] = n%d\n", v.Name(), obj)
886 }
887 a.localobj[v] = obj
888 }
889 return obj
890 }
891
892
893 func (a *analysis) genLoad(cgn *cgnode, result nodeid, ptr ssa.Value, offset, sizeof uint32) {
894 if obj := a.objectNode(cgn, ptr); obj != 0 {
895
896 a.copy(result, obj+nodeid(offset), sizeof)
897 } else {
898 a.load(result, a.valueNode(ptr), offset, sizeof)
899 }
900 }
901
902
903
904 func (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
908 a.addressOf(v.Type(), dst, obj)
909 } else {
910 a.offsetAddr(v.Type(), dst, ptr, offset)
911 }
912 }
913
914
915 func (a *analysis) genStore(cgn *cgnode, ptr ssa.Value, val nodeid, offset, sizeof uint32) {
916 if obj := a.objectNode(cgn, ptr); obj != 0 {
917
918 a.copy(obj+nodeid(offset), val, sizeof)
919 } else {
920 a.store(a.valueNode(ptr), val, offset, sizeof)
921 }
922 }
923
924
925 func (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
937
938 case *ssa.UnOp:
939 switch instr.Op {
940 case token.ARROW:
941
942
943 tElem := instr.X.Type().Underlying().(*types.Chan).Elem()
944 a.genLoad(cgn, a.valueNode(instr), instr.X, 0, a.sizeof(tElem))
945
946 case token.MUL:
947 a.genLoad(cgn, a.valueNode(instr), instr.X, 0, a.sizeof(instr.Type()))
948
949 default:
950
951 }
952
953 case *ssa.BinOp:
954
955
956 case ssa.CallInstruction:
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:
963 a.genConv(instr, cgn)
964
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:
971 a.genOffsetAddr(cgn, instr, a.valueNode(instr.X),
972 a.offsetOf(mustDeref(instr.X.Type()), instr.Field))
973
974 case *ssa.IndexAddr:
975 a.genOffsetAddr(cgn, instr, a.valueNode(instr.X), 1)
976
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:
983 _, 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 }
987
988 case *ssa.Select:
989 recv := a.valueOffsetNode(instr, 2)
990 for _, st := range instr.States {
991 elemSize := a.sizeof(st.Chan.Type().Underlying().(*types.Chan).Elem())
992 switch st.Dir {
993 case types.RecvOnly:
994 a.genLoad(cgn, recv, st.Chan, 0, elemSize)
995 recv += nodeid(elemSize)
996
997 case types.SendOnly:
998 a.genStore(cgn, st.Chan, a.valueNode(st.Send), 0, elemSize)
999 }
1000 }
1001
1002 case *ssa.Return:
1003 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:
1011 a.genStore(cgn, instr.Chan, a.valueNode(instr.X), 0, a.sizeof(instr.X.Type()))
1012
1013 case *ssa.Store:
1014 a.genStore(cgn, instr.Addr, a.valueNode(instr.Val), 0, a.sizeof(instr.Val.Type()))
1015
1016 case *ssa.Alloc, *ssa.MakeSlice, *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeInterface:
1017 v := instr.(ssa.Value)
1018 a.addressOf(v.Type(), a.valueNode(v), a.objectNode(cgn, v))
1019
1020 case *ssa.ChangeInterface:
1021 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1022
1023 case *ssa.TypeAssert:
1024 a.typeAssert(instr.AssertedType, a.valueNode(instr), a.valueNode(instr.X), true)
1025
1026 case *ssa.Slice:
1027 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1028
1029 case *ssa.SliceToArrayPointer:
1030
1031
1032
1033 a.copy(a.valueNode(instr), a.valueNode(instr.X), 1)
1034
1035 case *ssa.If, *ssa.Jump:
1036
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
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
1054
1055
1056 case *ssa.Range:
1057
1058
1059 case *ssa.Next:
1060 if !instr.IsString {
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087 theMap := instr.Iter.(*ssa.Range).X
1088 tMap := theMap.Type().Underlying().(*types.Map)
1089
1090 sksize := a.sizeof(tMap.Key())
1091 svsize := a.sizeof(tMap.Elem())
1092
1093
1094 tTuple := instr.Type().(*types.Tuple)
1095 dksize := a.sizeof(tTuple.At(1).Type())
1096
1097
1098 osrc := uint32(0)
1099 odst := uint32(1)
1100 sz := uint32(0)
1101
1102
1103 if tTuple.At(1).Type() != tInvalid {
1104 sz += sksize
1105 } else {
1106 odst += dksize
1107 osrc += sksize
1108 }
1109
1110
1111 if tTuple.At(2).Type() != tInvalid {
1112 sz += svsize
1113 }
1114
1115 a.genLoad(cgn, a.valueNode(instr)+nodeid(odst), theMap, osrc, sz)
1116 }
1117
1118 case *ssa.Lookup:
1119 if tMap, ok := instr.X.Type().Underlying().(*types.Map); ok {
1120
1121 ksize := a.sizeof(tMap.Key())
1122 vsize := a.sizeof(tMap.Elem())
1123 a.genLoad(cgn, a.valueNode(instr), instr.X, ksize, vsize)
1124 }
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())
1130 a.genStore(cgn, instr.Map, a.valueNode(instr.Key), 0, ksize)
1131 a.genStore(cgn, instr.Map, a.valueNode(instr.Value), ksize, vsize)
1132
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
1141 func (a *analysis) makeCGNode(fn *ssa.Function, obj nodeid, callersite *callsite) *cgnode {
1142 cgn := &cgnode{fn: fn, obj: obj, callersite: callersite}
1143 a.cgnodes = append(a.cgnodes, cgn)
1144 return cgn
1145 }
1146
1147
1148
1149
1150 func (a *analysis) genRootCalls() *cgnode {
1151 r := a.prog.NewFunction("<root>", new(types.Signature), "root of callgraph")
1152 root := a.makeCGNode(r, 0, nil)
1153
1154
1155
1156
1157
1158
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)
1166 site := &callsite{targets: targets}
1167 root.sites = append(root.sites, site)
1168 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
1180 func (a *analysis) genFunc(cgn *cgnode) {
1181 fn := cgn.fn
1182
1183 impl := a.findIntrinsic(fn)
1184
1185 if a.log != nil {
1186 fmt.Fprintf(a.log, "\n\n==== Generating constraints for %s, %s\n", cgn, cgn.contour())
1187
1188
1189 if impl != nil {
1190 fn2 := *cgn.fn
1191 fn2.Locals = nil
1192 fn2.Blocks = nil
1193 fn2.WriteTo(a.log)
1194 } else {
1195 cgn.fn.WriteTo(a.log)
1196 }
1197 }
1198
1199 if impl != nil {
1200 impl(a, cgn)
1201 return
1202 }
1203
1204 if fn.Blocks == nil {
1205
1206
1207 return
1208 }
1209
1210 if fn.TypeParams().Len() > 0 && len(fn.TypeArgs()) == 0 {
1211
1212
1213 return
1214 }
1215
1216 if strings.HasPrefix(fn.Synthetic, "instantiation wrapper ") {
1217
1218
1219
1220 return
1221 }
1222
1223 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
1230
1231 params := a.funcParams(cgn.obj)
1232 for _, p := range fn.Params {
1233 a.setValueNode(p, params, cgn)
1234 params += nodeid(a.sizeof(p.Type()))
1235 }
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 var space [10]*ssa.Value
1246 for _, b := range fn.Blocks {
1247 for _, instr := range b.Instrs {
1248 switch instr := instr.(type) {
1249 case *ssa.Range:
1250
1251
1252
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)
1259 a.setValueNode(instr, id, cgn)
1260 }
1261
1262
1263 rands := instr.Operands(space[:0])
1264 if call, ok := instr.(ssa.CallInstruction); ok && !call.Common().IsInvoke() {
1265
1266
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 }
1274 }
1275 }
1276
1277
1278 for _, b := range fn.Blocks {
1279 for _, instr := range b.Instrs {
1280 a.genInstr(cgn, instr)
1281 }
1282 }
1283
1284 a.localval = nil
1285 a.localobj = nil
1286 }
1287
1288
1289 func (a *analysis) genMethodsOf(T types.Type) {
1290 itf := isInterface(T)
1291
1292
1293
1294 mset := a.prog.MethodSets.MethodSet(T)
1295 for i, n := 0, mset.Len(); i < n; i++ {
1296 m := a.prog.MethodValue(mset.At(i))
1297 a.valueNode(m)
1298
1299 if !itf {
1300
1301 a.atFuncs[m] = true
1302 }
1303 }
1304 }
1305
1306
1307 func (a *analysis) generate() {
1308 start("Constraint generation")
1309 if a.log != nil {
1310 fmt.Fprintln(a.log, "==== Generating constraints")
1311 }
1312
1313
1314
1315 a.addNodes(tInvalid, "(zero)")
1316
1317
1318 a.panicNode = a.addNodes(tEface, "panic")
1319
1320
1321
1322
1323 if rtype := a.reflectRtypePtr; rtype != nil {
1324 a.genMethodsOf(rtype)
1325 }
1326
1327 root := a.genRootCalls()
1328
1329 if a.config.BuildCallGraph {
1330 a.result.CallGraph = callgraph.New(root.fn)
1331 }
1332
1333
1334
1335 for _, T := range a.prog.RuntimeTypes() {
1336 a.genMethodsOf(T)
1337 }
1338
1339
1340
1341
1342 for len(a.genq) > 0 {
1343 cgn := a.genq[0]
1344 a.genq = a.genq[1:]
1345 a.genFunc(cgn)
1346 }
1347
1348
1349 if os := a.prog.ImportedPackage("os"); os != nil {
1350
1351 T := types.NewSlice(types.Typ[types.String])
1352 obj := a.addNodes(sliceToArray(T), "<command-line args>")
1353 a.endObject(obj, nil, "<command-line args>")
1354 a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj)
1355 }
1356
1357
1358 a.panicNode = 0
1359 a.globalval = nil
1360 a.localval = nil
1361 a.localobj = nil
1362
1363 stop("Constraint generation")
1364 }
1365
View as plain text