Python points-to: improve performance.

This commit is contained in:
Mark Shannon
2019-04-16 17:30:14 +01:00
parent cd34e23c4c
commit dffbf698d2
14 changed files with 396 additions and 254 deletions

View File

@@ -29,4 +29,4 @@ total_size = strictcount(ControlFlowNode f, Object value, ClassObject cls, Point
)
and
efficiency = 100.0 * total_facts / total_size
select depth, total_facts, total_size, efficiency
select depth, total_facts, total_size, efficiency

View File

@@ -465,6 +465,16 @@ class CallNode extends ControlFlowNode {
override Call getNode() { result = super.getNode() }
predicate isDecoratorCall() {
exists(FunctionExpr func |
this.getNode() = func.getADecoratorCall()
)
or
exists(ClassExpr cls |
this.getNode() = cls.getADecoratorCall()
)
}
}
/** A control flow corresponding to an attribute expression, such as `value.attr` */

View File

@@ -32,15 +32,15 @@ abstract class CallableObjectInternal extends ObjectInternal {
abstract string getName();
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
none()
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
abstract Function getScope();
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
abstract CallNode getACall(PointsToContext ctx);
@@ -112,7 +112,7 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
}
pragma [noinline]
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
this.getScope().isProcedure() and
obj = ObjectInternal::none_() and
origin = CfgOrigin::fromCfgNode(this.getScope().getEntryNode())
@@ -128,15 +128,15 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
override boolean isDescriptor() { result = true }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
instance.isClass() = false and
value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown()
or
any(ObjectInternal obj).binds(instance, _, this) and
instance.isClass() = true and
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(cls, _, this) and
value = this and origin = CfgOrigin::fromCfgNode(this.getOrigin())
}
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown()
}
override CallNode getACall(PointsToContext ctx) {
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
or
@@ -255,7 +255,9 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
override CallNode getACall(PointsToContext ctx) {
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
@@ -339,15 +341,15 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
override boolean isDescriptor() { result = true }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
instance.isClass() = false and
value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown()
or
any(ObjectInternal obj).binds(instance, _, this) and
instance.isClass() = true and
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(cls, _, this) and
value = this and origin = CfgOrigin::unknown()
}
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown()
}
override CallNode getACall(PointsToContext ctx) {
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
}
@@ -423,7 +425,9 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
override CallNode getACall(PointsToContext ctx) {
PointsTo::pointsTo(result.getFunction(), ctx, this, _)

View File

@@ -35,9 +35,11 @@ abstract class ClassObjectInternal extends ObjectInternal {
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
instance = this and
PointsToInternal::attributeRequired(this, name) and
this.lookup(name, descriptor, _) and
@@ -47,14 +49,14 @@ abstract class ClassObjectInternal extends ObjectInternal {
abstract predicate lookup(string name, ObjectInternal value, CfgOrigin origin);
/** Approximation to descriptor protocol, skipping meta-descriptor protocol */
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
exists(ObjectInternal descriptor, CfgOrigin desc_origin |
this.lookup(name, descriptor, desc_origin) |
descriptor.isDescriptor() = false and
value = descriptor and origin = desc_origin
or
descriptor.isDescriptor() = true and
descriptor.descriptorGet(this, value, origin)
descriptor.descriptorGetClass(this, value, origin)
)
}
@@ -103,13 +105,10 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
}
override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
exists(ClassObjectInternal decl |
decl = Types::getMro(this).findDeclaringClass(name) |
Types::declaredAttribute(decl, name, value, origin)
)
Types::getMro(this).lookup(name, value, origin)
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
none()
@@ -166,7 +165,7 @@ class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObjec
origin = CfgOrigin::unknown()
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
none()
@@ -226,7 +225,7 @@ class UnknownClassInternal extends ClassObjectInternal, TUnknownClass {
none()
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
}
@@ -274,7 +273,7 @@ class TypeInternal extends ClassObjectInternal, TType {
none()
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
}
@@ -311,7 +310,7 @@ class DynamicallyCreatedClass extends ClassObjectInternal, TDynamicClass {
this = TDynamicClass(result, _, _)
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
override predicate introduced(ControlFlowNode node, PointsToContext context) {
this = TDynamicClass(node, _, context)

View File

@@ -37,17 +37,19 @@ abstract class ConstantObjectInternal extends ObjectInternal {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
none()
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
}

View File

@@ -49,9 +49,9 @@ class PropertyInternal extends ObjectInternal, TProperty {
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { result = true }
@@ -67,18 +67,22 @@ class PropertyInternal extends ObjectInternal, TProperty {
)
}
override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(cls, _, this) and
value = this and origin = CfgOrigin::fromCfgNode(this.getOrigin())
}
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
/* Just give an unknown value for now. We could improve this, but it would mean
* changing Contexts to account for property accesses.
*/
exists(AttrNode attr, ClassObjectInternal cls, string name |
exists(ClassObjectInternal cls, string name |
name = this.getName() and
PointsToInternal::pointsTo(attr.getObject(name), _, instance, _) and
instance.getClass() = cls and
receiver_type(_, name, instance, cls) and
cls.lookup(name, this, _) and
origin = CfgOrigin::fromCfgNode(attr) and value = ObjectInternal::unknown()
origin = CfgOrigin::unknown() and value = ObjectInternal::unknown()
)
}
@@ -125,25 +129,24 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { result = true }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(instance, _, this) and
exists(ObjectInternal cls |
instance.isClass() = false and cls = instance.getClass()
or
instance.isClass() = true and cls = instance
|
value = TBoundMethod(cls, this.getFunction()) and
origin = CfgOrigin::unknown()
)
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
value = TBoundMethod(cls, this.getFunction()) and
origin = CfgOrigin::unknown()
}
override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) {
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(instance, _, this) and
value = TBoundMethod(instance.getClass(), this.getFunction()) and
origin = CfgOrigin::unknown()
}
pragma [noinline] override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) {
descriptor = this.getFunction() and
exists(ObjectInternal instance |
any(ObjectInternal obj).binds(instance, name, this) |
@@ -200,18 +203,23 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
this.getFunction().calleeAndOffset(scope, paramOffset)
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { result = true }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(cls, _, this) and
value = this.getFunction() and origin = CfgOrigin::unknown()
}
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
any(ObjectInternal obj).binds(instance, _, this) and
value = this.getFunction() and origin = CfgOrigin::unknown()
}
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
override int length() { none() }

