Python points-to: Use strongly typed version of CfgOrigin.

This commit is contained in:
Mark Shannon
2019-04-04 10:51:28 +01:00
parent 162bf5143b
commit 31a95ceeec
7 changed files with 100 additions and 84 deletions

View File

@@ -82,11 +82,12 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
pragma [noinline]
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
exists(Function func, ControlFlowNode rval |
exists(Function func, ControlFlowNode rval, ControlFlowNode forigin |
func = this.getScope() and
callee.appliesToScope(func) |
rval = func.getAReturnValueFlowNode() and
PointsToInternal::pointsTo(rval, callee, obj, origin)
PointsToInternal::pointsTo(rval, callee, obj, forigin) and
origin = CfgOrigin::fromCfgNode(forigin)
or
PointsToInternal::reachableBlock(blockReturningNone(func), callee) and
obj = ObjectInternal::none_() and
@@ -98,7 +99,7 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
this.getScope().isProcedure() and
obj = ObjectInternal::none_() and
origin = this.getScope().getEntryNode()
origin = CfgOrigin::fromCfgNode(this.getScope().getEntryNode())
}
override predicate calleeAndOffset(Function scope, int paramOffset) {

View File

@@ -143,7 +143,7 @@ class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObjec
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and
value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and
origin = CfgOrigin::unknown()
}

View File

@@ -159,21 +159,21 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
not exists(EssaVariable var | var.getAUse() = init.getANormalExit() and var.getSourceVariable().getName() = name) and
ModuleAttributes::pointsToAtExit(init, name, ObjectInternal::undefined(), _) and
value = this.submodule(name) and
origin = CfgOrigin::fromModule(value)
origin = CfgOrigin::fromObject(value)
)
or
this.hasNoInitModule() and
exists(ModuleObjectInternal mod |
mod = this.submodule(name) and
value = mod |
origin = CfgOrigin::fromModule(mod)
origin = CfgOrigin::fromObject(mod)
)
}
override predicate attributesUnknown() { none() }
override ControlFlowNode getOrigin() {
none()
result = this.getSourceModule().getEntryNode()
}
}

View File

