Python points-to: Bring attribute points-to to effective parity with old points-to.

This commit is contained in:
Mark Shannon
2019-04-15 18:14:32 +01:00
parent 2e6c3c9ee3
commit cd34e23c4c
5 changed files with 120 additions and 42 deletions

View File

@@ -198,7 +198,7 @@ class FloatObjectInternal extends ConstantObjectInternal, TFloat {
override string toString() {
if this.floatValue() = this.floatValue().floor() then (
result = "float " + this.floatValue().toString() + ".0"
result = "float " + this.floatValue().floor().toString() + ".0"
) else (
result = "float " + this.floatValue().toString()
)

View File

@@ -79,6 +79,18 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
PointsToInternal::attributeRequired(this, name) and
instance_getattr(this, Types::getMro(this.getClass()), name, value, origin)
or
exists(EssaVariable self, PythonFunctionObjectInternal init, Context callee |
BaseFlow::reaches_exit(self) and
self.getSourceVariable().(Variable).isSelf() and
self.getScope() = init.getScope() and
exists(CallNode call, Context caller, ClassObjectInternal cls |
this = TSpecificInstance(call, cls, caller) and
callee.fromCall(this.getOrigin(), caller) and
cls.lookup("__init__", init, _)
) and
AttributePointsTo::variableAttributePointsTo(self, callee, name, value, origin)
)
}
override predicate attributesUnknown() { any() }

View File

@@ -366,21 +366,9 @@ module ObjectInternal {
}
ObjectInternal fromBuiltin(Builtin b) {
result = TInt(b.intValue())
or
result = TString(b.strValue())
or
result = TBuiltinClassObject(b)
or
result = TBuiltinFunctionObject(b)
or
result = TBuiltinOpaqueObject(b)
or
result = TBuiltinModuleObject(b)
or
result = TBuiltinMethodObject(b)
or
result = TBuiltinTuple(b)
b = result.getBuiltin() and
not b = Builtin::unknown() and
not b = Builtin::unknownType()
}
ObjectInternal classMethod() {

View File

@@ -131,8 +131,9 @@ newtype TObject =
PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _)
}
or
TDynamicClass(ControlFlowNode instantiation, ClassObjectInternal metacls, PointsToContext context) {
PointsToInternal::pointsTo(instantiation.(CallNode).getFunction(), context, metacls, _) and
TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) {
PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and
not count(instantiation.getAnArg()) = 1 and
Types::getMro(metacls).contains(TType())
}

View File