View File

@@ -76,9 +76,16 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
none()
}
pragma [nomagic]
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
PointsToInternal::attributeRequired(this, name) and
instance_getattr(this, Types::getMro(this.getClass()), name, value, origin)
exists(ObjectInternal cls_attr, CfgOrigin attr_orig |
this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig)
|
cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig
or
cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin)
)
or
exists(EssaVariable self, PythonFunctionObjectInternal init, Context callee |
BaseFlow::reaches_exit(self) and
@@ -93,18 +100,21 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
)
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
this = instance and descriptor.isDescriptor() = true and
exists(AttrNode attr |
PointsToInternal::pointsTo(attr.getObject(name), _, instance, _) and
this.getClass().(ClassObjectInternal).lookup(name, descriptor, _)
)
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
exists(ClassObjectInternal cls |
receiver_type(_, name, this, cls) and
cls.lookup(name, descriptor, _) and
descriptor.isDescriptor() = true
) and
this = instance
}
override int length() {
@@ -113,18 +123,6 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
}
bindingset[instance, mro, name]
predicate instance_getattr(ObjectInternal instance, ClassList mro, string name, ObjectInternal value, CfgOrigin origin) {
exists(ObjectInternal descriptor, CfgOrigin desc_origin |
Types::declaredAttribute(mro.findDeclaringClass(name), name, descriptor, desc_origin) |
descriptor.isDescriptor() = false and
value = descriptor and origin = desc_origin
or
descriptor.isDescriptor() = true and
descriptor.descriptorGet(instance, value, origin)
)
}
class SelfInstanceInternal extends TSelfInstance, ObjectInternal {
@@ -159,19 +157,10 @@ class SelfInstanceInternal extends TSelfInstance, ObjectInternal {
this = TSelfInstance(_, _, result)
}
/** Gets the `Builtin` for this object, if any.
* All objects (except unknown and undefined values) should return
* exactly one result for either this method or `getOrigin()`.
*/
override Builtin getBuiltin() {
none()
}
/** Gets a control flow node that represents the source origin of this
* objects.
* All objects (except unknown and undefined values) should return
* exactly one result for either this method or `getBuiltin()`.
*/
override ControlFlowNode getOrigin() {
exists(ParameterDefinition def |
this = TSelfInstance(def, _, _) and
@@ -201,18 +190,26 @@ class SelfInstanceInternal extends TSelfInstance, ObjectInternal {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [nomagic] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
PointsToInternal::attributeRequired(this, name) and
instance_getattr(this, Types::getMro(this.getClass()), name, value, origin)
exists(ObjectInternal cls_attr, CfgOrigin attr_orig |
this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig)
|
cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig
or
cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin)
)
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
exists(AttrNode attr, ClassObjectInternal cls |
receiver_type(attr, name, this, cls) and
cls_descriptor(cls, name, descriptor)
@@ -295,18 +292,26 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
PointsToInternal::attributeRequired(this, name) and
instance_getattr(this, Types::getMro(this.getClass()), name, value, origin)
exists(ObjectInternal cls_attr, CfgOrigin attr_orig |
this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig)
|
cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig
or
cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin)
)
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
exists(AttrNode attr, ClassObjectInternal cls |
receiver_type(attr, name, this, cls) and
cls_descriptor(cls, name, descriptor)
@@ -324,10 +329,6 @@ private int lengthFromClass(ClassObjectInternal cls) {
Types::getMro(cls).declares("__len__") and result = -1
}
private predicate receiver_type(AttrNode attr, string name, ObjectInternal value, ClassObjectInternal cls) {
PointsToInternal::pointsTo(attr.getObject(name), _, value, _) and value.getClass() = cls
}
private predicate cls_descriptor(ClassObjectInternal cls, string name, ObjectInternal descriptor) {
cls.lookup(name, descriptor, _) and
descriptor.isDescriptor() = true
@@ -361,7 +362,7 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
override boolean isClass() { result = false }
override ObjectInternal getClass() {
result = ObjectInternal::builtin("super")
result = ObjectInternal::super_()
}
override boolean isComparable() { result = false }
@@ -382,30 +383,36 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
PointsToInternal::attributeRequired(this, name) and
instance_getattr(this.getSelf(), this.getMro(), name, value, origin)
}
private ClassList getMro() {
result = Types::getMro(this.getSelf().getClass()).startingAt(this.getStartClass()).getTail()
}
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
descriptor.isDescriptor() = true and
exists(AttrNode attr |
PointsToInternal::pointsTo(attr.getObject(name), _, this, _) and
instance = this.getSelf() and
Types::declaredAttribute(this.getMro().findDeclaringClass(name), name, descriptor, _)
exists(ObjectInternal cls_attr, CfgOrigin attr_orig |
this.lookup(name, cls_attr, attr_orig)
|
cls_attr.isDescriptor() = false and value = cls_attr and origin = attr_orig
or
cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this.getSelf(), value, origin)
)
}
private predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
Types::getMro(this.getSelf().getClass()).startingAt(this.getStartClass()).getTail().lookup(name, value, origin)
}
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
descriptor.isDescriptor() = true and
this.lookup(name, descriptor, _) and
instance = this.getSelf() and
receiver_type(_, name, this, _)
}
override int length() {
none()
}

