mirror of
https://github.com/github/codeql.git
synced 2026-01-08 12:10:22 +01:00
386 lines
12 KiB
Plaintext
386 lines
12 KiB
Plaintext
import python
|
|
private import semmle.python.objects.TObject
|
|
private import semmle.python.objects.ObjectInternal
|
|
private import semmle.python.pointsto.PointsTo
|
|
private import semmle.python.pointsto.PointsToContext
|
|
private import semmle.python.pointsto.MRO
|
|
private import semmle.python.types.Builtins
|
|
|
|
/** A property object. */
|
|
class PropertyInternal extends ObjectInternal, TProperty {
|
|
/** Gets the name of this property */
|
|
override string getName() { result = this.getGetter().getName() }
|
|
|
|
/** Gets the getter function of this property */
|
|
CallableObjectInternal getGetter() { this = TProperty(_, _, result) }
|
|
|
|
private CallNode getCallNode() { this = TProperty(result, _, _) }
|
|
|
|
/** Gets the setter function of this property */
|
|
CallableObjectInternal getSetter() {
|
|
// @x.setter
|
|
exists(CallNode call, AttrNode setter |
|
|
call.getFunction() = setter and
|
|
PointsToInternal::pointsTo(setter.getObject("setter"), this.getContext(), this, _) and
|
|
PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _)
|
|
)
|
|
or
|
|
// x = property(getter, setter, deleter)
|
|
exists(ControlFlowNode setter_arg |
|
|
setter_arg = this.getCallNode().getArg(1) or
|
|
setter_arg = this.getCallNode().getArgByName("fset")
|
|
|
|
|
PointsToInternal::pointsTo(setter_arg, this.getContext(), result, _)
|
|
)
|
|
}
|
|
|
|
/** Gets the setter function of this property */
|
|
CallableObjectInternal getDeleter() {
|
|
exists(CallNode call, AttrNode setter |
|
|
call.getFunction() = setter and
|
|
PointsToInternal::pointsTo(setter.getObject("deleter"), this.getContext(), this, _) and
|
|
PointsToInternal::pointsTo(call.getArg(0), this.getContext(), result, _)
|
|
)
|
|
or
|
|
// x = property(getter, setter, deleter)
|
|
exists(ControlFlowNode deleter_arg |
|
|
deleter_arg = this.getCallNode().getArg(2) or
|
|
deleter_arg = this.getCallNode().getArgByName("fdel")
|
|
|
|
|
PointsToInternal::pointsTo(deleter_arg, this.getContext(), result, _)
|
|
)
|
|
}
|
|
|
|
private Context getContext() { this = TProperty(_, result, _) }
|
|
|
|
override string toString() { result = "property " + this.getName() }
|
|
|
|
override boolean booleanValue() { result = true }
|
|
|
|
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
|
this = TProperty(node, context, _)
|
|
}
|
|
|
|
override ClassDecl getClassDeclaration() { none() }
|
|
|
|
override boolean isClass() { result = false }
|
|
|
|
override ObjectInternal getClass() { result = ObjectInternal::property() }
|
|
|
|
override predicate notTestableForEquality() { none() }
|
|
|
|
override Builtin getBuiltin() { none() }
|
|
|
|
override ControlFlowNode getOrigin() { this = TProperty(result, _, _) }
|
|
|
|
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
|
none()
|
|
}
|
|
|
|
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
|
|
|
override int intValue() { none() }
|
|
|
|
override string strValue() { none() }
|
|
|
|
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
|
|
|
pragma[noinline]
|
|
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
|
value = TPropertySetterOrDeleter(this, name) and origin = CfgOrigin::unknown()
|
|
}
|
|
|
|
override predicate attributesUnknown() { none() }
|
|
|
|
override predicate subscriptUnknown() { none() }
|
|
|
|
override boolean isDescriptor() { result = true }
|
|
|
|
override int length() { none() }
|
|
|
|
override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() }
|
|
|
|
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(ClassObjectInternal cls, string name |
|
|
name = this.getName() and
|
|
receiver_type(_, name, instance, cls) and
|
|
cls.lookup(name, this, _) and
|
|
origin = CfgOrigin::unknown() and
|
|
value = ObjectInternal::unknown()
|
|
)
|
|
}
|
|
|
|
override predicate contextSensitiveCallee() { none() }
|
|
|
|
override predicate useOriginAsLegacyObject() { none() }
|
|
|
|
/* Properties aren't iterable */
|
|
override ObjectInternal getIterNext() { none() }
|
|
|
|
override predicate isNotSubscriptedType() { any() }
|
|
}
|
|
|
|
private class PropertySetterOrDeleter extends ObjectInternal, TPropertySetterOrDeleter {
|
|
override string toString() { result = this.getProperty().toString() + "." + this.getName() }
|
|
|
|
override string getName() { this = TPropertySetterOrDeleter(_, result) }
|
|
|
|
PropertyInternal getProperty() { this = TPropertySetterOrDeleter(result, _) }
|
|
|
|
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
|
exists(ControlFlowNode call |
|
|
obj = this.getProperty() and
|
|
obj = TProperty(call, _, _) and
|
|
origin = CfgOrigin::fromCfgNode(call)
|
|
)
|
|
}
|
|
|
|
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
|
|
|
override ClassDecl getClassDeclaration() { none() }
|
|
|
|
override boolean isClass() { result = false }
|
|
|
|
override ObjectInternal getClass() {
|
|
result = TBuiltinClassObject(Builtin::special("MethodType"))
|
|
}
|
|
|
|
override predicate notTestableForEquality() { none() }
|
|
|
|
override Builtin getBuiltin() { none() }
|
|
|
|
override ControlFlowNode getOrigin() { none() }
|
|
|
|
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
|
none()
|
|
}
|
|
|
|
override int intValue() { none() }
|
|
|
|
override string strValue() { none() }
|
|
|
|
override boolean booleanValue() { result = true }
|
|
|
|
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
|
|
|
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
|
|
|
override predicate attributesUnknown() { none() }
|
|
|
|
override predicate subscriptUnknown() { none() }
|
|
|
|
override boolean isDescriptor() { result = true }
|
|
|
|
override int length() { none() }
|
|
|
|
override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() }
|
|
|
|
override predicate contextSensitiveCallee() { none() }
|
|
|
|
override ObjectInternal getIterNext() { none() }
|
|
|
|
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
|
|
none()
|
|
}
|
|
|
|
override predicate descriptorGetInstance(
|
|
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
|
) {
|
|
none()
|
|
}
|
|
|
|
override predicate useOriginAsLegacyObject() { none() }
|
|
|
|
override predicate isNotSubscriptedType() { any() }
|
|
}
|
|
|
|
/** A class representing classmethods in Python */
|
|
class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
|
override string toString() { result = "classmethod(" + this.getFunction() + ")" }
|
|
|
|
override boolean booleanValue() { result = true }
|
|
|
|
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
|
exists(CallableObjectInternal function |
|
|
this = TClassMethod(node, function) and
|
|
class_method(node, function, context)
|
|
)
|
|
}
|
|
|
|
/** Gets the function wrapped by this classmethod object */
|
|
CallableObjectInternal getFunction() { this = TClassMethod(_, result) }
|
|
|
|
override ClassDecl getClassDeclaration() { none() }
|
|
|
|
override boolean isClass() { result = false }
|
|
|
|
override ObjectInternal getClass() { result = ObjectInternal::classMethod() }
|
|
|
|
override predicate notTestableForEquality() { none() }
|
|
|
|
override Builtin getBuiltin() { none() }
|
|
|
|
override ControlFlowNode getOrigin() { this = TClassMethod(result, _) }
|
|
|
|
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
|
none()
|
|
}
|
|
|
|
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
|
|
|
override int intValue() { none() }
|
|
|
|
override string strValue() { none() }
|
|
|
|
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
|
|
|
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
|
|
|
override predicate attributesUnknown() { none() }
|
|
|
|
override predicate subscriptUnknown() { none() }
|
|
|
|
override boolean isDescriptor() { result = true }
|
|
|
|
pragma[noinline]
|
|
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
|
|
value = TBoundMethod(cls, 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 = TBoundMethod(instance.getClass(), this.getFunction()) and
|
|
origin = CfgOrigin::unknown()
|
|
}
|
|
|
|
/**
|
|
* Holds if attribute lookup on this object may "bind" `cls` to `descriptor`.
|
|
* `cls` will always be a class as this is a classmethod.
|
|
* Here "bind" means that `instance` is passed to the `classmethod.__get__()` method
|
|
* at runtime. The term "bind" is used as this most likely results in a bound-method.
|
|
*/
|
|
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) |
|
|
instance.isClass() = false and cls = instance.getClass()
|
|
or
|
|
instance.isClass() = true and cls = instance
|
|
)
|
|
}
|
|
|
|
override int length() { none() }
|
|
|
|
override string getName() { result = this.getFunction().getName() }
|
|
|
|
override predicate contextSensitiveCallee() { none() }
|
|
|
|
override predicate useOriginAsLegacyObject() { none() }
|
|
|
|
/* Classmethods aren't iterable */
|
|
override ObjectInternal getIterNext() { none() }
|
|
|
|
override predicate isNotSubscriptedType() { any() }
|
|
}
|
|
|
|
class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
|
override string toString() { result = "staticmethod()" }
|
|
|
|
override boolean booleanValue() { result = true }
|
|
|
|
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
|
exists(CallableObjectInternal function |
|
|
this = TStaticMethod(node, function) and
|
|
static_method(node, function, context)
|
|
)
|
|
}
|
|
|
|
CallableObjectInternal getFunction() { this = TStaticMethod(_, result) }
|
|
|
|
override ClassDecl getClassDeclaration() { none() }
|
|
|
|
override boolean isClass() { result = false }
|
|
|
|
override ObjectInternal getClass() { result = ObjectInternal::builtin("staticmethod") }
|
|
|
|
override predicate notTestableForEquality() { none() }
|
|
|
|
override Builtin getBuiltin() { none() }
|
|
|
|
override ControlFlowNode getOrigin() { this = TStaticMethod(result, _) }
|
|
|
|
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
|
none()
|
|
}
|
|
|
|
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
|
|
|
override int intValue() { none() }
|
|
|
|
override string strValue() { none() }
|
|
|
|
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
|
this.getFunction().calleeAndOffset(scope, paramOffset)
|
|
}
|
|
|
|
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
|
|
|
override predicate attributesUnknown() { none() }
|
|
|
|
override predicate subscriptUnknown() { none() }
|
|
|
|
override boolean isDescriptor() { result = true }
|
|
|
|
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()
|
|
}
|
|
|
|
override int length() { none() }
|
|
|
|
override string getName() { result = this.getFunction().getName() }
|
|
|
|
override predicate contextSensitiveCallee() { none() }
|
|
|
|
override predicate useOriginAsLegacyObject() { none() }
|
|
|
|
/* Staticmethods aren't iterable */
|
|
override ObjectInternal getIterNext() { none() }
|
|
|
|
override predicate isNotSubscriptedType() { any() }
|
|
}
|