mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python points-to: improve performance.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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` */
|
||||
|
||||
@@ -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, _)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user