1
2
3
4
5 package vta
6
7 import (
8 "fmt"
9 "go/token"
10 "go/types"
11
12 "golang.org/x/tools/go/callgraph"
13 "golang.org/x/tools/go/ssa"
14 "golang.org/x/tools/go/types/typeutil"
15 "golang.org/x/tools/internal/aliases"
16 "golang.org/x/tools/internal/typeparams"
17 )
18
19
20 type node interface {
21 Type() types.Type
22 String() string
23 }
24
25
26 type constant struct {
27 typ types.Type
28 }
29
30 func (c constant) Type() types.Type {
31 return c.typ
32 }
33
34 func (c constant) String() string {
35 return fmt.Sprintf("Constant(%v)", c.Type())
36 }
37
38
39 type pointer struct {
40 typ *types.Pointer
41 }
42
43 func (p pointer) Type() types.Type {
44 return p.typ
45 }
46
47 func (p pointer) String() string {
48 return fmt.Sprintf("Pointer(%v)", p.Type())
49 }
50
51
52 type mapKey struct {
53 typ types.Type
54 }
55
56 func (mk mapKey) Type() types.Type {
57 return mk.typ
58 }
59
60 func (mk mapKey) String() string {
61 return fmt.Sprintf("MapKey(%v)", mk.Type())
62 }
63
64
65 type mapValue struct {
66 typ types.Type
67 }
68
69 func (mv mapValue) Type() types.Type {
70 return mv.typ
71 }
72
73 func (mv mapValue) String() string {
74 return fmt.Sprintf("MapValue(%v)", mv.Type())
75 }
76
77
78 type sliceElem struct {
79 typ types.Type
80 }
81
82 func (s sliceElem) Type() types.Type {
83 return s.typ
84 }
85
86 func (s sliceElem) String() string {
87 return fmt.Sprintf("Slice([]%v)", s.Type())
88 }
89
90
91 type channelElem struct {
92 typ types.Type
93 }
94
95 func (c channelElem) Type() types.Type {
96 return c.typ
97 }
98
99 func (c channelElem) String() string {
100 return fmt.Sprintf("Channel(chan %v)", c.Type())
101 }
102
103
104 type field struct {
105 StructType types.Type
106 index int
107 }
108
109 func (f field) Type() types.Type {
110 s := typeparams.CoreType(f.StructType).(*types.Struct)
111 return s.Field(f.index).Type()
112 }
113
114 func (f field) String() string {
115 s := typeparams.CoreType(f.StructType).(*types.Struct)
116 return fmt.Sprintf("Field(%v:%s)", f.StructType, s.Field(f.index).Name())
117 }
118
119
120 type global struct {
121 val *ssa.Global
122 }
123
124 func (g global) Type() types.Type {
125 return g.val.Type()
126 }
127
128 func (g global) String() string {
129 return fmt.Sprintf("Global(%s)", g.val.Name())
130 }
131
132
133
134 type local struct {
135 val ssa.Value
136 }
137
138 func (l local) Type() types.Type {
139 return l.val.Type()
140 }
141
142 func (l local) String() string {
143 return fmt.Sprintf("Local(%s)", l.val.Name())
144 }
145
146
147
148 type indexedLocal struct {
149 val ssa.Value
150 index int
151 typ types.Type
152 }
153
154 func (i indexedLocal) Type() types.Type {
155 return i.typ
156 }
157
158 func (i indexedLocal) String() string {
159 return fmt.Sprintf("Local(%s[%d])", i.val.Name(), i.index)
160 }
161
162
163 type function struct {
164 f *ssa.Function
165 }
166
167 func (f function) Type() types.Type {
168 return f.f.Type()
169 }
170
171 func (f function) String() string {
172 return fmt.Sprintf("Function(%s)", f.f.Name())
173 }
174
175
176
177
178
179
180
181
182
183
184 type nestedPtrInterface struct {
185 typ types.Type
186 }
187
188 func (l nestedPtrInterface) Type() types.Type {
189 return l.typ
190 }
191
192 func (l nestedPtrInterface) String() string {
193 return fmt.Sprintf("PtrInterface(%v)", l.typ)
194 }
195
196
197
198
199
200
201
202
203
204 type nestedPtrFunction struct {
205 typ types.Type
206 }
207
208 func (p nestedPtrFunction) Type() types.Type {
209 return p.typ
210 }
211
212 func (p nestedPtrFunction) String() string {
213 return fmt.Sprintf("PtrFunction(%v)", p.typ)
214 }
215
216
217 type panicArg struct{}
218
219 func (p panicArg) Type() types.Type {
220 return nil
221 }
222
223 func (p panicArg) String() string {
224 return "Panic"
225 }
226
227
228 type recoverReturn struct{}
229
230 func (r recoverReturn) Type() types.Type {
231 return nil
232 }
233
234 func (r recoverReturn) String() string {
235 return "Recover"
236 }
237
238
239
240 type vtaGraph map[node]map[node]bool
241
242
243 func (g vtaGraph) addEdge(x, y node) {
244 succs, ok := g[x]
245 if !ok {
246 succs = make(map[node]bool)
247 g[x] = succs
248 }
249 succs[y] = true
250 }
251
252
253
254 func (g vtaGraph) successors(n node) []node {
255 var succs []node
256 for succ := range g[n] {
257 succs = append(succs, succ)
258 }
259 return succs
260 }
261
262
263
264
265 func typePropGraph(funcs map[*ssa.Function]bool, callgraph *callgraph.Graph) (vtaGraph, *typeutil.Map) {
266 b := builder{graph: make(vtaGraph), callGraph: callgraph}
267 b.visit(funcs)
268 return b.graph, &b.canon
269 }
270
271
272
273 type builder struct {
274 graph vtaGraph
275 callGraph *callgraph.Graph
276
277
278
279
280
281
282
283
284 canon typeutil.Map
285 }
286
287 func (b *builder) visit(funcs map[*ssa.Function]bool) {
288
289 b.graph.addEdge(panicArg{}, recoverReturn{})
290
291 for f, in := range funcs {
292 if in {
293 b.fun(f)
294 }
295 }
296 }
297
298 func (b *builder) fun(f *ssa.Function) {
299 for _, bl := range f.Blocks {
300 for _, instr := range bl.Instrs {
301 b.instr(instr)
302 }
303 }
304 }
305
306 func (b *builder) instr(instr ssa.Instruction) {
307 switch i := instr.(type) {
308 case *ssa.Store:
309 b.addInFlowAliasEdges(b.nodeFromVal(i.Addr), b.nodeFromVal(i.Val))
310 case *ssa.MakeInterface:
311 b.addInFlowEdge(b.nodeFromVal(i.X), b.nodeFromVal(i))
312 case *ssa.MakeClosure:
313 b.closure(i)
314 case *ssa.UnOp:
315 b.unop(i)
316 case *ssa.Phi:
317 b.phi(i)
318 case *ssa.ChangeInterface:
319
320
321
322
323
324
325
326
327 b.addInFlowEdge(b.nodeFromVal(i.X), b.nodeFromVal(i))
328 case *ssa.ChangeType:
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343 b.addInFlowAliasEdges(b.nodeFromVal(i), b.nodeFromVal(i.X))
344 case *ssa.TypeAssert:
345 b.tassert(i)
346 case *ssa.Extract:
347 b.extract(i)
348 case *ssa.Field:
349 b.field(i)
350 case *ssa.FieldAddr:
351 b.fieldAddr(i)
352 case *ssa.Send:
353 b.send(i)
354 case *ssa.Select:
355 b.selekt(i)
356 case *ssa.Index:
357 b.index(i)
358 case *ssa.IndexAddr:
359 b.indexAddr(i)
360 case *ssa.Lookup:
361 b.lookup(i)
362 case *ssa.MapUpdate:
363 b.mapUpdate(i)
364 case *ssa.Next:
365 b.next(i)
366 case ssa.CallInstruction:
367 b.call(i)
368 case *ssa.Panic:
369 b.panic(i)
370 case *ssa.Return:
371 b.rtrn(i)
372 case *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeSlice, *ssa.BinOp,
373 *ssa.Alloc, *ssa.DebugRef, *ssa.Convert, *ssa.Jump, *ssa.If,
374 *ssa.Slice, *ssa.SliceToArrayPointer, *ssa.Range, *ssa.RunDefers:
375
376
377
378
379 return
380 case *ssa.MultiConvert:
381 b.multiconvert(i)
382 default:
383 panic(fmt.Sprintf("unsupported instruction %v\n", instr))
384 }
385 }
386
387 func (b *builder) unop(u *ssa.UnOp) {
388 switch u.Op {
389 case token.MUL:
390
391 b.addInFlowAliasEdges(b.nodeFromVal(u), b.nodeFromVal(u.X))
392 case token.ARROW:
393 t := typeparams.CoreType(u.X.Type()).(*types.Chan).Elem()
394 b.addInFlowAliasEdges(b.nodeFromVal(u), channelElem{typ: t})
395 default:
396
397 }
398 }
399
400 func (b *builder) phi(p *ssa.Phi) {
401 for _, edge := range p.Edges {
402 b.addInFlowAliasEdges(b.nodeFromVal(p), b.nodeFromVal(edge))
403 }
404 }
405
406 func (b *builder) tassert(a *ssa.TypeAssert) {
407 if !a.CommaOk {
408 b.addInFlowEdge(b.nodeFromVal(a.X), b.nodeFromVal(a))
409 return
410 }
411
412
413
414 tup := a.Type().(*types.Tuple)
415 t := tup.At(0).Type()
416
417 local := indexedLocal{val: a, typ: t, index: 0}
418 b.addInFlowEdge(b.nodeFromVal(a.X), local)
419 }
420
421
422
423
424 func (b *builder) extract(e *ssa.Extract) {
425 tup := e.Tuple.Type().(*types.Tuple)
426 t := tup.At(e.Index).Type()
427
428 local := indexedLocal{val: e.Tuple, typ: t, index: e.Index}
429 b.addInFlowAliasEdges(b.nodeFromVal(e), local)
430 }
431
432 func (b *builder) field(f *ssa.Field) {
433 fnode := field{StructType: f.X.Type(), index: f.Field}
434 b.addInFlowEdge(fnode, b.nodeFromVal(f))
435 }
436
437 func (b *builder) fieldAddr(f *ssa.FieldAddr) {
438 t := typeparams.CoreType(f.X.Type()).(*types.Pointer).Elem()
439
440
441 fnode := field{StructType: t, index: f.Field}
442 b.addInFlowEdge(fnode, b.nodeFromVal(f))
443 b.addInFlowEdge(b.nodeFromVal(f), fnode)
444 }
445
446 func (b *builder) send(s *ssa.Send) {
447 t := typeparams.CoreType(s.Chan.Type()).(*types.Chan).Elem()
448 b.addInFlowAliasEdges(channelElem{typ: t}, b.nodeFromVal(s.X))
449 }
450
451
452
453
454
455
456
457
458 func (b *builder) selekt(s *ssa.Select) {
459 recvIndex := 0
460 for _, state := range s.States {
461 t := typeparams.CoreType(state.Chan.Type()).(*types.Chan).Elem()
462
463 if state.Dir == types.SendOnly {
464 b.addInFlowAliasEdges(channelElem{typ: t}, b.nodeFromVal(state.Send))
465 } else {
466
467 tupEntry := indexedLocal{val: s, typ: t, index: 2 + recvIndex}
468 b.addInFlowAliasEdges(tupEntry, channelElem{typ: t})
469 recvIndex++
470 }
471 }
472 }
473
474
475
476
477 func (b *builder) index(i *ssa.Index) {
478 et := sliceArrayElem(i.X.Type())
479 b.addInFlowAliasEdges(b.nodeFromVal(i), sliceElem{typ: et})
480 }
481
482
483
484
485
486 func (b *builder) indexAddr(i *ssa.IndexAddr) {
487 et := sliceArrayElem(i.X.Type())
488 b.addInFlowEdge(sliceElem{typ: et}, b.nodeFromVal(i))
489 b.addInFlowEdge(b.nodeFromVal(i), sliceElem{typ: et})
490 }
491
492
493
494
495 func (b *builder) lookup(l *ssa.Lookup) {
496 t, ok := l.X.Type().Underlying().(*types.Map)
497 if !ok {
498
499 return
500 }
501
502 if !l.CommaOk {
503 b.addInFlowAliasEdges(b.nodeFromVal(l), mapValue{typ: t.Elem()})
504 } else {
505 i := indexedLocal{val: l, typ: t.Elem(), index: 0}
506 b.addInFlowAliasEdges(i, mapValue{typ: t.Elem()})
507 }
508 }
509
510
511
512
513 func (b *builder) mapUpdate(u *ssa.MapUpdate) {
514 t, ok := u.Map.Type().Underlying().(*types.Map)
515 if !ok {
516
517 return
518 }
519
520 b.addInFlowAliasEdges(mapKey{typ: t.Key()}, b.nodeFromVal(u.Key))
521 b.addInFlowAliasEdges(mapValue{typ: t.Elem()}, b.nodeFromVal(u.Value))
522 }
523
524
525
526
527 func (b *builder) next(n *ssa.Next) {
528 if n.IsString {
529 return
530 }
531 tup := n.Type().(*types.Tuple)
532 kt := tup.At(1).Type()
533 vt := tup.At(2).Type()
534
535 b.addInFlowAliasEdges(indexedLocal{val: n, typ: kt, index: 1}, mapKey{typ: kt})
536 b.addInFlowAliasEdges(indexedLocal{val: n, typ: vt, index: 2}, mapValue{typ: vt})
537 }
538
539
540
541
542
543 func (b *builder) addInFlowAliasEdges(l, r node) {
544 b.addInFlowEdge(r, l)
545
546 if canAlias(l, r) {
547 b.addInFlowEdge(l, r)
548 }
549 }
550
551 func (b *builder) closure(c *ssa.MakeClosure) {
552 f := c.Fn.(*ssa.Function)
553 b.addInFlowEdge(function{f: f}, b.nodeFromVal(c))
554
555 for i, fv := range f.FreeVars {
556 b.addInFlowAliasEdges(b.nodeFromVal(fv), b.nodeFromVal(c.Bindings[i]))
557 }
558 }
559
560
561
562
563
564
565
566
567
568 func (b *builder) panic(p *ssa.Panic) {
569
570
571 if !canHaveMethods(p.X.Type()) {
572 return
573 }
574
575 b.addInFlowEdge(b.nodeFromVal(p.X), panicArg{})
576 }
577
578
579
580 func (b *builder) call(c ssa.CallInstruction) {
581
582 if bf, ok := c.Common().Value.(*ssa.Builtin); ok && bf.Name() == "recover" {
583 if v, ok := c.(ssa.Value); ok {
584 b.addInFlowEdge(recoverReturn{}, b.nodeFromVal(v))
585 }
586 return
587 }
588
589 for _, f := range siteCallees(c, b.callGraph) {
590 addArgumentFlows(b, c, f)
591 }
592 }
593
594 func addArgumentFlows(b *builder, c ssa.CallInstruction, f *ssa.Function) {
595
596
597
598
599 if len(f.Params) == 0 {
600 return
601 }
602 cc := c.Common()
603 if cc.Method != nil {
604
605
606
607
608
609
610
611
612 if isFunction(f.Params[0].Type()) {
613 b.addInFlowEdge(b.nodeFromVal(cc.Value), b.nodeFromVal(f.Params[0]))
614 }
615 }
616
617 offset := 0
618 if cc.Method != nil {
619 offset = 1
620 }
621 for i, v := range cc.Args {
622
623
624
625
626
627 if len(f.Params) <= i+offset {
628 return
629 }
630 b.addInFlowAliasEdges(b.nodeFromVal(f.Params[i+offset]), b.nodeFromVal(v))
631 }
632 }
633
634
635
636
637 func (b *builder) rtrn(r *ssa.Return) {
638 n := b.callGraph.Nodes[r.Parent()]
639
640
641 if n == nil {
642 return
643 }
644
645 for _, e := range n.In {
646 if cv, ok := e.Site.(ssa.Value); ok {
647 addReturnFlows(b, r, cv)
648 }
649 }
650 }
651
652 func addReturnFlows(b *builder, r *ssa.Return, site ssa.Value) {
653 results := r.Results
654 if len(results) == 1 {
655
656
657 b.addInFlowEdge(b.nodeFromVal(results[0]), b.nodeFromVal(site))
658 return
659 }
660
661 tup := site.Type().(*types.Tuple)
662 for i, r := range results {
663 local := indexedLocal{val: site, typ: tup.At(i).Type(), index: i}
664 b.addInFlowEdge(b.nodeFromVal(r), local)
665 }
666 }
667
668 func (b *builder) multiconvert(c *ssa.MultiConvert) {
669
670
671 typeSetOf := func(typ types.Type) []*types.Term {
672
673 var terms []*types.Term
674 var err error
675 switch typ := aliases.Unalias(typ).(type) {
676 case *types.TypeParam:
677 terms, err = typeparams.StructuralTerms(typ)
678 case *types.Union:
679 terms, err = typeparams.UnionTermSet(typ)
680 case *types.Interface:
681 terms, err = typeparams.InterfaceTermSet(typ)
682 default:
683
684
685
686 terms = []*types.Term{types.NewTerm(false, typ)}
687 }
688
689 if err != nil {
690 return nil
691 }
692 return terms
693 }
694
695
696
697 isValuePreserving := func(ut_src, ut_dst types.Type) bool {
698
699 if types.IdenticalIgnoreTags(ut_dst, ut_src) {
700 return true
701 }
702
703 switch ut_dst.(type) {
704 case *types.Chan:
705
706 _, ok := ut_src.(*types.Chan)
707 return ok
708
709 case *types.Pointer:
710
711 _, ok := ut_src.(*types.Pointer)
712 return ok
713 }
714 return false
715 }
716 dst_terms := typeSetOf(c.Type())
717 src_terms := typeSetOf(c.X.Type())
718 for _, s := range src_terms {
719 us := s.Type().Underlying()
720 for _, d := range dst_terms {
721 ud := d.Type().Underlying()
722 if isValuePreserving(us, ud) {
723
724 b.addInFlowAliasEdges(b.nodeFromVal(c), b.nodeFromVal(c.X))
725 return
726 }
727
728
729 }
730 }
731 }
732
733
734
735
736 func (b *builder) addInFlowEdge(s, d node) {
737 if hasInFlow(d) {
738 b.graph.addEdge(b.representative(s), b.representative(d))
739 }
740 }
741
742
743 func (b *builder) nodeFromVal(val ssa.Value) node {
744 if p, ok := aliases.Unalias(val.Type()).(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
745
746
747 if i := interfaceUnderPtr(p.Elem()); i != nil {
748 return nestedPtrInterface{typ: i}
749 }
750
751 if f := functionUnderPtr(p.Elem()); f != nil {
752 return nestedPtrFunction{typ: f}
753 }
754 return pointer{typ: p}
755 }
756
757 switch v := val.(type) {
758 case *ssa.Const:
759 return constant{typ: val.Type()}
760 case *ssa.Global:
761 return global{val: v}
762 case *ssa.Function:
763 return function{f: v}
764 case *ssa.Parameter, *ssa.FreeVar, ssa.Instruction:
765
766
767 return local{val: v}
768 default:
769 panic(fmt.Errorf("unsupported value %v in node creation", val))
770 }
771 }
772
773
774
775
776 func (b *builder) representative(n node) node {
777 if n.Type() == nil {
778
779
780 return n
781 }
782 t := canonicalize(n.Type(), &b.canon)
783
784 switch i := n.(type) {
785 case constant:
786 return constant{typ: t}
787 case pointer:
788 return pointer{typ: t.(*types.Pointer)}
789 case sliceElem:
790 return sliceElem{typ: t}
791 case mapKey:
792 return mapKey{typ: t}
793 case mapValue:
794 return mapValue{typ: t}
795 case channelElem:
796 return channelElem{typ: t}
797 case nestedPtrInterface:
798 return nestedPtrInterface{typ: t}
799 case nestedPtrFunction:
800 return nestedPtrFunction{typ: t}
801 case field:
802 return field{StructType: canonicalize(i.StructType, &b.canon), index: i.index}
803 case indexedLocal:
804 return indexedLocal{typ: t, val: i.val, index: i.index}
805 case local, global, panicArg, recoverReturn, function:
806 return n
807 default:
808 panic(fmt.Errorf("canonicalizing unrecognized node %v", n))
809 }
810 }
811
812
813
814 func canonicalize(t types.Type, canon *typeutil.Map) types.Type {
815 rep := canon.At(t)
816 if rep != nil {
817 return rep.(types.Type)
818 }
819 canon.Set(t, t)
820 return t
821 }
822
View as plain text