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