// 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 }
// 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 }