src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

graph.go (24684B)


      1 // Copyright 2021 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package vta
      6 
      7 import (
      8 	"fmt"
      9 	"go/token"
     10 	"go/types"
     11 	"iter"
     12 
     13 	"golang.org/x/tools/go/ssa"
     14 	"golang.org/x/tools/go/types/typeutil"
     15 	"golang.org/x/tools/internal/typeparams"
     16 )
     17 
     18 // node interface for VTA nodes.
     19 type node interface {
     20 	Type() types.Type
     21 	String() string
     22 }
     23 
     24 // constant node for VTA.
     25 type constant struct {
     26 	typ types.Type
     27 }
     28 
     29 func (c constant) Type() types.Type {
     30 	return c.typ
     31 }
     32 
     33 func (c constant) String() string {
     34 	return fmt.Sprintf("Constant(%v)", c.Type())
     35 }
     36 
     37 // pointer node for VTA.
     38 type pointer struct {
     39 	typ *types.Pointer
     40 }
     41 
     42 func (p pointer) Type() types.Type {
     43 	return p.typ
     44 }
     45 
     46 func (p pointer) String() string {
     47 	return fmt.Sprintf("Pointer(%v)", p.Type())
     48 }
     49 
     50 // mapKey node for VTA, modeling reachable map key types.
     51 type mapKey struct {
     52 	typ types.Type
     53 }
     54 
     55 func (mk mapKey) Type() types.Type {
     56 	return mk.typ
     57 }
     58 
     59 func (mk mapKey) String() string {
     60 	return fmt.Sprintf("MapKey(%v)", mk.Type())
     61 }
     62 
     63 // mapValue node for VTA, modeling reachable map value types.
     64 type mapValue struct {
     65 	typ types.Type
     66 }
     67 
     68 func (mv mapValue) Type() types.Type {
     69 	return mv.typ
     70 }
     71 
     72 func (mv mapValue) String() string {
     73 	return fmt.Sprintf("MapValue(%v)", mv.Type())
     74 }
     75 
     76 // sliceElem node for VTA, modeling reachable slice and array element types.
     77 type sliceElem struct {
     78 	typ types.Type
     79 }
     80 
     81 func (s sliceElem) Type() types.Type {
     82 	return s.typ
     83 }
     84 
     85 func (s sliceElem) String() string {
     86 	return fmt.Sprintf("Slice([]%v)", s.Type())
     87 }
     88 
     89 // channelElem node for VTA, modeling reachable channel element types.
     90 type channelElem struct {
     91 	typ types.Type
     92 }
     93 
     94 func (c channelElem) Type() types.Type {
     95 	return c.typ
     96 }
     97 
     98 func (c channelElem) String() string {
     99 	return fmt.Sprintf("Channel(chan %v)", c.Type())
    100 }
    101 
    102 // field node for VTA.
    103 type field struct {
    104 	StructType types.Type
    105 	index      int // index of the field in the struct
    106 }
    107 
    108 func (f field) Type() types.Type {
    109 	s := typeparams.CoreType(f.StructType).(*types.Struct)
    110 	return s.Field(f.index).Type()
    111 }
    112 
    113 func (f field) String() string {
    114 	s := typeparams.CoreType(f.StructType).(*types.Struct)
    115 	return fmt.Sprintf("Field(%v:%s)", f.StructType, s.Field(f.index).Name())
    116 }
    117 
    118 // global node for VTA.
    119 type global struct {
    120 	val *ssa.Global
    121 }
    122 
    123 func (g global) Type() types.Type {
    124 	return g.val.Type()
    125 }
    126 
    127 func (g global) String() string {
    128 	return fmt.Sprintf("Global(%s)", g.val.Name())
    129 }
    130 
    131 // local node for VTA modeling local variables
    132 // and function/method parameters.
    133 type local struct {
    134 	val ssa.Value
    135 }
    136 
    137 func (l local) Type() types.Type {
    138 	return l.val.Type()
    139 }
    140 
    141 func (l local) String() string {
    142 	return fmt.Sprintf("Local(%s)", l.val.Name())
    143 }
    144 
    145 // indexedLocal node for VTA node. Models indexed locals
    146 // related to the ssa extract instructions.
    147 type indexedLocal struct {
    148 	val   ssa.Value
    149 	index int
    150 	typ   types.Type
    151 }
    152 
    153 func (i indexedLocal) Type() types.Type {
    154 	return i.typ
    155 }
    156 
    157 func (i indexedLocal) String() string {
    158 	return fmt.Sprintf("Local(%s[%d])", i.val.Name(), i.index)
    159 }
    160 
    161 // function node for VTA.
    162 type function struct {
    163 	f *ssa.Function
    164 }
    165 
    166 func (f function) Type() types.Type {
    167 	return f.f.Type()
    168 }
    169 
    170 func (f function) String() string {
    171 	return fmt.Sprintf("Function(%s)", f.f.Name())
    172 }
    173 
    174 // resultVar represents the result
    175 // variable of a function, whether
    176 // named or not.
    177 type resultVar struct {
    178 	f     *ssa.Function
    179 	index int // valid index into result var tuple
    180 }
    181 
    182 func (o resultVar) Type() types.Type {
    183 	return o.f.Signature.Results().At(o.index).Type()
    184 }
    185 
    186 func (o resultVar) String() string {
    187 	v := o.f.Signature.Results().At(o.index)
    188 	if n := v.Name(); n != "" {
    189 		return fmt.Sprintf("Return(%s[%s])", o.f.Name(), n)
    190 	}
    191 	return fmt.Sprintf("Return(%s[%d])", o.f.Name(), o.index)
    192 }
    193 
    194 // nestedPtrInterface node represents all references and dereferences
    195 // of locals and globals that have a nested pointer to interface type.
    196 // We merge such constructs into a single node for simplicity and without
    197 // much precision sacrifice as such variables are rare in practice. Both
    198 // a and b would be represented as the same PtrInterface(I) node in:
    199 //
    200 //	type I interface
    201 //	var a ***I
    202 //	var b **I
    203 type nestedPtrInterface struct {
    204 	typ types.Type
    205 }
    206 
    207 func (l nestedPtrInterface) Type() types.Type {
    208 	return l.typ
    209 }
    210 
    211 func (l nestedPtrInterface) String() string {
    212 	return fmt.Sprintf("PtrInterface(%v)", l.typ)
    213 }
    214 
    215 // nestedPtrFunction node represents all references and dereferences of locals
    216 // and globals that have a nested pointer to function type. We merge such
    217 // constructs into a single node for simplicity and without much precision
    218 // sacrifice as such variables are rare in practice. Both a and b would be
    219 // represented as the same PtrFunction(func()) node in:
    220 //
    221 //	var a *func()
    222 //	var b **func()
    223 type nestedPtrFunction struct {
    224 	typ types.Type
    225 }
    226 
    227 func (p nestedPtrFunction) Type() types.Type {
    228 	return p.typ
    229 }
    230 
    231 func (p nestedPtrFunction) String() string {
    232 	return fmt.Sprintf("PtrFunction(%v)", p.typ)
    233 }
    234 
    235 // panicArg models types of all arguments passed to panic.
    236 type panicArg struct{}
    237 
    238 func (p panicArg) Type() types.Type {
    239 	return nil
    240 }
    241 
    242 func (p panicArg) String() string {
    243 	return "Panic"
    244 }
    245 
    246 // recoverReturn models types of all return values of recover().
    247 type recoverReturn struct{}
    248 
    249 func (r recoverReturn) Type() types.Type {
    250 	return nil
    251 }
    252 
    253 func (r recoverReturn) String() string {
    254 	return "Recover"
    255 }
    256 
    257 type empty = struct{}
    258 
    259 // idx is an index representing a unique node in a vtaGraph.
    260 type idx int
    261 
    262 // vtaGraph remembers for each VTA node the set of its successors.
    263 // Tailored for VTA, hence does not support singleton (sub)graphs.
    264 type vtaGraph struct {
    265 	m    []map[idx]empty // m[i] has the successors for the node with index i.
    266 	idx  map[node]idx    // idx[n] is the index for the node n.
    267 	node []node          // node[i] is the node with index i.
    268 }
    269 
    270 func (g *vtaGraph) numNodes() int {
    271 	return len(g.idx)
    272 }
    273 
    274 func (g *vtaGraph) successors(x idx) iter.Seq[idx] {
    275 	return func(yield func(y idx) bool) {
    276 		for y := range g.m[x] {
    277 			if !yield(y) {
    278 				return
    279 			}
    280 		}
    281 	}
    282 }
    283 
    284 // addEdge adds an edge x->y to the graph.
    285 func (g *vtaGraph) addEdge(x, y node) {
    286 	if g.idx == nil {
    287 		g.idx = make(map[node]idx)
    288 	}
    289 	lookup := func(n node) idx {
    290 		i, ok := g.idx[n]
    291 		if !ok {
    292 			i = idx(len(g.idx))
    293 			g.m = append(g.m, nil)
    294 			g.idx[n] = i
    295 			g.node = append(g.node, n)
    296 		}
    297 		return i
    298 	}
    299 	a := lookup(x)
    300 	b := lookup(y)
    301 	succs := g.m[a]
    302 	if succs == nil {
    303 		succs = make(map[idx]empty)
    304 		g.m[a] = succs
    305 	}
    306 	succs[b] = empty{}
    307 }
    308 
    309 // typePropGraph builds a VTA graph for a set of `funcs` and initial
    310 // `callgraph` needed to establish interprocedural edges. Returns the
    311 // graph and a map for unique type representatives.
    312 func typePropGraph(funcs map[*ssa.Function]bool, callees calleesFunc) (*vtaGraph, *typeutil.Map) {
    313 	b := builder{callees: callees}
    314 	b.visit(funcs)
    315 	b.callees = nil // ensure callees is not pinned by pointers to other fields of b.
    316 	return &b.graph, &b.canon
    317 }
    318 
    319 // Data structure responsible for linearly traversing the
    320 // code and building a VTA graph.
    321 type builder struct {
    322 	graph   vtaGraph
    323 	callees calleesFunc // initial call graph for creating flows at unresolved call sites.
    324 
    325 	// Specialized type map for canonicalization of types.Type.
    326 	// Semantically equivalent types can have different implementations,
    327 	// i.e., they are different pointer values. The map allows us to
    328 	// have one unique representative. The keys are fixed and from the
    329 	// client perspective they are types. The values in our case are
    330 	// types too, in particular type representatives. Each value is a
    331 	// pointer so this map is not expected to take much memory.
    332 	canon typeutil.Map
    333 }
    334 
    335 func (b *builder) visit(funcs map[*ssa.Function]bool) {
    336 	// Add the fixed edge Panic -> Recover
    337 	b.graph.addEdge(panicArg{}, recoverReturn{})
    338 
    339 	for f, in := range funcs {
    340 		if in {
    341 			b.fun(f)
    342 		}
    343 	}
    344 }
    345 
    346 func (b *builder) fun(f *ssa.Function) {
    347 	for _, bl := range f.Blocks {
    348 		for _, instr := range bl.Instrs {
    349 			b.instr(instr)
    350 		}
    351 	}
    352 }
    353 
    354 func (b *builder) instr(instr ssa.Instruction) {
    355 	switch i := instr.(type) {
    356 	case *ssa.Store:
    357 		b.addInFlowAliasEdges(b.nodeFromVal(i.Addr), b.nodeFromVal(i.Val))
    358 	case *ssa.MakeInterface:
    359 		b.addInFlowEdge(b.nodeFromVal(i.X), b.nodeFromVal(i))
    360 	case *ssa.MakeClosure:
    361 		b.closure(i)
    362 	case *ssa.UnOp:
    363 		b.unop(i)
    364 	case *ssa.Phi:
    365 		b.phi(i)
    366 	case *ssa.ChangeInterface:
    367 		// Although in change interface a := A(b) command a and b are
    368 		// the same object, the only interesting flow happens when A
    369 		// is an interface. We create flow b -> a, but omit a -> b.
    370 		// The latter flow is not needed: if a gets assigned concrete
    371 		// type later on, that cannot be propagated back to b as b
    372 		// is a separate variable. The a -> b flow can happen when
    373 		// A is a pointer to interface, but then the command is of
    374 		// type ChangeType, handled below.
    375 		b.addInFlowEdge(b.nodeFromVal(i.X), b.nodeFromVal(i))
    376 	case *ssa.ChangeType:
    377 		// change type command a := A(b) results in a and b being the
    378 		// same value. For concrete type A, there is no interesting flow.
    379 		//
    380 		// When A is an interface, most interface casts are handled
    381 		// by the ChangeInterface instruction. The relevant case here is
    382 		// when converting a pointer to an interface type. This can happen
    383 		// when the underlying interfaces have the same method set.
    384 		//
    385 		//	type I interface{ foo() }
    386 		//	type J interface{ foo() }
    387 		//	var b *I
    388 		//	a := (*J)(b)
    389 		//
    390 		// When this happens we add flows between a <--> b.
    391 		b.addInFlowAliasEdges(b.nodeFromVal(i), b.nodeFromVal(i.X))
    392 	case *ssa.TypeAssert:
    393 		b.tassert(i)
    394 	case *ssa.Extract:
    395 		b.extract(i)
    396 	case *ssa.Field:
    397 		b.field(i)
    398 	case *ssa.FieldAddr:
    399 		b.fieldAddr(i)
    400 	case *ssa.Send:
    401 		b.send(i)
    402 	case *ssa.Select:
    403 		b.selekt(i)
    404 	case *ssa.Index:
    405 		b.index(i)
    406 	case *ssa.IndexAddr:
    407 		b.indexAddr(i)
    408 	case *ssa.Lookup:
    409 		b.lookup(i)
    410 	case *ssa.MapUpdate:
    411 		b.mapUpdate(i)
    412 	case *ssa.Next:
    413 		b.next(i)
    414 	case ssa.CallInstruction:
    415 		b.call(i)
    416 	case *ssa.Panic:
    417 		b.panic(i)
    418 	case *ssa.Return:
    419 		b.rtrn(i)
    420 	case *ssa.MakeChan, *ssa.MakeMap, *ssa.MakeSlice, *ssa.BinOp,
    421 		*ssa.Alloc, *ssa.DebugRef, *ssa.Convert, *ssa.Jump, *ssa.If,
    422 		*ssa.Slice, *ssa.SliceToArrayPointer, *ssa.Range, *ssa.RunDefers:
    423 		// No interesting flow here.
    424 		// Notes on individual instructions:
    425 		// SliceToArrayPointer: t1 = slice to array pointer *[4]T <- []T (t0)
    426 		// No interesting flow as sliceArrayElem(t1) == sliceArrayElem(t0).
    427 		return
    428 	case *ssa.MultiConvert:
    429 		b.multiconvert(i)
    430 	default:
    431 		panic(fmt.Sprintf("unsupported instruction %v\n", instr))
    432 	}
    433 }
    434 
    435 func (b *builder) unop(u *ssa.UnOp) {
    436 	switch u.Op {
    437 	case token.MUL:
    438 		// Multiplication operator * is used here as a dereference operator.
    439 		b.addInFlowAliasEdges(b.nodeFromVal(u), b.nodeFromVal(u.X))
    440 	case token.ARROW:
    441 		t := typeparams.CoreType(u.X.Type()).(*types.Chan).Elem()
    442 		b.addInFlowAliasEdges(b.nodeFromVal(u), channelElem{typ: t})
    443 	default:
    444 		// There is no interesting type flow otherwise.
    445 	}
    446 }
    447 
    448 func (b *builder) phi(p *ssa.Phi) {
    449 	for _, edge := range p.Edges {
    450 		b.addInFlowAliasEdges(b.nodeFromVal(p), b.nodeFromVal(edge))
    451 	}
    452 }
    453 
    454 func (b *builder) tassert(a *ssa.TypeAssert) {
    455 	if !a.CommaOk {
    456 		b.addInFlowEdge(b.nodeFromVal(a.X), b.nodeFromVal(a))
    457 		return
    458 	}
    459 	// The case where a is <a.AssertedType, bool> register so there
    460 	// is a flow from a.X to a[0]. Here, a[0] is represented as an
    461 	// indexedLocal: an entry into local tuple register a at index 0.
    462 	tup := a.Type().(*types.Tuple)
    463 	t := tup.At(0).Type()
    464 
    465 	local := indexedLocal{val: a, typ: t, index: 0}
    466 	b.addInFlowEdge(b.nodeFromVal(a.X), local)
    467 }
    468 
    469 // extract instruction t1 := t2[i] generates flows between t2[i]
    470 // and t1 where the source is indexed local representing a value
    471 // from tuple register t2 at index i and the target is t1.
    472 func (b *builder) extract(e *ssa.Extract) {
    473 	tup := e.Tuple.Type().(*types.Tuple)
    474 	t := tup.At(e.Index).Type()
    475 
    476 	local := indexedLocal{val: e.Tuple, typ: t, index: e.Index}
    477 	b.addInFlowAliasEdges(b.nodeFromVal(e), local)
    478 }
    479 
    480 func (b *builder) field(f *ssa.Field) {
    481 	fnode := field{StructType: f.X.Type(), index: f.Field}
    482 	b.addInFlowEdge(fnode, b.nodeFromVal(f))
    483 }
    484 
    485 func (b *builder) fieldAddr(f *ssa.FieldAddr) {
    486 	t := typeparams.CoreType(f.X.Type()).(*types.Pointer).Elem()
    487 
    488 	// Since we are getting pointer to a field, make a bidirectional edge.
    489 	fnode := field{StructType: t, index: f.Field}
    490 	b.addInFlowEdge(fnode, b.nodeFromVal(f))
    491 	b.addInFlowEdge(b.nodeFromVal(f), fnode)
    492 }
    493 
    494 func (b *builder) send(s *ssa.Send) {
    495 	t := typeparams.CoreType(s.Chan.Type()).(*types.Chan).Elem()
    496 	b.addInFlowAliasEdges(channelElem{typ: t}, b.nodeFromVal(s.X))
    497 }
    498 
    499 // selekt generates flows for select statement
    500 //
    501 //	a = select blocking/nonblocking [c_1 <- t_1, c_2 <- t_2, ..., <- o_1, <- o_2, ...]
    502 //
    503 // between receiving channel registers c_i and corresponding input register t_i. Further,
    504 // flows are generated between o_i and a[2 + i]. Note that a is a tuple register of type
    505 // <int, bool, r_1, r_2, ...> where the type of r_i is the element type of channel o_i.
    506 func (b *builder) selekt(s *ssa.Select) {
    507 	recvIndex := 0
    508 	for _, state := range s.States {
    509 		t := typeparams.CoreType(state.Chan.Type()).(*types.Chan).Elem()
    510 
    511 		if state.Dir == types.SendOnly {
    512 			b.addInFlowAliasEdges(channelElem{typ: t}, b.nodeFromVal(state.Send))
    513 		} else {
    514 			// state.Dir == RecvOnly by definition of select instructions.
    515 			tupEntry := indexedLocal{val: s, typ: t, index: 2 + recvIndex}
    516 			b.addInFlowAliasEdges(tupEntry, channelElem{typ: t})
    517 			recvIndex++
    518 		}
    519 	}
    520 }
    521 
    522 // index instruction a := b[c] on slices creates flows between a and
    523 // SliceElem(t) flow where t is an interface type of c. Arrays and
    524 // slice elements are both modeled as SliceElem.
    525 func (b *builder) index(i *ssa.Index) {
    526 	et := sliceArrayElem(i.X.Type())
    527 	b.addInFlowAliasEdges(b.nodeFromVal(i), sliceElem{typ: et})
    528 }
    529 
    530 // indexAddr instruction a := &b[c] fetches address of a index
    531 // into the field so we create bidirectional flow a <-> SliceElem(t)
    532 // where t is an interface type of c. Arrays and slice elements are
    533 // both modeled as SliceElem.
    534 func (b *builder) indexAddr(i *ssa.IndexAddr) {
    535 	et := sliceArrayElem(i.X.Type())
    536 	b.addInFlowEdge(sliceElem{typ: et}, b.nodeFromVal(i))
    537 	b.addInFlowEdge(b.nodeFromVal(i), sliceElem{typ: et})
    538 }
    539 
    540 // lookup handles map query commands a := m[b] where m is of type
    541 // map[...]V and V is an interface. It creates flows between `a`
    542 // and MapValue(V).
    543 func (b *builder) lookup(l *ssa.Lookup) {
    544 	t, ok := l.X.Type().Underlying().(*types.Map)
    545 	if !ok {
    546 		// No interesting flows for string lookups.
    547 		return
    548 	}
    549 
    550 	if !l.CommaOk {
    551 		b.addInFlowAliasEdges(b.nodeFromVal(l), mapValue{typ: t.Elem()})
    552 	} else {
    553 		i := indexedLocal{val: l, typ: t.Elem(), index: 0}
    554 		b.addInFlowAliasEdges(i, mapValue{typ: t.Elem()})
    555 	}
    556 }
    557 
    558 // mapUpdate handles map update commands m[b] = a where m is of type
    559 // map[K]V and K and V are interfaces. It creates flows between `a`
    560 // and MapValue(V) as well as between MapKey(K) and `b`.
    561 func (b *builder) mapUpdate(u *ssa.MapUpdate) {
    562 	t, ok := u.Map.Type().Underlying().(*types.Map)
    563 	if !ok {
    564 		// No interesting flows for string updates.
    565 		return
    566 	}
    567 
    568 	b.addInFlowAliasEdges(mapKey{typ: t.Key()}, b.nodeFromVal(u.Key))
    569 	b.addInFlowAliasEdges(mapValue{typ: t.Elem()}, b.nodeFromVal(u.Value))
    570 }
    571 
    572 // next instruction <ok, key, value> := next r, where r
    573 // is a range over map or string generates flow between
    574 // key and MapKey as well value and MapValue nodes.
    575 func (b *builder) next(n *ssa.Next) {
    576 	if n.IsString {
    577 		return
    578 	}
    579 	tup := n.Type().(*types.Tuple)
    580 	kt := tup.At(1).Type()
    581 	vt := tup.At(2).Type()
    582 
    583 	b.addInFlowAliasEdges(indexedLocal{val: n, typ: kt, index: 1}, mapKey{typ: kt})
    584 	b.addInFlowAliasEdges(indexedLocal{val: n, typ: vt, index: 2}, mapValue{typ: vt})
    585 }
    586 
    587 // addInFlowAliasEdges adds an edge r -> l to b.graph if l is a node that can
    588 // have an inflow, i.e., a node that represents an interface or an unresolved
    589 // function value. Similarly for the edge l -> r with an additional condition
    590 // of that l and r can potentially alias.
    591 func (b *builder) addInFlowAliasEdges(l, r node) {
    592 	b.addInFlowEdge(r, l)
    593 
    594 	if canAlias(l, r) {
    595 		b.addInFlowEdge(l, r)
    596 	}
    597 }
    598 
    599 func (b *builder) closure(c *ssa.MakeClosure) {
    600 	f := c.Fn.(*ssa.Function)
    601 	b.addInFlowEdge(function{f: f}, b.nodeFromVal(c))
    602 
    603 	for i, fv := range f.FreeVars {
    604 		b.addInFlowAliasEdges(b.nodeFromVal(fv), b.nodeFromVal(c.Bindings[i]))
    605 	}
    606 }
    607 
    608 // panic creates a flow from arguments to panic instructions to return
    609 // registers of all recover statements in the program. Introduces a
    610 // global panic node Panic and
    611 //  1. for every panic statement p: add p -> Panic
    612 //  2. for every recover statement r: add Panic -> r (handled in call)
    613 //
    614 // TODO(zpavlinovic): improve precision by explicitly modeling how panic
    615 // values flow from callees to callers and into deferred recover instructions.
    616 func (b *builder) panic(p *ssa.Panic) {
    617 	// Panics often have, for instance, strings as arguments which do
    618 	// not create interesting flows.
    619 	if !canHaveMethods(p.X.Type()) {
    620 		return
    621 	}
    622 
    623 	b.addInFlowEdge(b.nodeFromVal(p.X), panicArg{})
    624 }
    625 
    626 // call adds flows between arguments/parameters and return values/registers
    627 // for both static and dynamic calls, as well as go and defer calls.
    628 func (b *builder) call(c ssa.CallInstruction) {
    629 	// When c is r := recover() call register instruction, we add Recover -> r.
    630 	if bf, ok := c.Common().Value.(*ssa.Builtin); ok && bf.Name() == "recover" {
    631 		if v, ok := c.(ssa.Value); ok {
    632 			b.addInFlowEdge(recoverReturn{}, b.nodeFromVal(v))
    633 		}
    634 		return
    635 	}
    636 
    637 	for f := range siteCallees(c, b.callees) {
    638 		addArgumentFlows(b, c, f)
    639 
    640 		site, ok := c.(ssa.Value)
    641 		if !ok {
    642 			continue // go or defer
    643 		}
    644 
    645 		results := f.Signature.Results()
    646 		if results.Len() == 1 {
    647 			// When there is only one return value, the destination register does not
    648 			// have a tuple type.
    649 			b.addInFlowEdge(resultVar{f: f, index: 0}, b.nodeFromVal(site))
    650 		} else {
    651 			tup := site.Type().(*types.Tuple)
    652 			for i := 0; i < results.Len(); i++ {
    653 				local := indexedLocal{val: site, typ: tup.At(i).Type(), index: i}
    654 				b.addInFlowEdge(resultVar{f: f, index: i}, local)
    655 			}
    656 		}
    657 	}
    658 }
    659 
    660 func addArgumentFlows(b *builder, c ssa.CallInstruction, f *ssa.Function) {
    661 	// When f has no parameters (including receiver), there is no type
    662 	// flow here. Also, f's body and parameters might be missing, such
    663 	// as when vta is used within the golang.org/x/tools/go/analysis
    664 	// framework (see github.com/golang/go/issues/50670).
    665 	if len(f.Params) == 0 {
    666 		return
    667 	}
    668 	cc := c.Common()
    669 	if cc.Method != nil {
    670 		// In principle we don't add interprocedural flows for receiver
    671 		// objects. At a call site, the receiver object is interface
    672 		// while the callee object is concrete. The flow from interface
    673 		// to concrete type in general does not make sense. The exception
    674 		// is when the concrete type is a named function type (see #57756).
    675 		//
    676 		// The flow other way around would bake in information from the
    677 		// initial call graph.
    678 		if isFunction(f.Params[0].Type()) {
    679 			b.addInFlowEdge(b.nodeFromVal(cc.Value), b.nodeFromVal(f.Params[0]))
    680 		}
    681 	}
    682 
    683 	offset := 0
    684 	if cc.Method != nil {
    685 		offset = 1
    686 	}
    687 	for i, v := range cc.Args {
    688 		// Parameters of f might not be available, as in the case
    689 		// when vta is used within the golang.org/x/tools/go/analysis
    690 		// framework (see github.com/golang/go/issues/50670).
    691 		//
    692 		// TODO: investigate other cases of missing body and parameters
    693 		if len(f.Params) <= i+offset {
    694 			return
    695 		}
    696 		b.addInFlowAliasEdges(b.nodeFromVal(f.Params[i+offset]), b.nodeFromVal(v))
    697 	}
    698 }
    699 
    700 // rtrn creates flow edges from the operands of the return
    701 // statement to the result variables of the enclosing function.
    702 func (b *builder) rtrn(r *ssa.Return) {
    703 	for i, rs := range r.Results {
    704 		b.addInFlowEdge(b.nodeFromVal(rs), resultVar{f: r.Parent(), index: i})
    705 	}
    706 }
    707 
    708 func (b *builder) multiconvert(c *ssa.MultiConvert) {
    709 	// TODO(zpavlinovic): decide what to do on MultiConvert long term.
    710 	// TODO(zpavlinovic): add unit tests.
    711 	typeSetOf := func(typ types.Type) []*types.Term {
    712 		// This is a adaptation of x/exp/typeparams.NormalTerms which x/tools cannot depend on.
    713 		var terms []*types.Term
    714 		var err error
    715 		switch typ := types.Unalias(typ).(type) {
    716 		case *types.TypeParam:
    717 			terms, err = typeparams.StructuralTerms(typ)
    718 		case *types.Union:
    719 			terms, err = typeparams.UnionTermSet(typ)
    720 		case *types.Interface:
    721 			terms, err = typeparams.InterfaceTermSet(typ)
    722 		default:
    723 			// Common case.
    724 			// Specializing the len=1 case to avoid a slice
    725 			// had no measurable space/time benefit.
    726 			terms = []*types.Term{types.NewTerm(false, typ)}
    727 		}
    728 
    729 		if err != nil {
    730 			return nil
    731 		}
    732 		return terms
    733 	}
    734 	// isValuePreserving returns true if a conversion from ut_src to
    735 	// ut_dst is value-preserving, i.e. just a change of type.
    736 	// Precondition: neither argument is a named or alias type.
    737 	isValuePreserving := func(ut_src, ut_dst types.Type) bool {
    738 		// Identical underlying types?
    739 		if types.IdenticalIgnoreTags(ut_dst, ut_src) {
    740 			return true
    741 		}
    742 
    743 		switch ut_dst.(type) {
    744 		case *types.Chan:
    745 			// Conversion between channel types?
    746 			_, ok := ut_src.(*types.Chan)
    747 			return ok
    748 
    749 		case *types.Pointer:
    750 			// Conversion between pointers with identical base types?
    751 			_, ok := ut_src.(*types.Pointer)
    752 			return ok
    753 		}
    754 		return false
    755 	}
    756 	dst_terms := typeSetOf(c.Type())
    757 	src_terms := typeSetOf(c.X.Type())
    758 	for _, s := range src_terms {
    759 		us := s.Type().Underlying()
    760 		for _, d := range dst_terms {
    761 			ud := d.Type().Underlying()
    762 			if isValuePreserving(us, ud) {
    763 				// This is equivalent to a ChangeType.
    764 				b.addInFlowAliasEdges(b.nodeFromVal(c), b.nodeFromVal(c.X))
    765 				return
    766 			}
    767 			// This is equivalent to either: SliceToArrayPointer,,
    768 			// SliceToArrayPointer+Deref, Size 0 Array constant, or a Convert.
    769 		}
    770 	}
    771 }
    772 
    773 // addInFlowEdge adds s -> d to g if d is node that can have an inflow, i.e., a node
    774 // that represents an interface or an unresolved function value. Otherwise, there
    775 // is no interesting type flow so the edge is omitted.
    776 func (b *builder) addInFlowEdge(s, d node) {
    777 	if hasInFlow(d) {
    778 		b.graph.addEdge(b.representative(s), b.representative(d))
    779 	}
    780 }
    781 
    782 // Creates const, pointer, global, func, and local nodes based on register instructions.
    783 func (b *builder) nodeFromVal(val ssa.Value) node {
    784 	if p, ok := types.Unalias(val.Type()).(*types.Pointer); ok && !types.IsInterface(p.Elem()) && !isFunction(p.Elem()) {
    785 		// Nested pointer to interfaces are modeled as a special
    786 		// nestedPtrInterface node.
    787 		if i := interfaceUnderPtr(p.Elem()); i != nil {
    788 			return nestedPtrInterface{typ: i}
    789 		}
    790 		// The same goes for nested function types.
    791 		if f := functionUnderPtr(p.Elem()); f != nil {
    792 			return nestedPtrFunction{typ: f}
    793 		}
    794 		return pointer{typ: p}
    795 	}
    796 
    797 	switch v := val.(type) {
    798 	case *ssa.Const:
    799 		return constant{typ: val.Type()}
    800 	case *ssa.Global:
    801 		return global{val: v}
    802 	case *ssa.Function:
    803 		return function{f: v}
    804 	case *ssa.Parameter, *ssa.FreeVar, ssa.Instruction:
    805 		// ssa.Param, ssa.FreeVar, and a specific set of "register" instructions,
    806 		// satisfying the ssa.Value interface, can serve as local variables.
    807 		return local{val: v}
    808 	default:
    809 		panic(fmt.Errorf("unsupported value %v in node creation", val))
    810 	}
    811 }
    812 
    813 // representative returns a unique representative for node `n`. Since
    814 // semantically equivalent types can have different implementations,
    815 // this method guarantees the same implementation is always used.
    816 func (b *builder) representative(n node) node {
    817 	if n.Type() == nil {
    818 		// panicArg and recoverReturn do not have
    819 		// types and are unique by definition.
    820 		return n
    821 	}
    822 	t := canonicalize(n.Type(), &b.canon)
    823 
    824 	switch i := n.(type) {
    825 	case constant:
    826 		return constant{typ: t}
    827 	case pointer:
    828 		return pointer{typ: t.(*types.Pointer)}
    829 	case sliceElem:
    830 		return sliceElem{typ: t}
    831 	case mapKey:
    832 		return mapKey{typ: t}
    833 	case mapValue:
    834 		return mapValue{typ: t}
    835 	case channelElem:
    836 		return channelElem{typ: t}
    837 	case nestedPtrInterface:
    838 		return nestedPtrInterface{typ: t}
    839 	case nestedPtrFunction:
    840 		return nestedPtrFunction{typ: t}
    841 	case field:
    842 		return field{StructType: canonicalize(i.StructType, &b.canon), index: i.index}
    843 	case indexedLocal:
    844 		return indexedLocal{typ: t, val: i.val, index: i.index}
    845 	case local, global, panicArg, recoverReturn, function, resultVar:
    846 		return n
    847 	default:
    848 		panic(fmt.Errorf("canonicalizing unrecognized node %v", n))
    849 	}
    850 }
    851 
    852 // canonicalize returns a type representative of `t` unique subject
    853 // to type map `canon`.
    854 func canonicalize(t types.Type, canon *typeutil.Map) types.Type {
    855 	rep := canon.At(t)
    856 	if rep != nil {
    857 		return rep.(types.Type)
    858 	}
    859 	canon.Set(t, t)
    860 	return t
    861 }