View File

@@ -37,10 +37,11 @@ abstract class ModuleObjectInternal extends ObjectInternal {
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
override int length() { none() }
@@ -84,12 +85,12 @@ class BuiltinModuleObjectInternal extends ModuleObjectInternal, TBuiltinModuleOb
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and
origin = CfgOrigin::unknown()
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override ControlFlowNode getOrigin() {
none()
@@ -154,7 +155,7 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
this.getInitModule().attribute(name, value, origin)
or
exists(Module init |
@@ -176,7 +177,7 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
)
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override ControlFlowNode getOrigin() {
result = this.getSourceModule().getEntryNode()
@@ -234,19 +235,11 @@ class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
exists(EssaVariable var, ControlFlowNode exit, PointsToContext imp |
exit = this.getSourceModule().getANormalExit() and var.getAUse() = exit and
var.getSourceVariable().getName() = name and
PointsTo::variablePointsTo(var, imp, value, origin) and
imp.isImport() and
value != ObjectInternal::undefined()
)
or
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
ModuleAttributes::pointsToAtExit(this.getSourceModule(), name, value, origin)
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override ControlFlowNode getOrigin() {
result = this.getSourceModule().getEntryNode()

View File

@@ -90,7 +90,11 @@ class ObjectInternal extends TObject {
abstract boolean isDescriptor();
abstract predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin);
pragma[nomagic]
abstract predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin);
pragma[nomagic]
abstract predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin);
/** Holds if attribute lookup on this object may "bind" `instance` to `descriptor`.
* Here "bind" means that `instance` is passed to the `descriptor.__get__()` method
@@ -163,18 +167,20 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
value = ObjectInternal::fromBuiltin(this.getBuiltin().getMember(name)) and
origin = CfgOrigin::unknown()
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
override int length() { none() }
@@ -235,17 +241,19 @@ class UnknownInternal extends ObjectInternal, TUnknown {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
none()
}
override predicate attributesUnknown() { any() }
pragma [noinline] override predicate attributesUnknown() { any() }
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
override int length() { result = -1 }
@@ -307,17 +315,19 @@ class UndefinedInternal extends ObjectInternal, TUndefined {
none()
}
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
none()
}
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
override boolean isDescriptor() { none() }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
override int length() { none() }
@@ -390,9 +400,21 @@ module ObjectInternal {
ObjectInternal property() {
result = TBuiltinClassObject(Builtin::special("property"))
}
ObjectInternal super_() {
result = TBuiltinClassObject(Builtin::special("super"))
}
}
/** Helper for boolean predicates returning both `true` and `false` */
boolean maybe() {
result = true or result = false
}
/** Helper for attributes */
pragma [nomagic]
predicate receiver_type(AttrNode attr, string name, ObjectInternal value, ClassObjectInternal cls) {
PointsToInternal::pointsTo(attr.getObject(name), _, value, _) and value.getClass() = cls
}

View File

@@ -25,9 +25,11 @@ abstract class SequenceObjectInternal extends ObjectInternal {
override boolean isDescriptor() { result = false }
override predicate descriptorGet(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
}
@@ -81,9 +83,9 @@ abstract class TupleObjectInternal extends SequenceObjectInternal {
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
override predicate attributesUnknown() { none() }
pragma [noinline] override predicate attributesUnknown() { none() }
}

View File

@@ -99,7 +99,7 @@ newtype TObject =
}
or
TUnknownInstance(BuiltinClassObjectInternal cls) {
cls != ObjectInternal::builtin("super") and
cls != ObjectInternal::super_() and
cls != ObjectInternal::builtin("bool") and
cls != ObjectInternal::noneType()
}
@@ -171,14 +171,21 @@ predicate super_instantiation(CallNode instantiation, ObjectInternal self, Class
pragma [noinline]
private predicate super_2args(CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, PointsToContext context) {
exists(ControlFlowNode func, ControlFlowNode arg0, ControlFlowNode arg1 |
call2(instantiation, func, arg0, arg1) and
PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("super"), _) and
exists(ControlFlowNode arg0, ControlFlowNode arg1 |
super_call2(instantiation, arg0, arg1, context) and
PointsToInternal::pointsTo(arg0, context, startclass, _) and
PointsToInternal::pointsTo(arg1, context, self, _)
)
}
pragma [noinline]
private predicate super_call2(CallNode call, ControlFlowNode arg0, ControlFlowNode arg1, PointsToContext context) {
exists(ControlFlowNode func |
call2(call, func, arg0, arg1) and
PointsToInternal::pointsTo(func, context, ObjectInternal::super_(), _)
)
}
pragma [noinline]
private predicate super_noargs(CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, PointsToContext context) {
PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::builtin("super"), _) and
@@ -205,7 +212,7 @@ predicate method_binding(AttrNode instantiation, ObjectInternal self, CallableOb
receiver(instantiation, context, obj, name) |
exists(ObjectInternal cls |
cls = obj.getClass() and
cls != ObjectInternal::builtin("super") and
cls != ObjectInternal::super_() and
cls.attribute(name, function, _) and
self = obj
)

View File

@@ -155,6 +155,13 @@ class ClassList extends TClassList {
)
}
predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
exists(ClassObjectInternal decl |
decl = this.findDeclaringClass(name) |
Types::declaredAttribute(decl, name, value, origin)
)
}
predicate declares(string name) {
this.getHead().getClassDeclaration().declaresAttribute(name)
or

View File

@@ -175,6 +175,13 @@ cached module PointsToInternal {
reachableBlock(f.getBasicBlock(), context)
}
cached predicate pointsToString(ControlFlowNode f, PointsToContext context, string value) {
exists(StringObjectInternal str |
PointsToInternal::pointsTo(f, context, str, _) and
str.strValue() = value
)
}
private predicate points_to_candidate(ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
use_points_to(f, context, value, origin)
or
@@ -202,12 +209,7 @@ cached module PointsToInternal {
cached predicate attributeRequired(ObjectInternal obj, string name) {
pointsTo(any(AttrNode a).getObject(name), _, obj, _)
or
exists(CallNode call, PointsToContext ctx, StringObjectInternal nameobj |
pointsTo(call.getFunction(), ctx, ObjectInternal::builtin("getattr"), _) and
pointsTo(call.getArg(0), ctx, obj, _) and
pointsTo(call.getArg(1), ctx, nameobj, _) and
nameobj.strValue() = name
)
Expressions::getattr_call(_, _, _, obj, name)
}
/* Holds if BasicBlock `b` is reachable, given the context `context`. */
@@ -774,25 +776,49 @@ module InterModulePointsTo {
module InterProceduralPointsTo {
cached predicate call(CallNode call, PointsToContext caller, ObjectInternal value) {
PointsToInternal::pointsTo(call.getFunction(), caller, value, _)
}
cached predicate callWithContext(CallNode call, PointsToContext caller, ObjectInternal value, PointsToContext callee) {
callee.fromCall(call, caller) and
PointsToInternal::pointsTo(call.getFunction(), caller, value, _)
}
pragma [noinline]
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.asCfgNodeOrHere(f)
private predicate call_points_to_simple(CallNode f, PointsToContext context, ObjectInternal value, CfgOrigin origin) {
exists(ObjectInternal func |
call(f, context, func)
|
exists(PointsToContext callee |
callee.fromCall(f, context) and
func.callResult(callee, value, resultOrigin)
func.callResult(callee, value, origin)
)
or
func.callResult(value, resultOrigin) and
context.untrackableCall(f) and
value = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
or
func.callResult(value, origin) and
context.appliesTo(f)
)
}
pragma [noinline]
predicate call_points_to(CallNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
exists(ObjectInternal returnValue, CfgOrigin resultOrigin |
call_points_to_simple(f, context, returnValue, resultOrigin)
|
/* Either not a decorator, or we understand the return value */
(returnValue != ObjectInternal::unknown() or not f.isDecoratorCall()) and
value = returnValue and origin = resultOrigin.asCfgNodeOrHere(f)
or
/* A decorator and we don't understand it. Use the original, undecorated value */
f.isDecoratorCall() and returnValue = ObjectInternal::unknown() and
PointsToInternal::pointsTo(f.getArg(0), context, value, origin)
)
or
call_to_type(f, context) and
exists(ObjectInternal arg |
PointsToInternal::pointsTo(f.getArg(0), context, arg, _) and
value = arg.getClass() |
value = call_to_type(f, context) and
(
value.isBuiltin() and origin = f
or
origin = value.getOrigin()
@@ -802,14 +828,13 @@ module InterProceduralPointsTo {
}
pragma [noinline]
private predicate call_to_type(CallNode f, PointsToContext context) {
private ObjectInternal call_to_type(CallNode f, PointsToContext context) {
count(f.getArg(_)) = 1 and
PointsToInternal::pointsTo(f.getFunction(), context, ObjectInternal::builtin("type"), _)
}
pragma [noinline]
private predicate call_points_to_callee(CallNode f, PointsToContext context, ObjectInternal callee) {
PointsToInternal::pointsTo(f.getFunction(), context, callee, _)
call(f, context, ObjectInternal::builtin("type")) and
exists(ObjectInternal arg |
PointsToInternal::pointsTo(f.getArg(0), context, arg, _) and
result = arg.getClass()
)
}
/** Points-to for parameter. `def foo(param): ...`. */
@@ -838,11 +863,11 @@ module InterProceduralPointsTo {
context.isRuntime() and value = ObjectInternal::unknown() and origin = def.getDefiningNode()
}
pragma [noinline]
private predicate self_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
def.isSelf() and
exists(CallNode call, BoundMethodObjectInternal method, Function func, PointsToContext caller |
PointsToInternal::pointsTo(call.getFunction(), caller, method, _) and
context.fromCall(call, caller) and
callWithContext(call, caller, method, context) and
func = method.getScope() and
def.getScope() = func and
value = method.getSelf() and
@@ -850,6 +875,16 @@ module InterProceduralPointsTo {
)
}
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)
)
}
/** Helper for `parameter_points_to` */
pragma [noinline]
private predicate named_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
@@ -861,6 +896,7 @@ module InterProceduralPointsTo {
}
/** Helper for parameter_points_to */
pragma [noinline]
private predicate default_parameter_points_to(ParameterDefinition def, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
exists(PointsToContext imp | imp.isImport() | PointsToInternal::pointsTo(def.getDefault(), imp, value, origin)) and
context_for_default_value(def, context)
@@ -914,9 +950,8 @@ module InterProceduralPointsTo {
}
cached predicate callsite_calls_function(CallNode call, PointsToContext caller, Function scope, PointsToContext callee, int parameter_offset) {
callee.fromCall(call, caller) and
exists(ObjectInternal func |
PointsToInternal::pointsTo(call.getFunction(), caller, func, _) and
callWithContext(call, caller, func, callee) and
func.calleeAndOffset(scope, parameter_offset)
)
}
@@ -1049,11 +1084,16 @@ private predicate potential_builtin_points_to(NameNode f, ObjectInternal value,
module Expressions {
pragma [noinline]
private predicate attributeObjectPointsto(AttrNode attr, PointsToContext context, string name, ControlFlowNode obj, ObjectInternal objvalue) {
attr.isLoad() and attr.getObject(name) = obj and
PointsToInternal::pointsTo(obj, context, objvalue, _)
}
pragma [noinline]
predicate attributePointsTo(AttrNode attr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode obj, ObjectInternal objvalue) {
attr.isLoad() and
exists(string name |
attr.getObject(name) = obj and
PointsToInternal::pointsTo(obj, context, objvalue, _)
attributeObjectPointsto(attr, context, name, obj, objvalue)
|
exists(CfgOrigin orig |
objvalue.attribute(name, value, orig) and
@@ -1061,10 +1101,12 @@ module Expressions {
)
or
objvalue.attributesUnknown() and
origin = attr and value = ObjectInternal::unknown()
origin = attr and
value = ObjectInternal::unknown()
)
}
pragma [noinline]
predicate subscriptPointsTo(SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode obj, ObjectInternal objvalue) {
subscr.isLoad() and
obj = subscr.getObject() and
@@ -1075,6 +1117,7 @@ module Expressions {
/** Track bitwise expressions so we can handle integer flags and enums.
* Tracking too many binary expressions is likely to kill performance.
*/
pragma [noinline]
predicate binaryPointsTo(BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode operand, ObjectInternal opvalue) {
// TO DO...
// Track some integer values through `|` and the types of some objects
@@ -1083,6 +1126,7 @@ module Expressions {
value = ObjectInternal::unknown() and origin = b
}
pragma [noinline]
predicate unaryPointsTo(UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode operand, ObjectInternal opvalue) {
exists(Unaryop op |
op = u.getNode().getOp() and
@@ -1098,6 +1142,7 @@ module Expressions {
origin = u
}
pragma [noinline]
predicate builtinCallPointsTo(CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode arg, ObjectInternal argvalue) {
PointsToInternal::pointsTo(arg, context, argvalue, _) and
arg = call.getArg(0) and
@@ -1127,6 +1172,37 @@ module Expressions {
)
}
pragma [noinline]
private predicate getattrPointsTo(CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode arg, ObjectInternal argvalue) {
exists(string name |
getattr_call(call, arg, context, argvalue, name)
|
argvalue.attributesUnknown() and value = ObjectInternal::unknown() and origin = call
or
exists(CfgOrigin valOrigin |
argvalue.attribute(name, value, valOrigin) and origin = valOrigin.asCfgNodeOrHere(call)
)
)
}
pragma [noinline]
predicate getattr_call(CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, string name) {
exists(ControlFlowNode arg1 |
call_to_getattr(call, context, use, arg1) and
PointsToInternal::pointsTo(use, context, val, _) and
PointsToInternal::pointsToString(arg1, context, name)
)
}
pragma[noinline]
private predicate call_to_getattr(ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1) {
exists(ControlFlowNode func |
call2(call, func, arg0, arg1) and
PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("getattr"), _)
)
}
pragma [noinline]
private boolean otherComparisonEvaluatesTo(CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue) {
exists(Cmpop op |
comp.operands(operand, op, _) or
@@ -1139,58 +1215,68 @@ module Expressions {
pragma [noinline]
private boolean equalityEvaluatesTo(CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue) {
exists(ControlFlowNode r, boolean sense |
equality_test(comp, operand, sense, r) and
exists(ObjectInternal other |
PointsToInternal::pointsTo(operand, context, opvalue, _) and
PointsToInternal::pointsTo(r, context, other, _) |
opvalue.isComparable() = true and other.isComparable() = true and
(
other = opvalue and result = sense
or
other != opvalue and result = sense.booleanNot()
)
exists(ObjectInternal other, boolean sense |
equalityTest(comp, context, operand, opvalue, other, sense)
|
opvalue.isComparable() = true and other.isComparable() = true and
(
other = opvalue and result = sense
or
opvalue.isComparable() = false and result = maybe()
or
other.isComparable() = false and result = maybe()
other != opvalue and result = sense.booleanNot()
)
or
opvalue.isComparable() = false and result = maybe()
or
other.isComparable() = false and result = maybe()
)
}
pragma [noinline]
private boolean inequalityEvaluatesTo(ControlFlowNode expr, PointsToContext context, ControlFlowNode use, ObjectInternal val) {
exists(ControlFlowNode r, boolean sense |
exists(boolean strict, ObjectInternal other |
(
inequality(expr, use, r, strict) and sense = true
or
inequality(expr, r, use, strict) and sense = false
) and
PointsToInternal::pointsTo(use, context, val, _) and
PointsToInternal::pointsTo(r, context, other, _)
|
val.intValue() < other.intValue() and result = sense
or
val.intValue() > other.intValue() and result = sense.booleanNot()
or
val.intValue() = other.intValue() and result = strict.booleanXor(sense)
or
val.strValue() < other.strValue() and result = sense
or
val.strValue() > other.strValue() and result = sense.booleanNot()
or
val.strValue() = other.strValue() and result = strict.booleanXor(sense)
or
val.isComparable() = false and result = maybe()
or
other.isComparable() = false and result = maybe()
)
private predicate equalityTest(CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, ObjectInternal other, boolean sense) {
exists(ControlFlowNode r |
equality_test(comp, operand, sense, r) and
PointsToInternal::pointsTo(operand, context, opvalue, _) and
PointsToInternal::pointsTo(r, context, other, _)
)
}
pragma [noinline]
private boolean inequalityEvaluatesTo(CompareNode comp, PointsToContext context, ControlFlowNode use, ObjectInternal val) {
exists(boolean strict, boolean sense, ObjectInternal other |
inequalityTest(comp, context, use, val, other, strict, sense)
|
val.intValue() < other.intValue() and result = sense
or
val.intValue() > other.intValue() and result = sense.booleanNot()
or
val.intValue() = other.intValue() and result = strict.booleanXor(sense)
or
val.strValue() < other.strValue() and result = sense
or
val.strValue() > other.strValue() and result = sense.booleanNot()
or
val.strValue() = other.strValue() and result = strict.booleanXor(sense)
or
val.isComparable() = false and result = maybe()
or
other.isComparable() = false and result = maybe()
)
}
pragma [noinline]
private predicate inequalityTest(CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, ObjectInternal other, boolean strict, boolean sense) {
exists(ControlFlowNode r |
inequality(comp, operand, r, strict) and sense = true
or
inequality(comp, r, operand, strict) and sense = false
|
PointsToInternal::pointsTo(operand, context, opvalue, _) and
PointsToInternal::pointsTo(r, context, other, _)
)
}
/** Helper for comparisons. */
pragma [noinline]
private predicate inequality(CompareNode cmp, ControlFlowNode lesser, ControlFlowNode greater, boolean strict) {
exists(Cmpop op |
cmp.operands(lesser, op, greater) and op.getSymbol() = "<" and strict = true
@@ -1216,9 +1302,12 @@ module Expressions {
or
lenCallPointsTo(expr, context, value, origin, subexpr, subvalue)
or
getattrPointsTo(expr, context, value, origin, subexpr, subvalue)
or
value = ObjectInternal::bool(evaluatesTo(expr, context, subexpr, subvalue)) and origin = expr
}
pragma [noinline]
boolean evaluatesTo(ControlFlowNode expr, PointsToContext context, ControlFlowNode subexpr, ObjectInternal subvalue) {
result = equalityEvaluatesTo(expr, context, subexpr, subvalue)
or
@@ -1293,20 +1382,19 @@ module Expressions {
}
private predicate hasattr_call(CallNode call, ControlFlowNode use, PointsToContext context, ObjectInternal val, string name) {
exists(ControlFlowNode func, ControlFlowNode arg1 |
call2(call, func, use, arg1) and
points_to_hasattr(func, context) and
exists(ControlFlowNode arg1 |
call_to_hasattr(call, context, use, arg1) and
PointsToInternal::pointsTo(use, context, val, _) and
exists(StringObjectInternal str |
PointsToInternal::pointsTo(arg1, context, str, _) and
str.strValue() = name
)
PointsToInternal::pointsToString(arg1, context, name)
)
}
pragma[noinline]
private predicate points_to_hasattr(ControlFlowNode func, PointsToContext context) {
PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("hasattr"), _)
private predicate call_to_hasattr(ControlFlowNode call, PointsToContext context, ControlFlowNode arg0, ControlFlowNode arg1) {
exists(ControlFlowNode func |
call2(call, func, arg0, arg1) and
PointsToInternal::pointsTo(func, context, ObjectInternal::builtin("hasattr"), _)
)
}
pragma [nomagic]
@@ -1759,7 +1847,7 @@ module AttributePointsTo {
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
InterProceduralPointsTo::selfMethodCall(call, caller, func, context) and
def.isSelf() and def.getScope() = func and
variableAttributePointsTo(call.getInput(), caller, name, value, origin)
)
@@ -1769,7 +1857,7 @@ module AttributePointsTo {
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
InterProceduralPointsTo::selfMethodCall(def, context, func, callee) and
exit_self.getSourceVariable().(Variable).isSelf() and
exit_self.getScope() = func and
BaseFlow::reaches_exit(exit_self) and
@@ -1777,16 +1865,6 @@ module AttributePointsTo {
)
}
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)
)
}
}
module ModuleAttributes {
@@ -1819,7 +1897,7 @@ module ModuleAttributes {
scopeEntryPointsTo(var.getDefinition(), name, value, origin)
}
pragma [noinline]
pragma [nomagic]
private predicate importStarPointsTo(ImportStarRefinement def, string name, ObjectInternal value, CfgOrigin origin) {
def.getVariable().getName() = "$" and
exists(ImportStarNode imp, ModuleObjectInternal mod |

View File

@@ -14,6 +14,7 @@ private int given_cost() {
)
}
pragma [noinline]
private int max_context_cost() {
not py_flags_versioned("context.cost", _, _) and result = 7
or
@@ -103,6 +104,7 @@ private int total_call_cost(CallNode call) {
result = call_cost(call) + splay_cost(call)
}
pragma [noinline]
private int total_cost(CallNode call, PointsToContext ctx) {
ctx.appliesTo(call) and
result = total_call_cost(call) + context_cost(ctx)
@@ -238,6 +240,7 @@ class PointsToContext extends TPointsToContext {
}
/** Holds if a call would be too expensive to create a new context for */
pragma [nomagic]
predicate untrackableCall(CallNode call) {
total_cost(call, this) > max_context_cost()
}