@@ -126,7 +126,7 @@ module PointsTo {
deprecated predicate
points_to(ControlFlowNode f, PointsToContext context, Object obj, ClassObject cls, ControlFlowNode origin) {
exists(Value value |
pointsToValue(f, context, value, origin) and
PointsToInternal::pointsTo(f, context, value, origin) and
cls = value.getClass().getSource() |
obj = value.getSource() or
not exists(value.getSource()) and obj = origin
@@ -148,14 +148,6 @@ module PointsTo {
)
}
private predicate pointsToValue(ControlFlowNode f, PointsToContext context, Value value, ControlFlowNode origin) {
PointsToInternal::pointsTo(f, context, value, origin)
or
exists(string name |
AttributePointsTo::attributePointsTo(f.(AttrNode).getObject(name), context, name, value, origin)
)
}
deprecated predicate
ssa_variable_points_to(EssaVariable var, PointsToContext context, Object obj, ClassObject cls, CfgOrigin origin) {
exists(Value value |
@@ -199,6 +191,8 @@ cached module PointsToInternal {
InterModulePointsTo::from_import_points_to(f, context, value, origin)
or
InterProceduralPointsTo::call_points_to(f, context, value, origin)
or
AttributePointsTo::pointsTo(f, context, value, origin)
// To do... More stuff here :)
// or
// f.(CustomPointsToFact).pointsTo(context, value, origin)
@@ -1135,8 +1129,10 @@ module Expressions {
private boolean otherComparisonEvaluatesTo(CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue) {
exists(Cmpop op |
comp.operands(operand, op, _) and
(op instanceof In or op instanceof NotIn) |
comp.operands(operand, op, _) or
comp.operands(_, op, operand)
|
(op instanceof In or op instanceof NotIn) and
PointsToInternal::pointsTo(operand, context, opvalue, _)
) and result = maybe()
}
@@ -1694,19 +1690,100 @@ cached module Types {
module AttributePointsTo {
predicate attributePointsTo(ControlFlowNode f, Context context, string name, ObjectInternal value, ControlFlowNode origin) {
exists(ObjectInternal defobj, Context prev, AttributeAssignment def, ObjectInternal useobj |
PointsToInternal::pointsTo(f, context, useobj, _) and
PointsToInternal::variablePointsTo(def.getInput(), prev, defobj, _) and
PointsToInternal::pointsTo(def.getValue(), prev, value, origin) and name = def.getName()
|
prev.getOuter*().getCall().getBasicBlock().reaches(context.getOuter*().getCall().getBasicBlock()) and
useobj.(SelfInstanceInternal).getClass() = defobj.(SelfInstanceInternal).getClass()
or
def.getScope().getScope*().precedes(f.getScope().getScope*()) and
useobj.(SelfInstanceInternal).getClass() = defobj.(SelfInstanceInternal).getClass()
or
def.getDefiningNode().getBasicBlock().dominates(f.getBasicBlock()) and defobj = useobj
predicate pointsTo(AttrNode f, Context context, ObjectInternal value, ControlFlowNode origin) {
exists(EssaVariable var, string name, CfgOrigin orig |
var.getASourceUse() = f.getObject(name) and
variableAttributePointsTo(var, context, name, value, orig) and
origin = orig.asCfgNodeOrHere(f)
)
}
predicate variableAttributePointsTo(EssaVariable var, Context context, string name, ObjectInternal value, CfgOrigin origin) {
definitionAttributePointsTo(var.getDefinition(), context, name, value, origin)
or
exists(EssaVariable prev |
var.getDefinition().(PhiFunction).getShortCircuitInput() = prev and
variableAttributePointsTo(prev, context, name, value, origin)
)
}
predicate definitionAttributePointsTo(EssaDefinition def, Context context, string name, ObjectInternal value, CfgOrigin origin) {
variableAttributePointsTo(def.(PhiFunction).getAnInput(), context, name, value, origin)
or
piNodeAttributePointsTo(def, context, name, value, origin)
or
refinementAttributePointsTo(def, context, name, value, origin)
or
selfParameterAttributePointsTo(def, context, name, value, origin)
or
selfMethodCallsitePointsTo(def, context, name, value, origin)
}
pragma [noinline]
private predicate refinementAttributePointsTo(EssaNodeRefinement def, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
attributeAssignmentAttributePointsTo(def, context, name, value, origin)
or
attributeDeleteAttributePointsTo(def, context, name, value, origin)
or
uniEdgedPhiAttributePointsTo(def, context, name, value, origin)
}
/** Attribute deletions have no effect as far as value tracking is concerned. */
pragma [noinline]
private predicate attributeAssignmentAttributePointsTo(AttributeAssignment def, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
def.getName() != name and
variableAttributePointsTo(def.getInput(), context, name, value, origin)
or
def.getName() = name and
exists(ControlFlowNode cfgnode |
PointsToInternal::pointsTo(def.getValue(), context, value, cfgnode) and
origin = CfgOrigin::fromCfgNode(cfgnode)
)
}
/** Attribute deletions have no effect as far as value tracking is concerned. */
pragma [noinline]
private predicate attributeDeleteAttributePointsTo(EssaAttributeDeletion def, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
def.getName() != name and
variableAttributePointsTo(def.getInput(), context, name, value, origin)
}
private predicate uniEdgedPhiAttributePointsTo(SingleSuccessorGuard uniphi, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
variableAttributePointsTo(uniphi.getInput(), context, name, value, origin)
}
private predicate piNodeAttributePointsTo(PyEdgeRefinement pi, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
variableAttributePointsTo(pi.getInput(), context, name, value, origin)
}
private predicate selfParameterAttributePointsTo(ParameterDefinition def, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
exists(MethodCallsiteRefinement call, Function func, PointsToContext caller |
selfMethodCall(call, caller, func, context) and
def.isSelf() and def.getScope() = func and
variableAttributePointsTo(call.getInput(), caller, name, value, origin)
)
}
/** Pass through for `self` for the implicit re-definition of `self` in `self.foo()`. */
private predicate selfMethodCallsitePointsTo(MethodCallsiteRefinement def, PointsToContext context, string name, ObjectInternal value, CfgOrigin origin) {
/* The value of self remains the same, only the attributes may change */
exists(Function func, PointsToContext callee, EssaVariable exit_self |
selfMethodCall(def, context, func, callee) and
exit_self.getSourceVariable().(Variable).isSelf() and
exit_self.getScope() = func and
BaseFlow::reaches_exit(exit_self) and
variableAttributePointsTo(exit_self, context, name, value, origin)
)
}
private predicate selfMethodCall(MethodCallsiteRefinement def, PointsToContext caller, Function func, PointsToContext callee) {
def.getInput().getSourceVariable().(Variable).isSelf() and
exists(PythonFunctionObjectInternal method, CallNode call |
method.getScope() = func and
call = method.getACall() and
call = def.getDefiningNode() and
callee.fromCall(call, caller)
)
}