func (r *pointstoResult) display(printf printfFunc) { if pointer.CanHaveDynamicTypes(r.typ) { // Show concrete types for interface, reflect.Type or // reflect.Value expression. if len(r.ptrs) > 0 { printf(r.qpos, "this %s may contain these dynamic types:", r.qpos.TypeString(r.typ)) for _, ptr := range r.ptrs { var obj types.Object if nt, ok := deref(ptr.typ).(*types.Named); ok { obj = nt.Obj() } if len(ptr.labels) > 0 { printf(obj, "\t%s, may point to:", r.qpos.TypeString(ptr.typ)) printLabels(printf, ptr.labels, "\t\t") } else { printf(obj, "\t%s", r.qpos.TypeString(ptr.typ)) } } } else { printf(r.qpos, "this %s cannot contain any dynamic types.", r.typ) } } else { // Show labels for other expressions. if ptr := r.ptrs[0]; len(ptr.labels) > 0 { printf(r.qpos, "this %s may point to these objects:", r.qpos.TypeString(r.typ)) printLabels(printf, ptr.labels, "\t") } else { printf(r.qpos, "this %s may not point to anything.", r.qpos.TypeString(r.typ)) } } }
// 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 }
func checkTypesExpectation(e *expectation, pr *probe) bool { var expected typemap.M var surplus typemap.M exact := true for _, g := range e.types { if g == types.Typ[types.Invalid] { exact = false continue } expected.Set(g, struct{}{}) } if t := pr.instr.Args[0].Type(); !pointer.CanHaveDynamicTypes(t) { e.errorf("@types expectation requires an interface- or reflect.Value-typed operand, got %s", t) return false } // Find the set of types that the probe's // argument (x in print(x)) may contain. for _, T := range pr.arg0.PointsTo().DynamicTypes().Keys() { if expected.At(T) != nil { expected.Delete(T) } else if exact { surplus.Set(T, struct{}{}) } } // Report set difference: ok := true if expected.Len() > 0 { ok = false e.errorf("interface cannot contain these types: %s", expected.KeysString()) } if surplus.Len() > 0 { ok = false e.errorf("interface may additionally contain these types: %s", surplus.KeysString()) } return ok }
func (r *describeValueResult) display(printf printfFunc) { var prefix, suffix string if r.constVal != nil { suffix = fmt.Sprintf(" of constant value %s", r.constVal) } switch obj := r.obj.(type) { case *types.Func: if recv := obj.Type().(*types.Signature).Recv(); recv != nil { if _, ok := recv.Type().Underlying().(*types.Interface); ok { prefix = "interface method " } else { prefix = "method " } } case *types.Var: // TODO(adonovan): go/types should make it simple to // ask: IsStructField(*Var)? if false { prefix = "struct field " } } // Describe the expression. if r.obj != nil { if r.obj.Pos() == r.expr.Pos() { // defining ident printf(r.expr, "definition of %s%s%s", prefix, r.obj, suffix) } else { // referring ident printf(r.expr, "reference to %s%s%s", prefix, r.obj, suffix) if def := r.obj.Pos(); def != token.NoPos { printf(def, "defined here") } } } else { desc := importer.NodeDescription(r.expr) if suffix != "" { // constant expression printf(r.expr, "%s%s", desc, suffix) } else { // non-constant expression printf(r.expr, "%s of type %s", desc, r.typ) } } // pointer analysis could not be run if r.ptaErr != nil { printf(r.expr, "no points-to information: %s", r.ptaErr) return } if r.ptrs == nil { return // PTA was not invoked (not an error) } // Display the results of pointer analysis. if pointer.CanHaveDynamicTypes(r.typ) { // Show concrete types for interface, reflect.Type or // reflect.Value expression. if len(r.ptrs) > 0 { printf(r.qpos, "this %s may contain these dynamic types:", r.typ) for _, ptr := range r.ptrs { var obj types.Object if nt, ok := deref(ptr.typ).(*types.Named); ok { obj = nt.Obj() } if len(ptr.labels) > 0 { printf(obj, "\t%s, may point to:", ptr.typ) printLabels(printf, ptr.labels, "\t\t") } else { printf(obj, "\t%s", ptr.typ) } } } else { printf(r.qpos, "this %s cannot contain any dynamic types.", r.typ) } } else { // Show labels for other expressions. if ptr := r.ptrs[0]; len(ptr.labels) > 0 { printf(r.qpos, "value may point to these labels:") printLabels(printf, ptr.labels, "\t") } else { printf(r.qpos, "value cannot point to anything.") } } }