Example #1
0
// describePointer runs the pointer analysis of the selected SSA value.
func describePointer(o *Oracle, v ssa.Value, indirect bool) (ptrs []pointerResult, err error) {
	buildSSA(o)

	// TODO(adonovan): don't run indirect pointer analysis on non-ptr-ptrlike types.
	o.config.Queries = map[ssa.Value]pointer.Indirect{v: pointer.Indirect(indirect)}
	ptares := ptrAnalysis(o)

	// Combine the PT sets from all contexts.
	pointers := ptares.Queries[v]
	if pointers == nil {
		return nil, fmt.Errorf("PTA did not encounter this expression (dead code?)")
	}
	pts := pointer.PointsToCombined(pointers)

	if pointer.CanHaveDynamicTypes(v.Type()) {
		// Show concrete types for interface/reflect.Value expression.
		if concs := pts.DynamicTypes(); concs.Len() > 0 {
			concs.Iterate(func(conc types.Type, pta interface{}) {
				combined := pointer.PointsToCombined(pta.([]pointer.Pointer))
				labels := combined.Labels()
				sort.Sort(byPosAndString(labels)) // to ensure determinism
				ptrs = append(ptrs, pointerResult{conc, labels})
			})
		}
	} else {
		// Show labels for other expressions.
		labels := pts.Labels()
		sort.Sort(byPosAndString(labels)) // to ensure determinism
		ptrs = append(ptrs, pointerResult{v.Type(), labels})
	}
	sort.Sort(byTypeString(ptrs)) // to ensure determinism
	return ptrs, nil
}
// runPTA runs the pointer analysis of the selected SSA value or address.
func runPTA(o *Oracle, v ssa.Value, isAddr bool) (ptrs []pointerResult, err error) {
	buildSSA(o)

	if isAddr {
		o.ptaConfig.AddIndirectQuery(v)
	} else {
		o.ptaConfig.AddQuery(v)
	}
	ptares := ptrAnalysis(o)

	// Combine the PT sets from all contexts.
	var pointers []pointer.Pointer
	if isAddr {
		pointers = ptares.IndirectQueries[v]
	} else {
		pointers = ptares.Queries[v]
	}
	if pointers == nil {
		return nil, fmt.Errorf("pointer analysis did not find expression (dead code?)")
	}
	pts := pointer.PointsToCombined(pointers)

	if pointer.CanHaveDynamicTypes(v.Type()) {
		// Show concrete types for interface/reflect.Value expression.
		if concs := pts.DynamicTypes(); concs.Len() > 0 {
			concs.Iterate(func(conc types.Type, pta interface{}) {
				combined := pointer.PointsToCombined(pta.([]pointer.Pointer))
				labels := combined.Labels()
				sort.Sort(byPosAndString(labels)) // to ensure determinism
				ptrs = append(ptrs, pointerResult{conc, labels})
			})
		}
	} else {
		// Show labels for other expressions.
		labels := pts.Labels()
		sort.Sort(byPosAndString(labels)) // to ensure determinism
		ptrs = append(ptrs, pointerResult{v.Type(), labels})
	}
	sort.Sort(byTypeString(ptrs)) // to ensure determinism
	return ptrs, nil
}
Example #3
0
// peers enumerates, for a given channel send (or receive) operation,
// the set of possible receives (or sends) that correspond to it.
//
// TODO(adonovan): support reflect.{Select,Recv,Send}.
// TODO(adonovan): permit the user to query based on a MakeChan (not send/recv),
// or the implicit receive in "for v := range ch".
//
func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
	arrowPos := findArrow(qpos)
	if arrowPos == token.NoPos {
		return nil, fmt.Errorf("there is no send/receive here")
	}

	buildSSA(o)

	var queryOp chanOp // the originating send or receive operation
	var ops []chanOp   // all sends/receives of opposite direction

	// Look at all send/receive instructions in the whole ssa.Program.
	// Build a list of those of same type to query.
	allFuncs := ssautil.AllFunctions(o.prog)
	for fn := range allFuncs {
		for _, b := range fn.Blocks {
			for _, instr := range b.Instrs {
				for _, op := range chanOps(instr) {
					ops = append(ops, op)
					if op.pos == arrowPos {
						queryOp = op // we found the query op
					}
				}
			}
		}
	}
	if queryOp.ch == nil {
		return nil, fmt.Errorf("ssa.Instruction for send/receive not found")
	}

	// Discard operations of wrong channel element type.
	// Build set of channel ssa.Values as query to pointer analysis.
	// We compare channels by element types, not channel types, to
	// ignore both directionality and type names.
	queryType := queryOp.ch.Type()
	queryElemType := queryType.Underlying().(*types.Chan).Elem()
	o.ptaConfig.AddQuery(queryOp.ch)
	i := 0
	for _, op := range ops {
		if types.IsIdentical(op.ch.Type().Underlying().(*types.Chan).Elem(), queryElemType) {
			o.ptaConfig.AddQuery(op.ch)
			ops[i] = op
			i++
		}
	}
	ops = ops[:i]

	// Run the pointer analysis.
	ptares := ptrAnalysis(o)

	// Combine the PT sets from all contexts.
	queryChanPts := pointer.PointsToCombined(ptares.Queries[queryOp.ch])

	// Ascertain which make(chan) labels the query's channel can alias.
	var makes []token.Pos
	for _, label := range queryChanPts.Labels() {
		makes = append(makes, label.Pos())
	}
	sort.Sort(byPos(makes))

	// Ascertain which send/receive operations can alias the same make(chan) labels.
	var sends, receives []token.Pos
	for _, op := range ops {
		for _, ptr := range ptares.Queries[op.ch] {
			if ptr.PointsTo().Intersects(queryChanPts) {
				if op.dir == types.SendOnly {
					sends = append(sends, op.pos)
				} else {
					receives = append(receives, op.pos)
				}
			}
		}
	}
	sort.Sort(byPos(sends))
	sort.Sort(byPos(receives))

	return &peersResult{
		queryPos:  arrowPos,
		queryType: queryType,
		makes:     makes,
		sends:     sends,
		receives:  receives,
	}, nil
}