@@ -77,9 +77,9 @@ class ObjectInternal extends TObject {
abstract predicate attributesUnknown();
/** For backwards compatibility shim -- Not all objects have a "source"
/** For backwards compatibility shim -- Not all objects have a "source".
* Objects (except unknown and undefined values) should attempt to return
* exactly one result for either this method`.
* exactly one result for this method.
* */
@py_object getSource() {
result = this.getOrigin()

View File

@@ -8,44 +8,7 @@ private import semmle.python.pointsto.MRO2
private import semmle.python.types.Builtins
/* Use this version for speed */
library class CfgOrigin extends @py_object {
string toString() {
/* Not to be displayed */
none()
}
/** Get a `ControlFlowNode` from `this` or `here`.
* If `this` is a ControlFlowNode then use that, otherwise fall back on `here`
*/
pragma[inline]
ControlFlowNode asCfgNodeOrHere(ControlFlowNode here) {
result = this
or
not this instanceof ControlFlowNode and result = here
}
ControlFlowNode toCfgNode() {
result = this
}
pragma[inline]
CfgOrigin fix(ControlFlowNode here) {
if this = Builtin::unknown() then
result = here
else
result = this
}
}
/* Use this version for stronger type-checking */
//private newtype TCfgOrigin =
// TUnknownOrigin()
// or
// TCfgOrigin(ControlFlowNode f)
//
//library class CfgOrigin extends TCfgOrigin {
//library class CfgOrigin extends @py_object {
//
// string toString() {
// /* Not to be displayed */
@@ -57,44 +20,92 @@ library class CfgOrigin extends @py_object {
// */
// pragma[inline]
// ControlFlowNode asCfgNodeOrHere(ControlFlowNode here) {
// this = TUnknownOrigin() and result = here
// result = this
// or
// this = TCfgOrigin(result)
// not this instanceof ControlFlowNode and result = here
// }
//
// ControlFlowNode toCfgNode() {
// this = TCfgOrigin(result)
// result = this
// }
//
// pragma[inline]
// CfgOrigin fix(ControlFlowNode here) {
// this = TUnknownOrigin() and result = TCfgOrigin(here)
// or
// not this = TUnknownOrigin() and result = this
// if this = Builtin::unknown() then
// result = here
// else
// result = this
// }
//
//}
//
//module CfgOrigin {
//
// CfgOrigin fromCfgNode(ControlFlowNode f) {
// result = f
// }
//
// CfgOrigin unknown() {
// result = Builtin::unknown()
// }
//
// CfgOrigin fromObject(ObjectInternal obj) {
// obj.isBuiltin() and result = unknown()
// or
// result = obj.getOrigin()
// }
//
//}
/* Use this version for stronger type-checking */
private newtype TCfgOrigin =
TUnknownOrigin()
or
TFlowNodeOrigin(ControlFlowNode f)
library class CfgOrigin extends TCfgOrigin {
string toString() {
/* Not to be displayed */
none()
}
/** Get a `ControlFlowNode` from `this` or `here`.
* If `this` is a ControlFlowNode then use that, otherwise fall back on `here`
*/
pragma[inline]
ControlFlowNode asCfgNodeOrHere(ControlFlowNode here) {
this = TUnknownOrigin() and result = here
or
this = TFlowNodeOrigin(result)
}
ControlFlowNode toCfgNode() {
this = TFlowNodeOrigin(result)
}
CfgOrigin fix(ControlFlowNode here) {
this = TUnknownOrigin() and result = TFlowNodeOrigin(here)
or
not this = TUnknownOrigin() and result = this
}
}
module CfgOrigin {
CfgOrigin fromCfgNode(ControlFlowNode f) {
result = f
result = TFlowNodeOrigin(f)
}
CfgOrigin unknown() {
result = Builtin::unknown()
}
CfgOrigin fromModule(ModuleObjectInternal mod) {
mod.isBuiltin() and result = unknown()
or
result = mod.getSourceModule().getEntryNode()
result = TUnknownOrigin()
}
CfgOrigin fromObject(ObjectInternal obj) {
obj.isBuiltin() and result = unknown()
or
result = obj.getOrigin()
result = fromCfgNode(obj.getOrigin())
}
}
@@ -106,7 +117,7 @@ module PointsTo {
PointsToInternal::pointsTo(f, context, value, origin)
}
predicate variablePointsTo(EssaVariable var, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
predicate variablePointsTo(EssaVariable var, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
PointsToInternal::variablePointsTo(var, context, value, origin)
}
@@ -149,8 +160,7 @@ module PointsTo {
exists(Value value |
PointsToInternal::variablePointsTo(var, context, value, origin) and
cls = value.getClass().getSource() |
obj = value.getSource() or
not exists(value.getSource()) and obj = origin
obj = value.getSource()
)
}
@@ -444,17 +454,20 @@ cached module PointsToInternal {
)
}
private predicate self_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
origin = CfgOrigin::fromCfgNode(def.getDefiningNode()) and
private predicate self_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
origin = def.getDefiningNode() and
value.(SelfInstanceInternal).parameterAndContext(def, context)
}
/** Holds if ESSA edge refinement, `def`, refers to `(value, cls, origin)`. */
private predicate ssa_filter_definition_points_to(PyEdgeRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
def.getSense() = ssa_filter_definition_bool(def, context, value, origin)
exists(ControlFlowNode orig |
def.getSense() = ssa_filter_definition_bool(def, context, value, orig) and
origin = CfgOrigin::fromCfgNode(orig)
)
}
private boolean ssa_filter_definition_bool(PyEdgeRefinement def, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
private boolean ssa_filter_definition_bool(PyEdgeRefinement def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
result = Conditionals::testEvaluates(def.getTest(), def.getInput().getASourceUse(), context, value, origin)
}
@@ -643,7 +656,7 @@ module InterModulePointsTo {
exists(PackageObjectInternal package |
package.getSourceModule() = def.getDefiningNode().getScope() |
value = package.submodule(def.getSourceVariable().getName()) and
origin = CfgOrigin::fromModule(value).fix(def.getDefiningNode()) and
origin = CfgOrigin::fromObject(value).asCfgNodeOrHere(def.getDefiningNode()) and
context.isImport()
)
}
@@ -748,7 +761,7 @@ module InterProceduralPointsTo {
predicate call_points_to(CallNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
exists(ObjectInternal func, CfgOrigin resultOrigin |
call_points_to_callee(f, context, func) and
origin = resultOrigin.fix(f)
origin = resultOrigin.asCfgNodeOrHere(f)
|
exists(PointsToContext callee |
callee.fromCall(f, context) and
@@ -816,7 +829,7 @@ module InterProceduralPointsTo {
func = method.getScope() and
def.getScope() = func and
value = method.getSelf() and
origin = CfgOrigin::fromObject(value)
origin = value.getOrigin()
)
}
@@ -1007,11 +1020,11 @@ module Expressions {
attr.isLoad() and
exists(string name |
attr.getObject(name) = obj and
PointsTo::pointsTo(obj, context, objvalue, _)
PointsToInternal::pointsTo(obj, context, objvalue, _)
|
exists(CfgOrigin orig |
objvalue.attribute(name, value, orig) and
origin = orig.fix(attr)
origin = orig.asCfgNodeOrHere(attr)
)
or
objvalue.attributesUnknown() and
@@ -1022,7 +1035,7 @@ module Expressions {
predicate subscriptPointsTo(SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode obj, ObjectInternal objvalue) {
subscr.isLoad() and
obj = subscr.getObject() and
PointsTo::pointsTo(obj, context, objvalue, _) and
PointsToInternal::pointsTo(obj, context, objvalue, _) and
value = ObjectInternal::unknown() and origin = subscr
}
@@ -1033,7 +1046,7 @@ module Expressions {
// TO DO...
// Track some integer values through `|` and the types of some objects
operand = b.getAnOperand() and
PointsTo::pointsTo(operand, context, opvalue, _) and
PointsToInternal::pointsTo(operand, context, opvalue, _) and
value = ObjectInternal::unknown() and origin = b
}
@@ -1041,7 +1054,7 @@ module Expressions {
exists(Unaryop op |
op = u.getNode().getOp() and
operand = u.getOperand() and
PointsTo::pointsTo(operand, context, opvalue, _)
PointsToInternal::pointsTo(operand, context, opvalue, _)
|
op instanceof Not and value = ObjectInternal::bool(opvalue.booleanValue().booleanNot())
or
@@ -1636,7 +1649,7 @@ cached module Types {
module AttributePointsTo {
predicate attributePointsTo(ControlFlowNode f, Context context, string name, ObjectInternal value, CfgOrigin origin) {
predicate attributePointsTo(ControlFlowNode f, Context context, string name, ObjectInternal value, ControlFlowNode origin) {
exists(ObjectInternal obj, Context prev, AttributeAssignment def |
PointsToInternal::pointsTo(f, context, obj, _) and
PointsToInternal::variablePointsTo(def.getInput(), prev, obj, _) and

View File

@@ -134,10 +134,11 @@ class ClassObject extends Object {
/** Whether the named attribute refers to the object, class and origin */
predicate attributeRefersTo(string name, Object obj, ClassObject cls, ControlFlowNode origin) {
exists(Value val |
theClass().attribute(name, val, origin) and
exists(Value val, CfgOrigin valorig |
theClass().attribute(name, val, valorig) and
obj = val.getSource() and
cls = val.getClass().getSource()
cls = val.getClass().getSource() and
origin = valorig.toCfgNode()
)
}

View File

@@ -50,9 +50,10 @@ abstract class ModuleObject extends Object {
}
predicate attributeRefersTo(string name, Object obj, ControlFlowNode origin) {
exists(Value val |
theModule().(ModuleObjectInternal).attribute(name, val, origin) and
obj = val.getSource()
exists(Value val, CfgOrigin valorig |
theModule().(ModuleObjectInternal).attribute(name, val, valorig) and
obj = val.getSource() and
origin = valorig.toCfgNode()
)
}