mirror of
https://github.com/github/codeql.git
synced 2025-12-19 10:23:15 +01:00
Python: Autoformat objects.
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -8,9 +6,7 @@ private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
|
||||
abstract class CallableObjectInternal extends ObjectInternal {
|
||||
|
||||
/** Gets the scope of this callable if it has one */
|
||||
abstract Function getScope();
|
||||
|
||||
@@ -26,7 +22,10 @@ abstract class CallableObjectInternal extends ObjectInternal {
|
||||
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
|
||||
pragma[noinline]
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
none()
|
||||
}
|
||||
|
||||
abstract NameNode getParameter(int n);
|
||||
|
||||
@@ -36,11 +35,11 @@ abstract class CallableObjectInternal extends ObjectInternal {
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { none() }
|
||||
|
||||
@@ -50,12 +49,10 @@ abstract class CallableObjectInternal extends ObjectInternal {
|
||||
|
||||
/* Callables aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** Class representing Python functions */
|
||||
class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject {
|
||||
|
||||
override Function getScope() {
|
||||
exists(CallableExpr expr |
|
||||
this = TPythonFunctionObject(expr.getAFlowNode()) and
|
||||
@@ -63,9 +60,7 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Function " + this.getScope().getQualifiedName()
|
||||
}
|
||||
override string toString() { result = "Function " + this.getScope().getQualifiedName() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
this = TPythonFunctionObject(node) and context.appliesTo(node)
|
||||
@@ -77,19 +72,16 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TPythonFunctionObject(result)
|
||||
}
|
||||
override ControlFlowNode getOrigin() { this = TPythonFunctionObject(result) }
|
||||
|
||||
pragma [nomagic]
|
||||
pragma[nomagic]
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
exists(Function func, ControlFlowNode rval, ControlFlowNode forigin |
|
||||
func = this.getScope() and
|
||||
callee.appliesToScope(func) |
|
||||
callee.appliesToScope(func)
|
||||
|
|
||||
rval = func.getAReturnValueFlowNode() and
|
||||
PointsToInternal::pointsTo(rval, callee, obj, forigin) and
|
||||
origin = CfgOrigin::fromCfgNode(forigin)
|
||||
@@ -98,17 +90,20 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
|
||||
procedureReturnsNone(callee, obj, origin)
|
||||
}
|
||||
|
||||
private predicate procedureReturnsNone(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
private predicate procedureReturnsNone(
|
||||
PointsToContext callee, ObjectInternal obj, CfgOrigin origin
|
||||
) {
|
||||
exists(Function func |
|
||||
func = this.getScope() and
|
||||
callee.appliesToScope(func) |
|
||||
callee.appliesToScope(func)
|
||||
|
|
||||
PointsToInternal::reachableBlock(blockReturningNone(func), callee) and
|
||||
obj = ObjectInternal::none_() and
|
||||
origin = CfgOrigin::unknown()
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
this.getScope().isProcedure() and
|
||||
obj = ObjectInternal::none_() and
|
||||
@@ -119,41 +114,37 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
|
||||
scope = this.getScope() and paramOffset = 0
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = this.getScope().getName()
|
||||
}
|
||||
override string getName() { result = this.getScope().getName() }
|
||||
|
||||
override boolean isDescriptor() { result = true }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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())
|
||||
value = this and
|
||||
origin = CfgOrigin::fromCfgNode(this.getOrigin())
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
|
||||
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
|
||||
exists(BoundMethodObjectInternal bm |
|
||||
bm.getACall(ctx) = result and this = bm.getFunction()
|
||||
)
|
||||
exists(BoundMethodObjectInternal bm | bm.getACall(ctx) = result and this = bm.getFunction())
|
||||
}
|
||||
|
||||
override NameNode getParameter(int n) {
|
||||
result.getNode() = this.getScope().getArg(n)
|
||||
}
|
||||
override NameNode getParameter(int n) { result.getNode() = this.getScope().getArg(n) }
|
||||
|
||||
override NameNode getParameterByName(string name) {
|
||||
result.getNode() = this.getScope().getArgByName(name)
|
||||
}
|
||||
|
||||
|
||||
override predicate neverReturns() {
|
||||
InterProceduralPointsTo::neverReturns(this.getScope())
|
||||
}
|
||||
override predicate neverReturns() { InterProceduralPointsTo::neverReturns(this.getScope()) }
|
||||
|
||||
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
|
||||
function = this and offset = 0
|
||||
@@ -164,10 +155,8 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
private BasicBlock blockReturningNone(Function func) {
|
||||
exists(Return ret |
|
||||
not exists(ret.getValue()) and
|
||||
@@ -176,38 +165,31 @@ private BasicBlock blockReturningNone(Function func) {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/** Class representing built-in functions such as `len` or `print`. */
|
||||
class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunctionObject {
|
||||
override Builtin getBuiltin() { this = TBuiltinFunctionObject(result) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinFunctionObject(result)
|
||||
}
|
||||
override string toString() { result = "Builtin-function " + this.getBuiltin().getName() }
|
||||
|
||||
override string toString() {
|
||||
result = "Builtin-function " + this.getBuiltin().getName()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
exists(Builtin func, BuiltinClassObjectInternal cls |
|
||||
func = this.getBuiltin() and
|
||||
func != Builtin::builtin("isinstance") and
|
||||
func != Builtin::builtin("issubclass") and
|
||||
func != Builtin::builtin("callable") and
|
||||
cls = ObjectInternal::fromBuiltin(this.getReturnType()) |
|
||||
cls = ObjectInternal::fromBuiltin(this.getReturnType())
|
||||
|
|
||||
obj = TUnknownInstance(cls)
|
||||
or
|
||||
cls = ObjectInternal::noneType() and obj = ObjectInternal::none_()
|
||||
@@ -221,17 +203,11 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
|
||||
origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getBuiltin().getName()
|
||||
}
|
||||
override string getName() { result = this.getBuiltin().getName() }
|
||||
|
||||
Builtin getReturnType() {
|
||||
exists(Builtin func |
|
||||
@@ -251,21 +227,25 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override CallNode getACall(PointsToContext ctx) {
|
||||
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
|
||||
}
|
||||
|
||||
override NameNode getParameter(int n) {
|
||||
none()
|
||||
}
|
||||
override NameNode getParameter(int n) { none() }
|
||||
|
||||
override NameNode getParameterByName(string name) {
|
||||
none()
|
||||
}
|
||||
override NameNode getParameterByName(string name) { none() }
|
||||
|
||||
override predicate neverReturns() {
|
||||
exists(ModuleObjectInternal sys |
|
||||
@@ -283,7 +263,6 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
private Builtin getBuiltinFunctionReturnType(Builtin func) {
|
||||
@@ -297,7 +276,8 @@ private Builtin getBuiltinFunctionReturnType(Builtin func) {
|
||||
func = Builtin::builtin("__import__") and result = Builtin::special("ModuleType")
|
||||
or
|
||||
/* Fix a few minor inaccuracies in the CPython analysis */
|
||||
ext_rettype(func, result) and not (
|
||||
ext_rettype(func, result) and
|
||||
not (
|
||||
func = Builtin::builtin("__import__")
|
||||
or
|
||||
func = Builtin::builtin("compile") and result = Builtin::special("NoneType")
|
||||
@@ -309,34 +289,27 @@ private Builtin getBuiltinFunctionReturnType(Builtin func) {
|
||||
}
|
||||
|
||||
/** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`. */
|
||||
|
||||
class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethodObject {
|
||||
override Builtin getBuiltin() { this = TBuiltinMethodObject(result) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinMethodObject(result)
|
||||
}
|
||||
override string toString() { result = "builtin method " + this.getBuiltin().getName() }
|
||||
|
||||
override string toString() {
|
||||
result = "builtin method " + this.getBuiltin().getName()
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
exists(Builtin func, BuiltinClassObjectInternal cls |
|
||||
func = this.getBuiltin() and
|
||||
cls = ObjectInternal::fromBuiltin(this.getReturnType()) |
|
||||
cls = ObjectInternal::fromBuiltin(this.getReturnType())
|
||||
|
|
||||
obj = TUnknownInstance(cls)
|
||||
or
|
||||
cls = ObjectInternal::noneType() and obj = ObjectInternal::none_()
|
||||
@@ -352,41 +325,34 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
|
||||
|
||||
Builtin getReturnType() {
|
||||
/* If we have a record of the return type in our stubs, use that. */
|
||||
exists(Builtin func |
|
||||
func = this.getBuiltin() |
|
||||
ext_rettype(func, result)
|
||||
)
|
||||
exists(Builtin func | func = this.getBuiltin() | ext_rettype(func, result))
|
||||
}
|
||||
|
||||
private predicate returnTypeUnknown() {
|
||||
exists(Builtin func |
|
||||
func = this.getBuiltin() |
|
||||
not ext_rettype(func, _)
|
||||
)
|
||||
exists(Builtin func | func = this.getBuiltin() | not ext_rettype(func, _))
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getBuiltin().getName()
|
||||
}
|
||||
override string getName() { result = this.getBuiltin().getName() }
|
||||
|
||||
override Function getScope() { none() }
|
||||
|
||||
override boolean isDescriptor() { result = true }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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::unknown()
|
||||
value = this and
|
||||
origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
value = TBoundMethod(instance, this) and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
@@ -394,13 +360,9 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
|
||||
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
|
||||
}
|
||||
|
||||
override NameNode getParameter(int n) {
|
||||
none()
|
||||
}
|
||||
override NameNode getParameter(int n) { none() }
|
||||
|
||||
override NameNode getParameterByName(string name) {
|
||||
none()
|
||||
}
|
||||
override NameNode getParameterByName(string name) { none() }
|
||||
|
||||
override predicate neverReturns() { none() }
|
||||
|
||||
@@ -413,27 +375,20 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
/** Class representing bound-methods.
|
||||
/**
|
||||
* Class representing bound-methods.
|
||||
* Note that built-in methods, such as `[].append` are also represented as bound-methods.
|
||||
* Although built-in methods and bound-methods are distinct classes in CPython, their behaviour
|
||||
* is the same and we treat them identically.
|
||||
*/
|
||||
class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
CallableObjectInternal getFunction() { this = TBoundMethod(_, result) }
|
||||
|
||||
CallableObjectInternal getFunction() {
|
||||
this = TBoundMethod(_, result)
|
||||
}
|
||||
|
||||
ObjectInternal getSelf() {
|
||||
this = TBoundMethod(result, _)
|
||||
}
|
||||
ObjectInternal getSelf() { this = TBoundMethod(result, _) }
|
||||
|
||||
override string toString() {
|
||||
result = "Method(" + this.getFunction() + ", " + this.getSelf() + ")"
|
||||
@@ -443,9 +398,7 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
|
||||
result = TBuiltinClassObject(Builtin::special("MethodType"))
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
@@ -457,43 +410,41 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
|
||||
this.getFunction().callResult(obj, origin)
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
this.getFunction().calleeAndOffset(scope, paramOffset-1)
|
||||
this.getFunction().calleeAndOffset(scope, paramOffset - 1)
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = this.getFunction().getName()
|
||||
}
|
||||
override string getName() { result = this.getFunction().getName() }
|
||||
|
||||
override Function getScope() {
|
||||
result = this.getFunction().getScope()
|
||||
}
|
||||
override Function getScope() { result = this.getFunction().getScope() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override CallNode getACall(PointsToContext ctx) {
|
||||
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
|
||||
}
|
||||
|
||||
override NameNode getParameter(int n) {
|
||||
result = this.getFunction().getParameter(n+1)
|
||||
}
|
||||
override NameNode getParameter(int n) { result = this.getFunction().getParameter(n + 1) }
|
||||
|
||||
override NameNode getParameterByName(string name) {
|
||||
result = this.getFunction().getParameterByName(name)
|
||||
}
|
||||
|
||||
override predicate neverReturns() {
|
||||
this.getFunction().neverReturns()
|
||||
}
|
||||
override predicate neverReturns() { this.getFunction().neverReturns() }
|
||||
|
||||
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
|
||||
function = this.getFunction() and offset = 1
|
||||
@@ -501,10 +452,7 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
|
||||
|
||||
override predicate useOriginAsLegacyObject() { any() }
|
||||
|
||||
override predicate contextSensitiveCallee() {
|
||||
this.getFunction().contextSensitiveCallee()
|
||||
}
|
||||
override predicate contextSensitiveCallee() { this.getFunction().contextSensitiveCallee() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import python
|
||||
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -10,19 +8,16 @@ private import semmle.python.types.Builtins
|
||||
|
||||
/** Class representing classes */
|
||||
abstract class ClassObjectInternal extends ObjectInternal {
|
||||
override string getName() { result = this.getClassDeclaration().getName() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getClassDeclaration().getName()
|
||||
}
|
||||
|
||||
/** Holds if this is a class whose instances we treat specially, rather than as a generic instance.
|
||||
/**
|
||||
* Holds if this is a class whose instances we treat specially, rather than as a generic instance.
|
||||
* For example, `type` or `int`.
|
||||
*/
|
||||
boolean isSpecial() {
|
||||
result = Types::getMro(this).containsSpecial()
|
||||
}
|
||||
boolean isSpecial() { result = Types::getMro(this).containsSpecial() }
|
||||
|
||||
/** Looks up the attribute `name` on this class.
|
||||
/**
|
||||
* Looks up the attribute `name` on this class.
|
||||
* Note that this may be different from `this.attr(name)`.
|
||||
* For example given the class:
|
||||
* ```class C:
|
||||
@@ -51,11 +46,20 @@ abstract class ClassObjectInternal extends ObjectInternal {
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
pragma[noinline]
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
instance = this and
|
||||
PointsToInternal::attributeRequired(this, name) and
|
||||
this.lookup(name, descriptor, _) and
|
||||
@@ -63,11 +67,14 @@ abstract class ClassObjectInternal extends ObjectInternal {
|
||||
}
|
||||
|
||||
/** Approximation to descriptor protocol, skipping meta-descriptor protocol */
|
||||
pragma [noinline] 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) |
|
||||
this.lookup(name, descriptor, desc_origin)
|
||||
|
|
||||
descriptor.isDescriptor() = false and
|
||||
value = descriptor and origin = desc_origin
|
||||
value = descriptor and
|
||||
origin = desc_origin
|
||||
or
|
||||
descriptor.isDescriptor() = true and
|
||||
descriptor.descriptorGetClass(this, value, origin)
|
||||
@@ -80,13 +87,9 @@ abstract class ClassObjectInternal extends ObjectInternal {
|
||||
|
||||
override boolean isClass() { result = true }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { none() }
|
||||
|
||||
@@ -104,12 +107,10 @@ abstract class ClassObjectInternal extends ObjectInternal {
|
||||
}
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
/** Class representing Python source classes */
|
||||
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {
|
||||
|
||||
/** Gets the scope for this Python class */
|
||||
Class getScope() {
|
||||
exists(ClassExpr expr |
|
||||
@@ -118,34 +119,24 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "class " + this.getScope().getName()
|
||||
}
|
||||
override string toString() { result = "class " + this.getScope().getName() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
this = TPythonClassObject(node) and context.appliesTo(node)
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
this = TPythonClassObject(result)
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { this = TPythonClassObject(result) }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = Types::getMetaClass(this)
|
||||
}
|
||||
override ObjectInternal getClass() { result = Types::getMetaClass(this) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TPythonClassObject(result)
|
||||
}
|
||||
override ControlFlowNode getOrigin() { this = TPythonClassObject(result) }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
exists(PythonFunctionObjectInternal init |
|
||||
this.lookup("__init__", init, _) and
|
||||
init.calleeAndOffset(scope, paramOffset-1)
|
||||
init.calleeAndOffset(scope, paramOffset - 1)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -153,7 +144,8 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
|
||||
Types::getMro(this).lookup(name, value, origin)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
@@ -169,27 +161,17 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
|
||||
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
|
||||
this.lookup("__init__", function, _) and offset = 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Class representing built-in classes, except `type` */
|
||||
class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObject {
|
||||
override Builtin getBuiltin() { this = TBuiltinClassObject(result) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinClassObject(result)
|
||||
}
|
||||
override string toString() { result = "builtin-class " + this.getBuiltin().getName() }
|
||||
|
||||
override string toString() {
|
||||
result = "builtin-class " + this.getBuiltin().getName()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
this = TBuiltinClassObject(result)
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { this = TBuiltinClassObject(result) }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
@@ -198,19 +180,16 @@ class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObjec
|
||||
result = TType()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
Types::getMro(this).lookup(name, value, origin)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
@@ -222,33 +201,21 @@ class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObjec
|
||||
}
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** A class representing an unknown class */
|
||||
class UnknownClassInternal extends ClassObjectInternal, TUnknownClass {
|
||||
override string toString() { result = "Unknown class" }
|
||||
|
||||
override string toString() {
|
||||
result = "Unknown class"
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { result = Builtin::unknownType() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
result = Builtin::unknownType()
|
||||
}
|
||||
override ObjectInternal getClass() { result = this }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = this
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result = Builtin::unknownType()
|
||||
}
|
||||
override Builtin getBuiltin() { result = Builtin::unknownType() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
@@ -258,134 +225,94 @@ class UnknownClassInternal extends ClassObjectInternal, TUnknownClass {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
}
|
||||
|
||||
/** A class representing the built-in class `type`. */
|
||||
class TypeInternal extends ClassObjectInternal, TType {
|
||||
override string toString() { result = "builtin-class type" }
|
||||
|
||||
override string toString() {
|
||||
result = "builtin-class type"
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { result = Builtin::special("type") }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
result = Builtin::special("type")
|
||||
}
|
||||
override ObjectInternal getClass() { result = this }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = this
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result = Builtin::special("type")
|
||||
}
|
||||
override Builtin getBuiltin() { result = Builtin::special("type") }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
Types::getMro(this).lookup(name, value, origin)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
}
|
||||
|
||||
/** A class representing a dynamically created class `type(name, *args, **kwargs)`. */
|
||||
class DynamicallyCreatedClass extends ClassObjectInternal, TDynamicClass {
|
||||
override string toString() { result = this.getOrigin().getNode().toString() }
|
||||
|
||||
override string toString() {
|
||||
result = this.getOrigin().getNode().toString()
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
this = TDynamicClass(_, result, _)
|
||||
}
|
||||
override ObjectInternal getClass() { this = TDynamicClass(_, result, _) }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
override predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
exists(ClassObjectInternal decl |
|
||||
decl = Types::getMro(this).findDeclaringClass(name) |
|
||||
exists(ClassObjectInternal decl | decl = Types::getMro(this).findDeclaringClass(name) |
|
||||
Types::declaredAttribute(decl, name, value, origin)
|
||||
)
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TDynamicClass(result, _, _)
|
||||
}
|
||||
override ControlFlowNode getOrigin() { this = TDynamicClass(result, _, _) }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
this = TDynamicClass(node, _, context)
|
||||
}
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
}
|
||||
|
||||
class SubscriptedTypeInternal extends ObjectInternal, TSubscriptedType {
|
||||
ObjectInternal getGeneric() { this = TSubscriptedType(result, _) }
|
||||
|
||||
ObjectInternal getGeneric() {
|
||||
this = TSubscriptedType(result, _)
|
||||
}
|
||||
|
||||
ObjectInternal getSpecializer() {
|
||||
this = TSubscriptedType(_, result)
|
||||
}
|
||||
ObjectInternal getSpecializer() { this = TSubscriptedType(_, result) }
|
||||
|
||||
override string getName() { result = this.getGeneric().getName() }
|
||||
|
||||
override string toString() { result = this.getGeneric().toString() + "[" + this.getSpecializer().toString() + "]" }
|
||||
override string toString() {
|
||||
result = this.getGeneric().toString() + "[" + this.getSpecializer().toString() + "]"
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
exists(ObjectInternal generic, ObjectInternal index |
|
||||
@@ -395,16 +322,12 @@ class SubscriptedTypeInternal extends ObjectInternal, TSubscriptedType {
|
||||
}
|
||||
|
||||
/** Gets the class declaration for this object, if it is a class with a declaration. */
|
||||
override ClassDecl getClassDeclaration() {
|
||||
result = this.getGeneric().getClassDeclaration()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { result = this.getGeneric().getClassDeclaration() }
|
||||
|
||||
/** True if this "object" is a class. That is, its class inherits from `type` */
|
||||
override boolean isClass() { result = true }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = this.getGeneric().getClass()
|
||||
}
|
||||
override ObjectInternal getClass() { result = this.getGeneric().getClass() }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
@@ -414,9 +337,11 @@ class SubscriptedTypeInternal extends ObjectInternal, TSubscriptedType {
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset){ none() }
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
@@ -424,17 +349,25 @@ class SubscriptedTypeInternal extends ObjectInternal, TSubscriptedType {
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
none()
|
||||
}
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
override int intValue() { none()}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() { none() }
|
||||
|
||||
@@ -448,8 +381,4 @@ class SubscriptedTypeInternal extends ObjectInternal, TSubscriptedType {
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate isNotSubscriptedType() { none() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -7,16 +6,13 @@ private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
|
||||
/** Class representing constants.
|
||||
/**
|
||||
* Class representing constants.
|
||||
* Includes `None`, `True` and `False` as
|
||||
* well as strings and integers.
|
||||
*/
|
||||
abstract class ConstantObjectInternal extends ObjectInternal {
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
@@ -32,33 +28,41 @@ abstract class ConstantObjectInternal extends ObjectInternal {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] 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
|
||||
exists(ObjectInternal cls_attr, CfgOrigin attr_orig |
|
||||
this.getClass().(ClassObjectInternal).lookup(name, cls_attr, attr_orig) and
|
||||
cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin)
|
||||
cls_attr.isDescriptor() = true and
|
||||
cls_attr.descriptorGetInstance(this, value, origin)
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { none() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
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
|
||||
@@ -77,29 +81,23 @@ abstract class ConstantObjectInternal extends ObjectInternal {
|
||||
abstract ImmutableLiteral getLiteral();
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private boolean callToBool(CallNode call, PointsToContext context) {
|
||||
PointsToInternal::pointsTo(call.getFunction(), context, ClassValue::bool(), _) and
|
||||
exists(ObjectInternal arg |
|
||||
PointsToInternal::pointsTo(call.getArg(0),context, arg, _) and
|
||||
PointsToInternal::pointsTo(call.getArg(0), context, arg, _) and
|
||||
arg.booleanValue() = result
|
||||
)
|
||||
}
|
||||
|
||||
private abstract class BooleanObjectInternal extends ConstantObjectInternal {
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = ClassValue::bool()
|
||||
}
|
||||
abstract private class BooleanObjectInternal extends ConstantObjectInternal {
|
||||
override ObjectInternal getClass() { result = ClassValue::bool() }
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
/* Booleans aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
@@ -107,18 +105,12 @@ private abstract class BooleanObjectInternal extends ConstantObjectInternal {
|
||||
override ImmutableLiteral getLiteral() {
|
||||
result.(BooleanLiteral).booleanValue() = this.booleanValue()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TrueObjectInternal extends BooleanObjectInternal, TTrue {
|
||||
override string toString() { result = "bool True" }
|
||||
|
||||
override string toString() {
|
||||
result = "bool True"
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
node.(NameNode).getId() = "True" and context.appliesTo(node)
|
||||
@@ -126,25 +118,15 @@ private class TrueObjectInternal extends BooleanObjectInternal, TTrue {
|
||||
callToBool(node, context) = true
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
result = 1
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result = Builtin::special("True")
|
||||
}
|
||||
override int intValue() { result = 1 }
|
||||
|
||||
override Builtin getBuiltin() { result = Builtin::special("True") }
|
||||
}
|
||||
|
||||
private class FalseObjectInternal extends BooleanObjectInternal, TFalse {
|
||||
override string toString() { result = "bool False" }
|
||||
|
||||
override string toString() {
|
||||
result = "bool False"
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = false
|
||||
}
|
||||
override boolean booleanValue() { result = false }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
node.(NameNode).getId() = "False" and context.appliesTo(node)
|
||||
@@ -152,84 +134,51 @@ private class FalseObjectInternal extends BooleanObjectInternal, TFalse {
|
||||
callToBool(node, context) = false
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
result = 0
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result = Builtin::special("False")
|
||||
}
|
||||
override int intValue() { result = 0 }
|
||||
|
||||
override Builtin getBuiltin() { result = Builtin::special("False") }
|
||||
}
|
||||
|
||||
private class NoneObjectInternal extends ConstantObjectInternal, TNone {
|
||||
override string toString() { result = "None" }
|
||||
|
||||
override string toString() {
|
||||
result = "None"
|
||||
}
|
||||
override boolean booleanValue() { result = false }
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = false
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("NoneType"))
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("NoneType")) }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
node.(NameNode).getId() = "None" and context.appliesTo(node)
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result = Builtin::special("None")
|
||||
}
|
||||
override Builtin getBuiltin() { result = Builtin::special("None") }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
/* None isn't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override ImmutableLiteral getLiteral() {
|
||||
result instanceof None
|
||||
}
|
||||
|
||||
override ImmutableLiteral getLiteral() { result instanceof None }
|
||||
}
|
||||
|
||||
|
||||
class IntObjectInternal extends ConstantObjectInternal, TInt {
|
||||
|
||||
override string toString() {
|
||||
result = "int " + this.intValue().toString()
|
||||
}
|
||||
override string toString() { result = "int " + this.intValue().toString() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
context.appliesTo(node) and
|
||||
node.getNode().(IntegerLiteral).getValue() = this.intValue()
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("int"))
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("int")) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result.intValue() = this.intValue()
|
||||
}
|
||||
override Builtin getBuiltin() { result.intValue() = this.intValue() }
|
||||
|
||||
override int intValue() {
|
||||
this = TInt(result)
|
||||
}
|
||||
override int intValue() { this = TInt(result) }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.intValue() = 0 and result = false
|
||||
@@ -247,17 +196,13 @@ class IntObjectInternal extends ConstantObjectInternal, TInt {
|
||||
or
|
||||
result.(NegativeIntegerLiteral).getOperand().(IntegerLiteral).getValue() = -this.intValue()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FloatObjectInternal extends ConstantObjectInternal, TFloat {
|
||||
|
||||
override string toString() {
|
||||
if this.floatValue() = this.floatValue().floor() then (
|
||||
result = "float " + this.floatValue().floor().toString() + ".0"
|
||||
) else (
|
||||
result = "float " + this.floatValue().toString()
|
||||
)
|
||||
if this.floatValue() = this.floatValue().floor()
|
||||
then result = "float " + this.floatValue().floor().toString() + ".0"
|
||||
else result = "float " + this.floatValue().toString()
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
@@ -265,25 +210,15 @@ class FloatObjectInternal extends ConstantObjectInternal, TFloat {
|
||||
node.getNode().(FloatLiteral).getValue() = this.floatValue()
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("float"))
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("float")) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result.floatValue() = this.floatValue()
|
||||
}
|
||||
override Builtin getBuiltin() { result.floatValue() = this.floatValue() }
|
||||
|
||||
float floatValue() {
|
||||
this = TFloat(result)
|
||||
}
|
||||
float floatValue() { this = TFloat(result) }
|
||||
|
||||
override int intValue() {
|
||||
this = TFloat(result)
|
||||
}
|
||||
override int intValue() { this = TFloat(result) }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.floatValue() = 0.0 and result = false
|
||||
@@ -296,18 +231,11 @@ class FloatObjectInternal extends ConstantObjectInternal, TFloat {
|
||||
/* floats aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override ImmutableLiteral getLiteral() {
|
||||
result.(FloatLiteral).getValue() = this.floatValue()
|
||||
}
|
||||
|
||||
override ImmutableLiteral getLiteral() { result.(FloatLiteral).getValue() = this.floatValue() }
|
||||
}
|
||||
|
||||
|
||||
class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
|
||||
|
||||
override string toString() {
|
||||
result = "'" + this.strValue() + "'"
|
||||
}
|
||||
override string toString() { result = "'" + this.strValue() + "'" }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
context.appliesTo(node) and
|
||||
@@ -315,22 +243,16 @@ class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
|
||||
node.getNode().(StrConst).isUnicode()
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("unicode"))
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("unicode")) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result.(Builtin).strValue() = this.strValue() and
|
||||
result.getClass() = Builtin::special("unicode")
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
this = TUnicode(result)
|
||||
}
|
||||
override string strValue() { this = TUnicode(result) }
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.strValue() = "" and result = false
|
||||
@@ -338,25 +260,15 @@ class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
|
||||
this.strValue() != "" and result = true
|
||||
}
|
||||
|
||||
override int length() {
|
||||
result = this.strValue().length()
|
||||
}
|
||||
override int length() { result = this.strValue().length() }
|
||||
|
||||
override ObjectInternal getIterNext() {
|
||||
result = TUnknownInstance(this.getClass())
|
||||
}
|
||||
|
||||
override ImmutableLiteral getLiteral() {
|
||||
result.(Unicode).getText() = this.strValue()
|
||||
}
|
||||
override ObjectInternal getIterNext() { result = TUnknownInstance(this.getClass()) }
|
||||
|
||||
override ImmutableLiteral getLiteral() { result.(Unicode).getText() = this.strValue() }
|
||||
}
|
||||
|
||||
class BytesObjectInternal extends ConstantObjectInternal, TBytes {
|
||||
|
||||
override string toString() {
|
||||
result = "'" + this.strValue() + "'"
|
||||
}
|
||||
override string toString() { result = "'" + this.strValue() + "'" }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
context.appliesTo(node) and
|
||||
@@ -364,22 +276,16 @@ class BytesObjectInternal extends ConstantObjectInternal, TBytes {
|
||||
not node.getNode().(StrConst).isUnicode()
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("bytes"))
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(Builtin::special("bytes")) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result.(Builtin).strValue() = this.strValue() and
|
||||
result.getClass() = Builtin::special("bytes")
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
this = TBytes(result)
|
||||
}
|
||||
override string strValue() { this = TBytes(result) }
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.strValue() = "" and result = false
|
||||
@@ -387,20 +293,9 @@ class BytesObjectInternal extends ConstantObjectInternal, TBytes {
|
||||
this.strValue() != "" and result = true
|
||||
}
|
||||
|
||||
override int length() {
|
||||
result = this.strValue().length()
|
||||
}
|
||||
override int length() { result = this.strValue().length() }
|
||||
|
||||
override ObjectInternal getIterNext() {
|
||||
result = TUnknownInstance(this.getClass())
|
||||
}
|
||||
|
||||
override ImmutableLiteral getLiteral() {
|
||||
result.(Bytes).getText() = this.strValue()
|
||||
}
|
||||
override ObjectInternal getIterNext() { result = TUnknownInstance(this.getClass()) }
|
||||
|
||||
override ImmutableLiteral getLiteral() { result.(Bytes).getText() = this.strValue() }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -9,16 +8,11 @@ private import semmle.python.types.Builtins
|
||||
|
||||
/** Class representing property objects in Python */
|
||||
class PropertyInternal extends ObjectInternal, TProperty {
|
||||
|
||||
/** Gets the name of this property */
|
||||
override string getName() {
|
||||
result = this.getGetter().getName()
|
||||
}
|
||||
override string getName() { result = this.getGetter().getName() }
|
||||
|
||||
/** Gets the getter function of this property */
|
||||
CallableObjectInternal getGetter() {
|
||||
this = TProperty(_, _, result)
|
||||
}
|
||||
CallableObjectInternal getGetter() { this = TProperty(_, _, result) }
|
||||
|
||||
private CallNode getCallNode() { this = TProperty(result, _, _) }
|
||||
|
||||
@@ -55,11 +49,9 @@ class PropertyInternal extends ObjectInternal, TProperty {
|
||||
)
|
||||
}
|
||||
|
||||
private Context getContext() { this = TProperty(_,result, _) }
|
||||
private Context getContext() { this = TProperty(_, result, _) }
|
||||
|
||||
override string toString() {
|
||||
result = "property " + this.getName()
|
||||
}
|
||||
override string toString() { result = "property " + this.getName() }
|
||||
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
@@ -79,7 +71,9 @@ class PropertyInternal extends ObjectInternal, TProperty {
|
||||
|
||||
override ControlFlowNode getOrigin() { this = TProperty(result, _, _) }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
@@ -89,7 +83,8 @@ class PropertyInternal extends ObjectInternal, TProperty {
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
value = TPropertySetterOrDeleter(this, name) and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
@@ -103,20 +98,28 @@ class PropertyInternal extends ObjectInternal, TProperty {
|
||||
|
||||
override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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())
|
||||
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
|
||||
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()
|
||||
origin = CfgOrigin::unknown() and
|
||||
value = ObjectInternal::unknown()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -128,40 +131,31 @@ class PropertyInternal extends ObjectInternal, TProperty {
|
||||
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 toString() {
|
||||
result = this.getProperty().toString() + "." + this.getName()
|
||||
}
|
||||
override string getName() { this = TPropertySetterOrDeleter(_, result) }
|
||||
|
||||
override string getName() {
|
||||
this = TPropertySetterOrDeleter(_, result)
|
||||
}
|
||||
|
||||
PropertyInternal getProperty() {
|
||||
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
|
||||
obj = this.getProperty() and
|
||||
obj = TProperty(call, _, _) and
|
||||
origin = CfgOrigin::fromCfgNode(call)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
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"))
|
||||
result = TBuiltinClassObject(Builtin::special("MethodType"))
|
||||
}
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
@@ -170,7 +164,9 @@ private class PropertySetterOrDeleter extends ObjectInternal, TPropertySetterOrD
|
||||
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override int intValue() { none() }
|
||||
|
||||
@@ -196,23 +192,24 @@ private class PropertySetterOrDeleter extends ObjectInternal, TPropertySetterOrD
|
||||
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate descriptorGetInstance(ObjectInternal instance, 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 string toString() { result = "classmethod(" + this.getFunction() + ")" }
|
||||
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
@@ -224,9 +221,7 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
||||
}
|
||||
|
||||
/** Gets the function wrapped by this classmethod object */
|
||||
CallableObjectInternal getFunction() {
|
||||
this = TClassMethod(_, result)
|
||||
}
|
||||
CallableObjectInternal getFunction() { this = TClassMethod(_, result) }
|
||||
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
@@ -240,7 +235,9 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
||||
|
||||
override ControlFlowNode getOrigin() { this = TClassMethod(result, _) }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
@@ -258,26 +255,31 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
||||
|
||||
override boolean isDescriptor() { result = true }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
|
||||
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) {
|
||||
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`.
|
||||
/**
|
||||
* 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) {
|
||||
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) |
|
||||
exists(ObjectInternal instance | any(ObjectInternal obj).binds(instance, name, this) |
|
||||
instance.isClass() = false and cls = instance.getClass()
|
||||
or
|
||||
instance.isClass() = true and cls = instance
|
||||
@@ -286,9 +288,7 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getFunction().getName()
|
||||
}
|
||||
override string getName() { result = this.getFunction().getName() }
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
@@ -298,14 +298,10 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
|
||||
override string toString() {
|
||||
result = "staticmethod()"
|
||||
}
|
||||
override string toString() { result = "staticmethod()" }
|
||||
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
@@ -316,9 +312,7 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
)
|
||||
}
|
||||
|
||||
CallableObjectInternal getFunction() {
|
||||
this = TStaticMethod(_, result)
|
||||
}
|
||||
CallableObjectInternal getFunction() { this = TStaticMethod(_, result) }
|
||||
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
@@ -332,7 +326,9 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
|
||||
override ControlFlowNode getOrigin() { this = TStaticMethod(result, _) }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
@@ -352,23 +348,29 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
|
||||
override boolean isDescriptor() { result = true }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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()
|
||||
value = this.getFunction() and
|
||||
origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) {
|
||||
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()
|
||||
value = this.getFunction() and
|
||||
origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
none()
|
||||
}
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getFunction().getName()
|
||||
}
|
||||
override string getName() { result = this.getFunction().getName() }
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
@@ -378,5 +380,4 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import python
|
||||
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -10,18 +8,19 @@ private import semmle.python.types.Builtins
|
||||
|
||||
/** A class representing instances */
|
||||
abstract class InstanceObject extends ObjectInternal {
|
||||
|
||||
pragma [nomagic]
|
||||
pragma[nomagic]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
exists(ObjectInternal cls_attr |
|
||||
this.classAttribute(name, cls_attr)
|
||||
|
|
||||
/* If class attribute is not a descriptor, that usually means it is some sort of
|
||||
exists(ObjectInternal cls_attr | this.classAttribute(name, cls_attr) |
|
||||
/*
|
||||
* If class attribute is not a descriptor, that usually means it is some sort of
|
||||
* default value and likely overridden by an instance attribute. In that case
|
||||
* use `unknown` to signal that an attribute exists but to avoid false positives
|
||||
* f using the default value.
|
||||
*/
|
||||
cls_attr.isDescriptor() = false and value = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
|
||||
cls_attr.isDescriptor() = false and
|
||||
value = ObjectInternal::unknown() and
|
||||
origin = CfgOrigin::unknown()
|
||||
or
|
||||
cls_attr.isDescriptor() = true and cls_attr.descriptorGetInstance(this, value, origin)
|
||||
)
|
||||
@@ -29,13 +28,13 @@ abstract class InstanceObject extends ObjectInternal {
|
||||
this.selfAttribute(name, value, origin)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
private predicate classAttribute(string name, ObjectInternal cls_attr) {
|
||||
PointsToInternal::attributeRequired(this, name) and
|
||||
this.getClass().(ClassObjectInternal).lookup(name, cls_attr, _)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
private predicate selfAttribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
PointsToInternal::attributeRequired(this, name) and
|
||||
exists(EssaVariable self, PythonFunctionObjectInternal init, Context callee |
|
||||
@@ -56,7 +55,6 @@ abstract class InstanceObject extends ObjectInternal {
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
private predicate self_variable_reaching_init_exit(EssaVariable self) {
|
||||
@@ -65,14 +63,12 @@ private predicate self_variable_reaching_init_exit(EssaVariable self) {
|
||||
self.getScope().getName() = "__init__"
|
||||
}
|
||||
|
||||
/** A class representing instances instantiated at a specific point in the program (statically)
|
||||
/**
|
||||
* A class representing instances instantiated at a specific point in the program (statically)
|
||||
* For example the code `C()` would be a specific instance of `C`.
|
||||
*/
|
||||
class SpecificInstanceInternal extends TSpecificInstance, InstanceObject {
|
||||
|
||||
override string toString() {
|
||||
result = this.getOrigin().getNode().toString()
|
||||
}
|
||||
override string toString() { result = this.getOrigin().getNode().toString() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
//result = this.getClass().instancesBooleanValue()
|
||||
@@ -84,9 +80,7 @@ class SpecificInstanceInternal extends TSpecificInstance, InstanceObject {
|
||||
}
|
||||
|
||||
/** Gets the class declaration for this object, if it is a declared class. */
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
@@ -95,64 +89,65 @@ class SpecificInstanceInternal extends TSpecificInstance, InstanceObject {
|
||||
override ObjectInternal getClass() {
|
||||
exists(ClassObjectInternal cls, ClassDecl decl |
|
||||
this = TSpecificInstance(_, cls, _) and
|
||||
decl = cls.getClassDeclaration() |
|
||||
if decl.callReturnsInstance() then
|
||||
result = cls
|
||||
else
|
||||
result = TUnknownClass()
|
||||
decl = cls.getClassDeclaration()
|
||||
|
|
||||
if decl.callReturnsInstance() then result = cls else result = TUnknownClass()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `Builtin` for this object, if any.
|
||||
* All objects (except unknown and undefined values) should return
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
/** Gets a control flow node that represents the source origin of this
|
||||
/**
|
||||
* Gets a control flow node that represents the source origin of this
|
||||
* objects.
|
||||
* All objects (except unknown and undefined values) should return
|
||||
* All objects (except unknown and undefined values) should return
|
||||
* exactly one result for either this method or `getBuiltin()`.
|
||||
*/
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TSpecificInstance(result, _, _)
|
||||
}
|
||||
override ControlFlowNode getOrigin() { this = TSpecificInstance(result, _, _) }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
// TO DO -- Handle cases where class overrides __call__ in more detail, like normal calls.
|
||||
this.getClass().(ClassObjectInternal).lookup("__call__", _, _) and
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
obj = ObjectInternal::unknown() and
|
||||
origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
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
|
||||
@@ -161,9 +156,7 @@ class SpecificInstanceInternal extends TSpecificInstance, InstanceObject {
|
||||
this = instance
|
||||
}
|
||||
|
||||
override int length() {
|
||||
result = lengthFromClass(this.getClass())
|
||||
}
|
||||
override int length() { result = lengthFromClass(this.getClass()) }
|
||||
|
||||
override predicate initializer(PythonFunctionObjectInternal init, Context callee) {
|
||||
exists(CallNode call, Context caller, ClassObjectInternal cls |
|
||||
@@ -174,13 +167,12 @@ class SpecificInstanceInternal extends TSpecificInstance, InstanceObject {
|
||||
}
|
||||
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** A class representing context-free instances represented by `self` in the source code
|
||||
/**
|
||||
* A class representing context-free instances represented by `self` in the source code
|
||||
*/
|
||||
class SelfInstanceInternal extends TSelfInstance, InstanceObject {
|
||||
|
||||
override string toString() {
|
||||
result = "self instance of " + this.getClass().(ClassObjectInternal).getName()
|
||||
}
|
||||
@@ -191,34 +183,24 @@ class SelfInstanceInternal extends TSelfInstance, InstanceObject {
|
||||
result = maybe()
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
predicate parameterAndContext(ParameterDefinition def, PointsToContext context) {
|
||||
this = TSelfInstance(def, context, _)
|
||||
}
|
||||
|
||||
/** Gets the class declaration for this object, if it is a declared class. */
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
this = TSelfInstance(_, _, result)
|
||||
}
|
||||
override ObjectInternal getClass() { this = TSelfInstance(_, _, result) }
|
||||
|
||||
ParameterDefinition getParameter() {
|
||||
this = TSelfInstance(result, _, _)
|
||||
}
|
||||
ParameterDefinition getParameter() { this = TSelfInstance(result, _, _) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
exists(ParameterDefinition def |
|
||||
@@ -231,35 +213,39 @@ class SelfInstanceInternal extends TSelfInstance, InstanceObject {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
// In general instances aren't callable, but some are...
|
||||
// TO DO -- Handle cases where class overrides __call__
|
||||
none()
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
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)
|
||||
@@ -267,9 +253,7 @@ class SelfInstanceInternal extends TSelfInstance, InstanceObject {
|
||||
instance = this
|
||||
}
|
||||
|
||||
override int length() {
|
||||
result = lengthFromClass(this.getClass())
|
||||
}
|
||||
override int length() { result = lengthFromClass(this.getClass()) }
|
||||
|
||||
override predicate initializer(PythonFunctionObjectInternal init, Context callee) {
|
||||
callee.isRuntime() and
|
||||
@@ -278,53 +262,41 @@ class SelfInstanceInternal extends TSelfInstance, InstanceObject {
|
||||
}
|
||||
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** A class representing a value that has a known class, but no other information */
|
||||
class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
|
||||
|
||||
override string toString() {
|
||||
result = "instance of " + this.getClass().(ClassObjectInternal).getName()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = maybe()
|
||||
}
|
||||
override boolean booleanValue() { result = maybe() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
/** Gets the class declaration for this object, if it is a declared class. */
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
this = TUnknownInstance(result)
|
||||
}
|
||||
override ObjectInternal getClass() { this = TUnknownInstance(result) }
|
||||
|
||||
/** Gets the `Builtin` for this object, if any.
|
||||
* All objects (except unknown and undefined values) should return
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
/** Gets a control flow node that represents the source origin of this
|
||||
/**
|
||||
* Gets a control flow node that represents the source origin of this
|
||||
* objects.
|
||||
* All objects (except unknown and undefined values) should return
|
||||
* All objects (except unknown and undefined values) should return
|
||||
* exactly one result for either this method or `getBuiltin()`.
|
||||
*/
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
@@ -336,40 +308,45 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
|
||||
none()
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] 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
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
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)
|
||||
@@ -377,9 +354,7 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
|
||||
instance = this
|
||||
}
|
||||
|
||||
override int length() {
|
||||
result = lengthFromClass(this.getClass())
|
||||
}
|
||||
override int length() { result = lengthFromClass(this.getClass()) }
|
||||
|
||||
override string getName() { none() }
|
||||
|
||||
@@ -390,7 +365,6 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
private int lengthFromClass(ClassObjectInternal cls) {
|
||||
@@ -404,7 +378,6 @@ private predicate cls_descriptor(ClassObjectInternal cls, string name, ObjectInt
|
||||
|
||||
/** A class representing an instance of the `super` class */
|
||||
class SuperInstance extends TSuperInstance, ObjectInternal {
|
||||
|
||||
override string toString() {
|
||||
result = "super(" + this.getStartClass().toString() + ", " + this.getSelf().toString() + ")"
|
||||
}
|
||||
@@ -419,34 +392,28 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
|
||||
}
|
||||
|
||||
/** Gets the class declared as the starting point for MRO lookup. */
|
||||
ClassObjectInternal getStartClass() {
|
||||
this = TSuperInstance(_, result)
|
||||
}
|
||||
ClassObjectInternal getStartClass() { this = TSuperInstance(_, result) }
|
||||
|
||||
/** Gets 'self' object */
|
||||
ObjectInternal getSelf() {
|
||||
this = TSuperInstance(result, _)
|
||||
}
|
||||
ObjectInternal getSelf() { this = TSuperInstance(result, _) }
|
||||
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = ObjectInternal::superType()
|
||||
}
|
||||
override ObjectInternal getClass() { result = ObjectInternal::superType() }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override int intValue() { none() }
|
||||
|
||||
@@ -454,46 +421,60 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
exists(ObjectInternal cls_attr, CfgOrigin attr_orig |
|
||||
this.attribute_descriptor(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)
|
||||
cls_attr.isDescriptor() = true and
|
||||
cls_attr.descriptorGetInstance(this.getSelf(), value, origin)
|
||||
)
|
||||
}
|
||||
|
||||
/* Helper for `attribute` */
|
||||
pragma [noinline] private predicate attribute_descriptor(string name, ObjectInternal cls_attr, CfgOrigin attr_orig) {
|
||||
pragma[noinline]
|
||||
private predicate attribute_descriptor(string name, ObjectInternal cls_attr, CfgOrigin attr_orig) {
|
||||
PointsToInternal::attributeRequired(this, name) and
|
||||
this.lookup(name, cls_attr, attr_orig)
|
||||
}
|
||||
|
||||
private predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
Types::getMro(this.getSelf().getClass()).startingAt(this.getStartClass()).getTail().lookup(name, value, 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) {
|
||||
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()
|
||||
}
|
||||
override int length() { none() }
|
||||
|
||||
override string getName() { none() }
|
||||
|
||||
@@ -504,6 +485,4 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -9,7 +8,6 @@ private import semmle.python.types.Builtins
|
||||
|
||||
/** A class representing modules */
|
||||
abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
|
||||
/** Gets the source scope of this module, if it has one. */
|
||||
abstract Module getSourceModule();
|
||||
|
||||
@@ -27,30 +25,35 @@ abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = ObjectInternal::moduleType()
|
||||
}
|
||||
override ObjectInternal getClass() { result = ObjectInternal::moduleType() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] 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() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
/** Holds if this module is a `__init__.py` module. */
|
||||
predicate isInitModule() {
|
||||
any(PackageObjectInternal package).getInitModule() = this
|
||||
}
|
||||
predicate isInitModule() { any(PackageObjectInternal package).getInitModule() = this }
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
@@ -59,14 +62,16 @@ abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
/* Modules aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
/** Holds if this module "exports" name.
|
||||
/**
|
||||
* Holds if this module "exports" name.
|
||||
* That is, does it define `name` in `__all__` or is
|
||||
* `__all__` not defined and `name` a global variable that does not start with "_"
|
||||
* This is the set of names imported by `from ... import *`.
|
||||
*/
|
||||
predicate exports(string name) {
|
||||
not this.(ModuleObjectInternal).attribute("__all__", _, _) and this.hasAttribute(name)
|
||||
and not name.charAt(0) = "_"
|
||||
not this.(ModuleObjectInternal).attribute("__all__", _, _) and
|
||||
this.hasAttribute(name) and
|
||||
not name.charAt(0) = "_"
|
||||
or
|
||||
py_exports(this.getSourceModule(), name)
|
||||
}
|
||||
@@ -75,101 +80,61 @@ abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
abstract predicate hasCompleteExportInfo();
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
/** A class representing built-in modules */
|
||||
class BuiltinModuleObjectInternal extends ModuleObjectInternal, TBuiltinModuleObject {
|
||||
override Builtin getBuiltin() { this = TBuiltinModuleObject(result) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinModuleObject(result)
|
||||
}
|
||||
override string toString() { result = "Module " + this.getBuiltin().getName() }
|
||||
|
||||
override string toString() {
|
||||
result = "Module " + this.getBuiltin().getName()
|
||||
}
|
||||
override string getName() { result = this.getBuiltin().getName() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getBuiltin().getName()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override Module getSourceModule() { none() }
|
||||
|
||||
override Module getSourceModule() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] 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()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate hasCompleteExportInfo() {
|
||||
any()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate hasCompleteExportInfo() { any() }
|
||||
}
|
||||
|
||||
/** A class representing packages */
|
||||
class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "Package " + this.getName()
|
||||
}
|
||||
override string toString() { result = "Package " + this.getName() }
|
||||
|
||||
/** Gets the folder for this package */
|
||||
Folder getFolder() {
|
||||
this = TPackageObject(result)
|
||||
}
|
||||
Folder getFolder() { this = TPackageObject(result) }
|
||||
|
||||
override string getName() {
|
||||
result = moduleNameFromFile(this.getFolder())
|
||||
}
|
||||
override string getName() { result = moduleNameFromFile(this.getFolder()) }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override Module getSourceModule() {
|
||||
result.getFile() = this.getFolder().getFile("__init__.py")
|
||||
}
|
||||
override Module getSourceModule() { result.getFile() = this.getFolder().getFile("__init__.py") }
|
||||
|
||||
/** Gets the init module of this package */
|
||||
PythonModuleObjectInternal getInitModule() {
|
||||
result = TPythonModule(this.getSourceModule())
|
||||
}
|
||||
PythonModuleObjectInternal getInitModule() { result = TPythonModule(this.getSourceModule()) }
|
||||
|
||||
predicate hasNoInitModule() {
|
||||
exists(Folder f |
|
||||
@@ -188,19 +153,14 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
)
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] 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 |
|
||||
@@ -215,12 +175,14 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
this.hasNoInitModule() and
|
||||
exists(ModuleObjectInternal mod |
|
||||
mod = this.submodule(name) and
|
||||
value = mod |
|
||||
value = mod
|
||||
|
|
||||
origin = CfgOrigin::fromObject(mod)
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
exists(Module package |
|
||||
@@ -238,7 +200,6 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
}
|
||||
|
||||
override predicate hasCompleteExportInfo() {
|
||||
|
||||
not exists(this.getInitModule())
|
||||
or
|
||||
this.getInitModule().hasCompleteExportInfo()
|
||||
@@ -247,53 +208,34 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
|
||||
/** A class representing Python modules */
|
||||
class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override string toString() { result = this.getSourceModule().toString() }
|
||||
|
||||
override string toString() {
|
||||
result = this.getSourceModule().toString()
|
||||
}
|
||||
override string getName() { result = this.getSourceModule().getName() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getSourceModule().getName()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override Module getSourceModule() { this = TPythonModule(result) }
|
||||
|
||||
override Module getSourceModule() {
|
||||
this = TPythonModule(result)
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
value != ObjectInternal::undefined() and
|
||||
ModuleAttributes::pointsToAtExit(this.getSourceModule(), name, value, origin)
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
result = this.getSourceModule().getEntryNode()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { result = this.getSourceModule().getEntryNode() }
|
||||
|
||||
/** Holds if this value has the attribute `name` */
|
||||
override predicate hasAttribute(string name) {
|
||||
@@ -317,76 +259,56 @@ class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
|
||||
not exists(Call modify, Attribute attr, GlobalVariable all |
|
||||
modify.getScope() = this.getSourceModule() and
|
||||
modify.getFunc() = attr and
|
||||
all.getId() = "__all__" |
|
||||
all.getId() = "__all__"
|
||||
|
|
||||
attr.getObject().(Name).uses(all)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A class representing a module that is missing from the DB, but inferred to exists from imports. */
|
||||
class AbsentModuleObjectInternal extends ModuleObjectInternal, TAbsentModule {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override string toString() {
|
||||
if exists(Module m, SyntaxError se | se.getFile() = m.getFile() and m.getName() = this.getName()) then
|
||||
result = "Unparsable module " + this.getName()
|
||||
else
|
||||
result = "Missing module " + this.getName()
|
||||
if
|
||||
exists(Module m, SyntaxError se | se.getFile() = m.getFile() and m.getName() = this.getName())
|
||||
then result = "Unparsable module " + this.getName()
|
||||
else result = "Missing module " + this.getName()
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
this = TAbsentModule(result)
|
||||
}
|
||||
override string getName() { this = TAbsentModule(result) }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
missing_imported_module(node, context, this.getName())
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override Module getSourceModule() {
|
||||
none()
|
||||
}
|
||||
override Module getSourceModule() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
value = TAbsentModuleAttribute(this, name) and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate hasCompleteExportInfo() {
|
||||
none()
|
||||
}
|
||||
override predicate hasCompleteExportInfo() { none() }
|
||||
}
|
||||
|
||||
/** A class representing an attribute of a missing module. */
|
||||
class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleAttribute {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override string toString() {
|
||||
exists(ModuleObjectInternal mod, string name |
|
||||
@@ -396,39 +318,28 @@ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleA
|
||||
}
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
exists(ModuleObjectInternal mod, string name |
|
||||
this = TAbsentModuleAttribute(mod, name) |
|
||||
exists(ModuleObjectInternal mod, string name | this = TAbsentModuleAttribute(mod, name) |
|
||||
PointsToInternal::pointsTo(node.(AttrNode).getObject(name), context, mod, _)
|
||||
or
|
||||
PointsToInternal::pointsTo(node.(ImportMemberNode).getModule(name), context, mod, _)
|
||||
)
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
@@ -442,31 +353,36 @@ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleA
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = maybe()
|
||||
}
|
||||
override boolean booleanValue() { result = maybe() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = ObjectInternal::unknownClass()
|
||||
}
|
||||
override ObjectInternal getClass() { result = ObjectInternal::unknownClass() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
none()
|
||||
}
|
||||
|
||||
override int length() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
/* We know what this is called, but not its innate name.
|
||||
* However, if we are looking for things by name, this is a reasonable approximation */
|
||||
override string getName() {
|
||||
this = TAbsentModuleAttribute(_, result)
|
||||
}
|
||||
/*
|
||||
* We know what this is called, but not its innate name.
|
||||
* However, if we are looking for things by name, this is a reasonable approximation
|
||||
*/
|
||||
|
||||
override string getName() { this = TAbsentModuleAttribute(_, result) }
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
@@ -476,5 +392,4 @@ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleA
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,16 +16,17 @@ import semmle.python.objects.Constants
|
||||
import semmle.python.objects.Sequences
|
||||
import semmle.python.objects.Descriptors
|
||||
|
||||
|
||||
class ObjectInternal extends TObject {
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/** The boolean value of this object, this may be both
|
||||
* true and false if the "object" represents a set of possible objects. */
|
||||
/**
|
||||
* The boolean value of this object, this may be both
|
||||
* true and false if the "object" represents a set of possible objects.
|
||||
*/
|
||||
abstract boolean booleanValue();
|
||||
|
||||
/** Holds if this object is introduced into the code base at `node` given the `context`
|
||||
/**
|
||||
* Holds if this object is introduced into the code base at `node` given the `context`
|
||||
* This means that `node`, in `context`, points-to this object, but the object has not flowed
|
||||
* there from anywhere else.
|
||||
* Examples:
|
||||
@@ -41,22 +42,25 @@ class ObjectInternal extends TObject {
|
||||
/** True if this "object" is a class. That is, its class inherits from `type` */
|
||||
abstract boolean isClass();
|
||||
|
||||
/** Gets the class of this object. */
|
||||
/** Gets the class of this object. */
|
||||
abstract ObjectInternal getClass();
|
||||
|
||||
/** True if this "object" can be meaningfully analysed to determine the boolean value of
|
||||
/**
|
||||
* True if this "object" can be meaningfully analysed to determine the boolean value of
|
||||
* equality tests on it.
|
||||
* For example, `None` or `int` can be, but `int()` or an unknown string cannot.
|
||||
*/
|
||||
abstract predicate notTestableForEquality();
|
||||
|
||||
/** Gets the `Builtin` for this object, if any.
|
||||
/**
|
||||
* Gets the `Builtin` for this object, if any.
|
||||
* Objects (except unknown and undefined values) should attempt to return
|
||||
* exactly one result for either this method or `getOrigin()`.
|
||||
*/
|
||||
abstract Builtin getBuiltin();
|
||||
|
||||
/** Gets a control flow node that represents the source origin of this
|
||||
/**
|
||||
* Gets a control flow node that represents the source origin of this
|
||||
* object, if it has a meaningful location in the source code.
|
||||
* This method exists primarily for providing backwards compatibility and
|
||||
* locations for source objects.
|
||||
@@ -64,7 +68,8 @@ class ObjectInternal extends TObject {
|
||||
*/
|
||||
abstract ControlFlowNode getOrigin();
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
/**
|
||||
* Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj`.
|
||||
*
|
||||
* This is the context-insensitive version.
|
||||
@@ -72,7 +77,8 @@ class ObjectInternal extends TObject {
|
||||
*/
|
||||
abstract predicate callResult(ObjectInternal obj, CfgOrigin origin);
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
/**
|
||||
* Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj` with callee context `callee`.
|
||||
*
|
||||
* This is the context-sensitive version.
|
||||
@@ -80,34 +86,36 @@ class ObjectInternal extends TObject {
|
||||
*/
|
||||
abstract predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin);
|
||||
|
||||
/** The integer value of things that have integer values and whose integer value is
|
||||
/**
|
||||
* The integer value of things that have integer values and whose integer value is
|
||||
* tracked.
|
||||
* That is, some ints, mainly small numbers, and bools.
|
||||
*/
|
||||
abstract int intValue();
|
||||
|
||||
/** The string value of things that have string values.
|
||||
/**
|
||||
* The string value of things that have string values.
|
||||
* That is, strings.
|
||||
*/
|
||||
abstract string strValue();
|
||||
|
||||
/** Holds if the function `scope` is called when this object is called and `paramOffset`
|
||||
/**
|
||||
* Holds if the function `scope` is called when this object is called and `paramOffset`
|
||||
* is the difference from the parameter position and the argument position.
|
||||
* For a normal function `paramOffset` is 0. For classes and bound-methods it is 1.
|
||||
* Used by points-to to help determine flow from arguments to parameters.
|
||||
*/
|
||||
abstract predicate calleeAndOffset(Function scope, int paramOffset);
|
||||
|
||||
final predicate isBuiltin() {
|
||||
exists(this.getBuiltin())
|
||||
}
|
||||
final predicate isBuiltin() { exists(this.getBuiltin()) }
|
||||
|
||||
/** Holds if the result of getting the attribute `name` is `value` and that `value` comes
|
||||
/**
|
||||
* Holds if the result of getting the attribute `name` is `value` and that `value` comes
|
||||
* from `origin`. Note this is *not* the same as class lookup. For example
|
||||
* for an object `x` the attribute `name` (`x.name`) may refer to a bound-method, an attribute of the
|
||||
* for an object `x` the attribute `name` (`x.name`) may refer to a bound-method, an attribute of the
|
||||
* instance, or an attribute of the class.
|
||||
*/
|
||||
pragma [nomagic]
|
||||
pragma[nomagic]
|
||||
abstract predicate attribute(string name, ObjectInternal value, CfgOrigin origin);
|
||||
|
||||
/** Holds if the attributes of this object are wholly or partly unknowable */
|
||||
@@ -116,59 +124,71 @@ class ObjectInternal extends TObject {
|
||||
/** Holds if the result of subscripting this object are wholly or partly unknowable */
|
||||
abstract predicate subscriptUnknown();
|
||||
|
||||
/** For backwards compatibility shim -- Not all objects have a "source".
|
||||
/**
|
||||
* For backwards compatibility shim -- Not all objects have a "source".
|
||||
* Objects (except unknown and undefined values) should attempt to return
|
||||
* exactly one result for this method.
|
||||
* */
|
||||
*/
|
||||
@py_object getSource() {
|
||||
result = this.getOrigin()
|
||||
or
|
||||
result = this.getBuiltin()
|
||||
}
|
||||
|
||||
/** Holds if this object is a descriptor.
|
||||
/**
|
||||
* Holds if this object is a descriptor.
|
||||
* Holds, for example, for functions and properties and not for integers.
|
||||
*/
|
||||
abstract boolean isDescriptor();
|
||||
|
||||
/** Holds if the result of attribute access on the class holding this descriptor is `value`, originating at `origin`
|
||||
/**
|
||||
* Holds if the result of attribute access on the class holding this descriptor is `value`, originating at `origin`
|
||||
* For example, although `T.__dict__['name'] = classmethod(f)`, `T.name` is a bound-method, binding `f` and `T`
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin);
|
||||
|
||||
/** Holds if the result of attribute access on an instance of a class holding this descriptor is `value`, originating at `origin`
|
||||
/**
|
||||
* Holds if the result of attribute access on an instance of a class holding this descriptor is `value`, originating at `origin`
|
||||
* For example, with `T.__dict__['name'] = classmethod(f)`, `T().name` is a bound-method, binding `f` and `T`
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin);
|
||||
abstract predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
);
|
||||
|
||||
/** Holds if attribute lookup on this object may "bind" `instance` to `descriptor`.
|
||||
/**
|
||||
* Holds if attribute lookup on this object may "bind" `instance` to `descriptor`.
|
||||
* Here "bind" means that `instance` is passed to the `descriptor.__get__()` method
|
||||
* at runtime. The term "bind" is used as this most likely results in a bound-method.
|
||||
*/
|
||||
abstract predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor);
|
||||
|
||||
/** Gets the length of the sequence that this "object" represents.
|
||||
/**
|
||||
* Gets the length of the sequence that this "object" represents.
|
||||
* Always returns a value for a sequence, will be -1 if the object has no fixed length.
|
||||
*/
|
||||
abstract int length();
|
||||
|
||||
/** Holds if the object `function` is called when this object is called and `paramOffset`
|
||||
/**
|
||||
* Holds if the object `function` is called when this object is called and `paramOffset`
|
||||
* is the difference from the parameter position and the argument position.
|
||||
* For a normal function `paramOffset` is 0. For classes and bound-methods it is 1.
|
||||
* This is used to implement the `CallableValue` public API.
|
||||
*/
|
||||
predicate functionAndOffset(CallableObjectInternal function, int offset) { none() }
|
||||
|
||||
/** Holds if this 'object' represents an entity that should be exposed to the legacy points_to API
|
||||
/**
|
||||
* Holds if this 'object' represents an entity that should be exposed to the legacy points_to API
|
||||
* This should hold for almost all objects that do not have an underlying DB object representing their source,
|
||||
* for example `super` objects and bound-method. This should not hold for objects that are inferred to exists by
|
||||
* an import statements or the like, but which aren't in the database. */
|
||||
/* This predicate can be removed when the legacy points_to API is removed. */
|
||||
* an import statements or the like, but which aren't in the database.
|
||||
*/
|
||||
/* This predicate can be removed when the legacy points_to API is removed. */
|
||||
abstract predicate useOriginAsLegacyObject();
|
||||
|
||||
/** Gets the name of this of this object if it has a meaningful name.
|
||||
/**
|
||||
* Gets the name of this of this object if it has a meaningful name.
|
||||
* Note that the name of an object is not necessarily the name by which it is called
|
||||
* For example the function named `posixpath.join` will be called `os.path.join`.
|
||||
*/
|
||||
@@ -176,50 +196,36 @@ class ObjectInternal extends TObject {
|
||||
|
||||
abstract predicate contextSensitiveCallee();
|
||||
|
||||
/** Gets the 'object' resulting from iterating over this object.
|
||||
/**
|
||||
* Gets the 'object' resulting from iterating over this object.
|
||||
* Used in the context `for i in this:`. The result is the 'object'
|
||||
* assigned to `i`.
|
||||
*/
|
||||
abstract ObjectInternal getIterNext();
|
||||
|
||||
/** Holds if this value has the attribute `name` */
|
||||
predicate hasAttribute(string name) {
|
||||
this.(ObjectInternal).attribute(name, _, _)
|
||||
}
|
||||
predicate hasAttribute(string name) { this.(ObjectInternal).attribute(name, _, _) }
|
||||
|
||||
abstract predicate isNotSubscriptedType();
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
|
||||
override Builtin getBuiltin() { this = TBuiltinOpaqueObject(result) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinOpaqueObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = this.getBuiltin().getClass().getName() + " object"
|
||||
}
|
||||
override string toString() { result = this.getBuiltin().getClass().getName() + " object" }
|
||||
|
||||
override boolean booleanValue() {
|
||||
// TO DO ... Depends on class. `result = this.getClass().instancesBooleanValue()`
|
||||
result = maybe()
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
override ObjectInternal getClass() { result = TBuiltinClassObject(this.getBuiltin().getClass()) }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
@@ -231,46 +237,47 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] 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()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate subscriptUnknown() {
|
||||
exists(this.getBuiltin().getItem(_))
|
||||
}
|
||||
override predicate subscriptUnknown() { exists(this.getBuiltin().getItem(_)) }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] 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() }
|
||||
|
||||
override string getName() {
|
||||
result = this.getBuiltin().getName()
|
||||
}
|
||||
override string getName() { result = this.getBuiltin().getName() }
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
@@ -279,39 +286,24 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
class UnknownInternal extends ObjectInternal, TUnknown {
|
||||
override string toString() { result = "Unknown value" }
|
||||
|
||||
override string toString() {
|
||||
result = "Unknown value"
|
||||
}
|
||||
override boolean booleanValue() { result = maybe() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = maybe()
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TUnknownClass()
|
||||
}
|
||||
override ObjectInternal getClass() { result = TUnknownClass() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
result = Builtin::unknown()
|
||||
}
|
||||
override Builtin getBuiltin() { result = Builtin::unknown() }
|
||||
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
@@ -321,37 +313,40 @@ class UnknownInternal extends ObjectInternal, TUnknown {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { any() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { any() }
|
||||
|
||||
override predicate subscriptUnknown() { any() }
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] 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() { result = -1 }
|
||||
|
||||
@@ -364,38 +359,24 @@ class UnknownInternal extends ObjectInternal, TUnknown {
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
class UndefinedInternal extends ObjectInternal, TUndefined {
|
||||
override string toString() { result = "Undefined variable" }
|
||||
|
||||
override string toString() {
|
||||
result = "Undefined variable"
|
||||
}
|
||||
override boolean booleanValue() { none() }
|
||||
|
||||
override boolean booleanValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override predicate notTestableForEquality() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
none()
|
||||
}
|
||||
override ObjectInternal getClass() { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
@@ -407,37 +388,40 @@ class UndefinedInternal extends ObjectInternal, TUndefined {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { none() }
|
||||
|
||||
override boolean isDescriptor() { none() }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] 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() }
|
||||
|
||||
@@ -445,39 +429,31 @@ class UndefinedInternal extends ObjectInternal, TUndefined {
|
||||
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
/** Holds if this object requires context to determine the object resulting from a call to it.
|
||||
* True for most callables. */
|
||||
/**
|
||||
* Holds if this object requires context to determine the object resulting from a call to it.
|
||||
* True for most callables.
|
||||
*/
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
module ObjectInternal {
|
||||
|
||||
ObjectInternal bool(boolean b) {
|
||||
b = true and result = TTrue()
|
||||
or
|
||||
b = false and result = TFalse()
|
||||
}
|
||||
|
||||
ObjectInternal none_() {
|
||||
result = TNone()
|
||||
}
|
||||
ObjectInternal none_() { result = TNone() }
|
||||
|
||||
ObjectInternal unknown() {
|
||||
result = TUnknown()
|
||||
}
|
||||
ObjectInternal unknown() { result = TUnknown() }
|
||||
|
||||
ClassObjectInternal unknownClass() {
|
||||
result = TUnknownClass()
|
||||
}
|
||||
ClassObjectInternal unknownClass() { result = TUnknownClass() }
|
||||
|
||||
ObjectInternal undefined() {
|
||||
result = TUndefined()
|
||||
}
|
||||
ObjectInternal undefined() { result = TUndefined() }
|
||||
|
||||
ObjectInternal builtin(string name) {
|
||||
result = TBuiltinClassObject(Builtin::builtin(name))
|
||||
@@ -490,12 +466,10 @@ module ObjectInternal {
|
||||
}
|
||||
|
||||
ObjectInternal sysModules() {
|
||||
result = TBuiltinOpaqueObject(Builtin::special("sys").getMember("modules"))
|
||||
result = TBuiltinOpaqueObject(Builtin::special("sys").getMember("modules"))
|
||||
}
|
||||
|
||||
ObjectInternal fromInt(int n) {
|
||||
result = TInt(n)
|
||||
}
|
||||
ObjectInternal fromInt(int n) { result = TInt(n) }
|
||||
|
||||
ObjectInternal fromBuiltin(Builtin b) {
|
||||
b = result.getBuiltin() and
|
||||
@@ -506,67 +480,38 @@ module ObjectInternal {
|
||||
b = Builtin::special("sys").getMember("version_info") and result = TSysVersionInfo()
|
||||
}
|
||||
|
||||
ObjectInternal classMethod() {
|
||||
result = TBuiltinClassObject(Builtin::special("ClassMethod"))
|
||||
}
|
||||
ObjectInternal classMethod() { result = TBuiltinClassObject(Builtin::special("ClassMethod")) }
|
||||
|
||||
ObjectInternal staticMethod() {
|
||||
result = TBuiltinClassObject(Builtin::special("StaticMethod"))
|
||||
}
|
||||
ObjectInternal staticMethod() { result = TBuiltinClassObject(Builtin::special("StaticMethod")) }
|
||||
|
||||
ObjectInternal boundMethod() {
|
||||
result = TBuiltinClassObject(Builtin::special("MethodType"))
|
||||
}
|
||||
ObjectInternal boundMethod() { result = TBuiltinClassObject(Builtin::special("MethodType")) }
|
||||
|
||||
ObjectInternal moduleType() {
|
||||
result = TBuiltinClassObject(Builtin::special("ModuleType"))
|
||||
}
|
||||
ObjectInternal moduleType() { result = TBuiltinClassObject(Builtin::special("ModuleType")) }
|
||||
|
||||
ObjectInternal noneType() {
|
||||
result = TBuiltinClassObject(Builtin::special("NoneType"))
|
||||
}
|
||||
ObjectInternal noneType() { result = TBuiltinClassObject(Builtin::special("NoneType")) }
|
||||
|
||||
ObjectInternal type() {
|
||||
result = TType()
|
||||
}
|
||||
ObjectInternal type() { result = TType() }
|
||||
|
||||
ObjectInternal property() {
|
||||
result = TBuiltinClassObject(Builtin::special("property"))
|
||||
}
|
||||
ObjectInternal property() { result = TBuiltinClassObject(Builtin::special("property")) }
|
||||
|
||||
ObjectInternal superType() {
|
||||
result = TBuiltinClassObject(Builtin::special("super"))
|
||||
}
|
||||
ObjectInternal superType() { result = TBuiltinClassObject(Builtin::special("super")) }
|
||||
|
||||
/** The old-style class type (Python 2 only) */
|
||||
ObjectInternal classType() {
|
||||
result = TBuiltinClassObject(Builtin::special("ClassType"))
|
||||
}
|
||||
|
||||
ObjectInternal emptyTuple() {
|
||||
result.(BuiltinTupleObjectInternal).length() = 0
|
||||
}
|
||||
ObjectInternal classType() { result = TBuiltinClassObject(Builtin::special("ClassType")) }
|
||||
|
||||
ObjectInternal emptyTuple() { result.(BuiltinTupleObjectInternal).length() = 0 }
|
||||
}
|
||||
|
||||
class DecoratedFunction extends ObjectInternal, TDecoratedFunction {
|
||||
CallNode getDecoratorCall() { this = TDecoratedFunction(result) }
|
||||
|
||||
|
||||
CallNode getDecoratorCall() {
|
||||
this = TDecoratedFunction(result)
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
private ObjectInternal decoratedObject() {
|
||||
PointsTo::pointsTo(this.getDecoratorCall().getArg(0), _, result, _)
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = this.decoratedObject().getName()
|
||||
}
|
||||
override string getName() { result = this.decoratedObject().getName() }
|
||||
|
||||
override string toString() {
|
||||
result = "Decorated " + this.decoratedObject().toString()
|
||||
@@ -576,17 +521,13 @@ class DecoratedFunction extends ObjectInternal, TDecoratedFunction {
|
||||
|
||||
override boolean booleanValue() { result = true }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override ObjectInternal getClass() { result = TUnknownClass() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
@@ -598,25 +539,15 @@ class DecoratedFunction extends ObjectInternal, TDecoratedFunction {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
result = this.getDecoratorCall()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { result = this.getDecoratorCall() }
|
||||
|
||||
override int intValue() {
|
||||
none()
|
||||
}
|
||||
override int intValue() { none() }
|
||||
|
||||
override string strValue() {
|
||||
none()
|
||||
}
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
none()
|
||||
}
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
@@ -624,11 +555,22 @@ class DecoratedFunction extends ObjectInternal, TDecoratedFunction {
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] 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() }
|
||||
|
||||
@@ -639,17 +581,13 @@ class DecoratedFunction extends ObjectInternal, TDecoratedFunction {
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
/** Helper for boolean predicates returning both `true` and `false` */
|
||||
boolean maybe() {
|
||||
result = true or result = false
|
||||
}
|
||||
boolean maybe() { result = true or result = false }
|
||||
|
||||
/** Helper for attributes */
|
||||
pragma [nomagic]
|
||||
pragma[nomagic]
|
||||
predicate receiver_type(AttrNode attr, string name, ObjectInternal value, ClassObjectInternal cls) {
|
||||
PointsToInternal::pointsTo(attr.getObject(name), _, value, _) and value.getClass() = cls
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
|
||||
import python
|
||||
|
||||
|
||||
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
@@ -12,7 +7,6 @@ private import semmle.python.pointsto.MRO
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
abstract class SequenceObjectInternal extends ObjectInternal {
|
||||
|
||||
/** Gets the `n`th item of this sequence, if one exists. */
|
||||
abstract ObjectInternal getItem(int n);
|
||||
|
||||
@@ -24,45 +18,50 @@ abstract class SequenceObjectInternal extends ObjectInternal {
|
||||
|
||||
override boolean isDescriptor() { result = false }
|
||||
|
||||
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, 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() }
|
||||
pragma[noinline]
|
||||
override predicate descriptorGetInstance(
|
||||
ObjectInternal instance, ObjectInternal value, CfgOrigin origin
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
|
||||
pragma[noinline]
|
||||
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) {
|
||||
none()
|
||||
}
|
||||
|
||||
override string getName() { none() }
|
||||
|
||||
override predicate contextSensitiveCallee() { none() }
|
||||
|
||||
override ObjectInternal getIterNext() { result = this.getItem(_) }
|
||||
|
||||
}
|
||||
|
||||
abstract class TupleObjectInternal extends SequenceObjectInternal {
|
||||
|
||||
override string toString() {
|
||||
result = "(" + this.contents(0) + ")"
|
||||
}
|
||||
override string toString() { result = "(" + this.contents(0) + ")" }
|
||||
|
||||
private string contents(int n) {
|
||||
n < 4 and n = this.length() and result = ""
|
||||
or
|
||||
n = 3 and this.length() > 3 and result = (this.length()-3).toString() + " more..."
|
||||
n = 3 and this.length() > 3 and result = (this.length() - 3).toString() + " more..."
|
||||
or
|
||||
result = this.item(n) + ", " + this.contents(n+1)
|
||||
result = this.item(n) + ", " + this.contents(n + 1)
|
||||
}
|
||||
|
||||
private string item(int n) {
|
||||
exists(ObjectInternal item | item = this.getItem(n) |
|
||||
// To avoid infinite recursion, nested tuples are replaced with the string "...".
|
||||
if item instanceof TupleObjectInternal then
|
||||
result = "(...)"
|
||||
else
|
||||
result = item.toString()
|
||||
if item instanceof TupleObjectInternal then result = "(...)" else result = item.toString()
|
||||
)
|
||||
or
|
||||
n in [0..this.length()-1] and
|
||||
not exists(this.getItem(n)) and result = "?"
|
||||
n in [0 .. this.length() - 1] and
|
||||
not exists(this.getItem(n)) and
|
||||
result = "?"
|
||||
}
|
||||
|
||||
/** Gets the class declaration for this object, if it is a declared class. */
|
||||
@@ -73,60 +72,59 @@ abstract class TupleObjectInternal extends SequenceObjectInternal {
|
||||
|
||||
override ObjectInternal getClass() { result = ObjectInternal::builtin("tuple") }
|
||||
|
||||
/** True if this "object" can be meaningfully analysed for
|
||||
/**
|
||||
* True if this "object" can be meaningfully analysed for
|
||||
* truth or false in comparisons. For example, `None` or `int` can be, but `int()`
|
||||
* or an unknown string cannot.
|
||||
*/
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
/**
|
||||
* Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj`.
|
||||
*/
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
/**
|
||||
* Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj` with callee context `callee`.
|
||||
*/
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** The integer value of things that have integer values.
|
||||
/**
|
||||
* The integer value of things that have integer values.
|
||||
* That is, ints and bools.
|
||||
*/
|
||||
override int intValue() { none() }
|
||||
|
||||
/** The integer value of things that have integer values.
|
||||
/**
|
||||
* The integer value of things that have integer values.
|
||||
* That is, strings.
|
||||
*/
|
||||
override string strValue() { none() }
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
pragma[noinline]
|
||||
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
||||
|
||||
pragma [noinline] override predicate attributesUnknown() { none() }
|
||||
pragma[noinline]
|
||||
override predicate attributesUnknown() { none() }
|
||||
|
||||
override predicate subscriptUnknown() { none() }
|
||||
|
||||
}
|
||||
|
||||
/** A tuple built-in to the interpreter, including the empty tuple. */
|
||||
class BuiltinTupleObjectInternal extends TBuiltinTuple, TupleObjectInternal {
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { this = TBuiltinTuple(result) }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinTuple(result)
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ObjectInternal getItem(int n) {
|
||||
result.getBuiltin() = this.getBuiltin().getItem(n)
|
||||
}
|
||||
override ObjectInternal getItem(int n) { result.getBuiltin() = this.getBuiltin().getItem(n) }
|
||||
|
||||
override int length() {
|
||||
exists(Builtin b |
|
||||
@@ -138,23 +136,17 @@ class BuiltinTupleObjectInternal extends TBuiltinTuple, TupleObjectInternal {
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
/** A tuple declared by a tuple expression in the Python source code */
|
||||
class PythonTupleObjectInternal extends TPythonTuple, TupleObjectInternal {
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
this = TPythonTuple(node, context)
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TPythonTuple(result, _)
|
||||
}
|
||||
override ControlFlowNode getOrigin() { this = TPythonTuple(result, _) }
|
||||
|
||||
override ObjectInternal getItem(int n) {
|
||||
exists(TupleNode t, PointsToContext context |
|
||||
@@ -173,51 +165,37 @@ class PythonTupleObjectInternal extends TPythonTuple, TupleObjectInternal {
|
||||
override predicate useOriginAsLegacyObject() { none() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
/** A tuple created by a `*` parameter */
|
||||
class VarargsTupleObjectInternal extends TVarargsTuple, TupleObjectInternal {
|
||||
class VarargsTupleObjectInternal extends TVarargsTuple, TupleObjectInternal {
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
||||
|
||||
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
|
||||
none()
|
||||
}
|
||||
override Builtin getBuiltin() { none() }
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
override ObjectInternal getItem(int n) {
|
||||
exists(CallNode call, PointsToContext context, int offset, int length |
|
||||
this = TVarargsTuple(call, context, offset, length) and
|
||||
n < length and
|
||||
InterProceduralPointsTo::positional_argument_points_to(call, offset+n, context, result, _)
|
||||
InterProceduralPointsTo::positional_argument_points_to(call, offset + n, context, result, _)
|
||||
)
|
||||
}
|
||||
|
||||
override int length() {
|
||||
this = TVarargsTuple(_, _, _, result)
|
||||
}
|
||||
override int length() { this = TVarargsTuple(_, _, _, result) }
|
||||
|
||||
override predicate useOriginAsLegacyObject() { any() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The `sys.version_info` object. We treat this specially to prevent premature pruning and
|
||||
/**
|
||||
* The `sys.version_info` object. We treat this specially to prevent premature pruning and
|
||||
* false positives when we are unsure of the actual version of Python that the code is expecting.
|
||||
*/
|
||||
class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectInternal {
|
||||
|
||||
override string toString() {
|
||||
result = "sys.version_info"
|
||||
}
|
||||
override string toString() { result = "sys.version_info" }
|
||||
|
||||
override ObjectInternal getItem(int n) {
|
||||
n = 0 and result = TInt(major_version())
|
||||
@@ -235,39 +213,45 @@ class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectIntern
|
||||
/** True if this "object" is a class. */
|
||||
override boolean isClass() { result = false }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result.getBuiltin() = this.getClassDeclaration()
|
||||
}
|
||||
override ObjectInternal getClass() { result.getBuiltin() = this.getClassDeclaration() }
|
||||
|
||||
override predicate notTestableForEquality() { none() }
|
||||
|
||||
/** Gets the `Builtin` for this object, if any.
|
||||
/**
|
||||
* Gets the `Builtin` for this object, if any.
|
||||
* Objects (except unknown and undefined values) should attempt to 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
|
||||
/**
|
||||
* Gets a control flow node that represents the source origin of this
|
||||
* objects.
|
||||
*/
|
||||
override ControlFlowNode getOrigin() { none() }
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
/**
|
||||
* Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj`.
|
||||
*/
|
||||
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
/**
|
||||
* Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj` with callee context `callee`.
|
||||
*/
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
|
||||
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
none()
|
||||
}
|
||||
|
||||
/** The integer value of things that have integer values.
|
||||
/**
|
||||
* The integer value of things that have integer values.
|
||||
* That is, ints and bools.
|
||||
*/
|
||||
override int intValue() { none() }
|
||||
|
||||
/** The integer value of things that have integer values.
|
||||
/**
|
||||
* The integer value of things that have integer values.
|
||||
* That is, strings.
|
||||
*/
|
||||
override string strValue() { none() }
|
||||
@@ -280,7 +264,8 @@ class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectIntern
|
||||
|
||||
override predicate subscriptUnknown() { none() }
|
||||
|
||||
/** Gets the length of the sequence that this "object" represents.
|
||||
/**
|
||||
* Gets the length of the sequence that this "object" represents.
|
||||
* Always returns a value for a sequence, will be -1 if object has no fixed length.
|
||||
*/
|
||||
override int length() { result = 5 }
|
||||
@@ -290,5 +275,4 @@ class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectIntern
|
||||
override predicate useOriginAsLegacyObject() { any() }
|
||||
|
||||
override predicate isNotSubscriptedType() { any() }
|
||||
|
||||
}
|
||||
|
||||
@@ -4,239 +4,193 @@ private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.pointsto.PointsToContext
|
||||
|
||||
/** Internal type backing `ObjectInternal` and `Value`
|
||||
/**
|
||||
* Internal type backing `ObjectInternal` and `Value`
|
||||
* See `ObjectInternal.qll` for an explanation of the API.
|
||||
*/
|
||||
cached newtype TObject =
|
||||
cached
|
||||
newtype TObject =
|
||||
/* Builtin class objects */
|
||||
TBuiltinClassObject(Builtin bltn) {
|
||||
bltn.isClass() and
|
||||
not bltn = Builtin::unknownType() and
|
||||
not bltn = Builtin::special("type")
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Builtin function objects (module members) */
|
||||
TBuiltinFunctionObject(Builtin bltn) { bltn.isFunction() }
|
||||
or
|
||||
TBuiltinFunctionObject(Builtin bltn) { bltn.isFunction() } or
|
||||
/* Builtin method objects (class members) */
|
||||
TBuiltinMethodObject(Builtin bltn) { bltn.isMethod() }
|
||||
or
|
||||
TBuiltinMethodObject(Builtin bltn) { bltn.isMethod() } or
|
||||
/* Builtin module objects */
|
||||
TBuiltinModuleObject(Builtin bltn) { bltn.isModule() }
|
||||
or
|
||||
TBuiltinModuleObject(Builtin bltn) { bltn.isModule() } or
|
||||
/* Other builtin objects from the interpreter */
|
||||
TBuiltinOpaqueObject(Builtin bltn) {
|
||||
not bltn.isClass() and not bltn.isFunction() and
|
||||
not bltn.isMethod() and not bltn.isModule() and
|
||||
not bltn.isClass() and
|
||||
not bltn.isFunction() and
|
||||
not bltn.isMethod() and
|
||||
not bltn.isModule() and
|
||||
not bltn.getClass() = Builtin::special("tuple") and
|
||||
not exists(bltn.intValue()) and
|
||||
not exists(bltn.floatValue()) and
|
||||
not exists(bltn.strValue()) and
|
||||
not py_special_objects(bltn, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Python function objects (including lambdas) */
|
||||
TPythonFunctionObject(ControlFlowNode callable) {
|
||||
callable.getNode() instanceof CallableExpr
|
||||
}
|
||||
or
|
||||
TPythonFunctionObject(ControlFlowNode callable) { callable.getNode() instanceof CallableExpr } or
|
||||
/* Python class objects */
|
||||
TPythonClassObject(ControlFlowNode classexpr) {
|
||||
classexpr.getNode() instanceof ClassExpr
|
||||
}
|
||||
or
|
||||
TPythonClassObject(ControlFlowNode classexpr) { classexpr.getNode() instanceof ClassExpr } or
|
||||
/* Package objects */
|
||||
TPackageObject(Folder f) {
|
||||
isPreferredModuleForName(f, _)
|
||||
}
|
||||
or
|
||||
TPackageObject(Folder f) { isPreferredModuleForName(f, _) } or
|
||||
/* Python module objects */
|
||||
TPythonModule(Module m) {
|
||||
not m.isPackage() and isPreferredModuleForName(m.getFile(), _) and
|
||||
not m.isPackage() and
|
||||
isPreferredModuleForName(m.getFile(), _) and
|
||||
not exists(SyntaxError se | se.getFile() = m.getFile())
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* `True` */
|
||||
TTrue()
|
||||
or
|
||||
TTrue() or
|
||||
/* `False` */
|
||||
TFalse()
|
||||
or
|
||||
TFalse() or
|
||||
/* `None` */
|
||||
TNone()
|
||||
or
|
||||
TNone() or
|
||||
/* Represents any value about which nothing useful is known */
|
||||
TUnknown()
|
||||
or
|
||||
TUnknown() or
|
||||
/* Represents any value known to be a class, but not known to be any specific class */
|
||||
TUnknownClass()
|
||||
or
|
||||
TUnknownClass() or
|
||||
/* Represents the absence of a value. Used by points-to for tracking undefined variables */
|
||||
TUndefined()
|
||||
or
|
||||
TUndefined() or
|
||||
/* The integer `n` */
|
||||
TInt(int n) {
|
||||
// Powers of 2 are used for flags
|
||||
is_power_2(n) or
|
||||
is_power_2(n)
|
||||
or
|
||||
// And all combinations of flags up to 2^8
|
||||
n in [0..511] or
|
||||
n in [0 .. 511]
|
||||
or
|
||||
// Any number explicitly mentioned in the source code.
|
||||
exists(IntegerLiteral num |
|
||||
n = num.getValue() or
|
||||
exists(UnaryExpr neg | neg.getOp() instanceof USub and neg.getOperand() = num)
|
||||
and n = -num.getN().toInt()
|
||||
n = num.getValue()
|
||||
or
|
||||
exists(UnaryExpr neg | neg.getOp() instanceof USub and neg.getOperand() = num) and
|
||||
n = -num.getN().toInt()
|
||||
)
|
||||
or
|
||||
n = any(Builtin b).intValue()
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* The float `f` */
|
||||
TFloat(float f) {
|
||||
f = any(FloatLiteral num).getValue()
|
||||
}
|
||||
or
|
||||
TFloat(float f) { f = any(FloatLiteral num).getValue() } or
|
||||
/* The unicode string `s` */
|
||||
TUnicode(string s) {
|
||||
// Any string explicitly mentioned in the source code.
|
||||
exists(StrConst str |
|
||||
exists(StrConst str |
|
||||
s = str.getText() and
|
||||
str.isUnicode()
|
||||
)
|
||||
or
|
||||
// Any string from the library put in the DB by the extractor.
|
||||
exists(Builtin b |
|
||||
s = b.strValue() and
|
||||
s = b.strValue() and
|
||||
b.getClass() = Builtin::special("unicode")
|
||||
)
|
||||
or
|
||||
s = "__main__"
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* The byte string `s` */
|
||||
TBytes(string s) {
|
||||
// Any string explicitly mentioned in the source code.
|
||||
exists(StrConst str |
|
||||
exists(StrConst str |
|
||||
s = str.getText() and
|
||||
not str.isUnicode()
|
||||
)
|
||||
or
|
||||
// Any string from the library put in the DB by the extractor.
|
||||
exists(Builtin b |
|
||||
s = b.strValue() and
|
||||
s = b.strValue() and
|
||||
b.getClass() = Builtin::special("bytes")
|
||||
)
|
||||
or
|
||||
s = "__main__"
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* An instance of `cls`, instantiated at `instantiation` given the `context`. */
|
||||
TSpecificInstance(ControlFlowNode instantiation, ClassObjectInternal cls, PointsToContext context) {
|
||||
PointsToInternal::pointsTo(instantiation.(CallNode).getFunction(), context, cls, _) and
|
||||
cls.isSpecial() = false
|
||||
or
|
||||
literal_instantiation(instantiation, cls, context)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* A non-specific instance `cls` which enters the scope at `def` given the callee `context`. */
|
||||
TSelfInstance(ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls) {
|
||||
self_parameter(def, context, cls)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* A bound method */
|
||||
TBoundMethod(ObjectInternal self, CallableObjectInternal function) {
|
||||
any(ObjectInternal obj).binds(self, _, function) and
|
||||
function.isDescriptor() = true
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents any value whose class is known, but nothing else */
|
||||
TUnknownInstance(BuiltinClassObjectInternal cls) {
|
||||
cls != ObjectInternal::superType() and
|
||||
cls != ObjectInternal::builtin("bool") and
|
||||
cls != ObjectInternal::noneType()
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents an instance of `super` */
|
||||
TSuperInstance(ObjectInternal self, ClassObjectInternal startclass) {
|
||||
super_instantiation(_, self, startclass, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents an instance of `classmethod` */
|
||||
TClassMethod(CallNode instantiation, CallableObjectInternal function) {
|
||||
class_method(instantiation, function, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents an instance of `staticmethod` */
|
||||
TStaticMethod(CallNode instantiation, CallableObjectInternal function) {
|
||||
static_method(instantiation, function, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents a builtin tuple */
|
||||
TBuiltinTuple(Builtin bltn) {
|
||||
bltn.getClass() = Builtin::special("tuple")
|
||||
}
|
||||
or
|
||||
TBuiltinTuple(Builtin bltn) { bltn.getClass() = Builtin::special("tuple") } or
|
||||
/* Represents a tuple in the Python source */
|
||||
TPythonTuple(TupleNode origin, PointsToContext context) {
|
||||
origin.isLoad() and
|
||||
context.appliesTo(origin)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Varargs tuple */
|
||||
TVarargsTuple(CallNode call, PointsToContext context, int offset, int length) {
|
||||
InterProceduralPointsTo::varargs_tuple(call, context, _, _, offset, length)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* `type` */
|
||||
TType()
|
||||
or
|
||||
TType() or
|
||||
/* Represents an instance of `property` */
|
||||
TProperty(CallNode call, Context ctx, CallableObjectInternal getter) {
|
||||
PointsToInternal::pointsTo(call.getFunction(), ctx, ObjectInternal::property(), _) and
|
||||
PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents the `setter` or `deleter` method of a property object. */
|
||||
TPropertySetterOrDeleter(PropertyInternal property, string method) {
|
||||
exists(AttrNode attr |
|
||||
PointsToInternal::pointsTo(attr.getObject(method), _, property, _)
|
||||
) and
|
||||
( method = "setter" or method = "deleter" )
|
||||
}
|
||||
or
|
||||
exists(AttrNode attr | PointsToInternal::pointsTo(attr.getObject(method), _, property, _)) and
|
||||
(method = "setter" or method = "deleter")
|
||||
} or
|
||||
/* Represents a dynamically created class */
|
||||
TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) {
|
||||
PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and
|
||||
not count(instantiation.getAnArg()) = 1 and
|
||||
Types::getMro(metacls).contains(TType())
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Represents `sys.version_info`. Acts like a tuple with a range of values depending on the version being analysed. */
|
||||
TSysVersionInfo()
|
||||
or
|
||||
TSysVersionInfo() or
|
||||
/* Represents a module that is inferred to perhaps exist, but is not present in the database. */
|
||||
TAbsentModule(string name) {
|
||||
missing_imported_module(_, _, name)
|
||||
}
|
||||
or
|
||||
TAbsentModule(string name) { missing_imported_module(_, _, name) } or
|
||||
/* Represents an attribute of a module that is inferred to perhaps exist, but is not present in the database. */
|
||||
TAbsentModuleAttribute(AbsentModuleObjectInternal mod, string attrname) {
|
||||
(
|
||||
PointsToInternal::pointsTo(any(AttrNode attr).getObject(attrname), _, mod, _)
|
||||
or
|
||||
PointsToInternal::pointsTo(any(ImportMemberNode imp).getModule(attrname), _, mod, _)
|
||||
)
|
||||
and
|
||||
) and
|
||||
exists(string modname |
|
||||
modname = mod.getName() and
|
||||
not common_module_name(modname + "." + attrname)
|
||||
)
|
||||
}
|
||||
or
|
||||
} or
|
||||
/* Opaque object representing the result of calling a decorator on a function that we don't understand */
|
||||
TDecoratedFunction(CallNode call) {
|
||||
call.isFunctionDecoratorCall()
|
||||
}
|
||||
or
|
||||
TDecoratedFunction(CallNode call) { call.isFunctionDecoratorCall() } or
|
||||
/* Represents a subscript operation applied to a type. For type-hint analysis */
|
||||
TSubscriptedType(ObjectInternal generic, ObjectInternal index) {
|
||||
isType(generic) and
|
||||
@@ -252,16 +206,22 @@ predicate isType(ObjectInternal t) {
|
||||
}
|
||||
|
||||
private predicate is_power_2(int n) {
|
||||
n = 1 or
|
||||
exists(int half | is_power_2(half) and n = half*2)
|
||||
n = 1
|
||||
or
|
||||
exists(int half | is_power_2(half) and n = half * 2)
|
||||
}
|
||||
|
||||
predicate static_method(CallNode instantiation, CallableObjectInternal function, PointsToContext context) {
|
||||
PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::builtin("staticmethod"), _) and
|
||||
predicate static_method(
|
||||
CallNode instantiation, CallableObjectInternal function, PointsToContext context
|
||||
) {
|
||||
PointsToInternal::pointsTo(instantiation.getFunction(), context,
|
||||
ObjectInternal::builtin("staticmethod"), _) and
|
||||
PointsToInternal::pointsTo(instantiation.getArg(0), context, function, _)
|
||||
}
|
||||
|
||||
predicate class_method(CallNode instantiation, CallableObjectInternal function, PointsToContext context) {
|
||||
predicate class_method(
|
||||
CallNode instantiation, CallableObjectInternal function, PointsToContext context
|
||||
) {
|
||||
PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::classMethod(), _) and
|
||||
PointsToInternal::pointsTo(instantiation.getArg(0), context, function, _)
|
||||
}
|
||||
@@ -285,14 +245,20 @@ predicate literal_instantiation(ControlFlowNode n, ClassObjectInternal cls, Poin
|
||||
)
|
||||
}
|
||||
|
||||
predicate super_instantiation(CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, PointsToContext context) {
|
||||
predicate super_instantiation(
|
||||
CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass,
|
||||
PointsToContext context
|
||||
) {
|
||||
super_2args(instantiation, self, startclass, context)
|
||||
or
|
||||
super_noargs(instantiation, self, startclass, context)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate super_2args(CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, PointsToContext context) {
|
||||
pragma[noinline]
|
||||
private predicate super_2args(
|
||||
CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass,
|
||||
PointsToContext context
|
||||
) {
|
||||
exists(ControlFlowNode arg0, ControlFlowNode arg1 |
|
||||
super_call2(instantiation, arg0, arg1, context) and
|
||||
PointsToInternal::pointsTo(arg0, context, startclass, _) and
|
||||
@@ -300,17 +266,23 @@ private predicate super_2args(CallNode instantiation, ObjectInternal self, Class
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate super_call2(CallNode call, ControlFlowNode arg0, ControlFlowNode arg1, PointsToContext context) {
|
||||
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::superType(), _)
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private predicate super_noargs(CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass, PointsToContext context) {
|
||||
PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::builtin("super"), _) and
|
||||
pragma[noinline]
|
||||
private predicate super_noargs(
|
||||
CallNode instantiation, ObjectInternal self, ClassObjectInternal startclass,
|
||||
PointsToContext context
|
||||
) {
|
||||
PointsToInternal::pointsTo(instantiation.getFunction(), context, ObjectInternal::builtin("super"),
|
||||
_) and
|
||||
not exists(instantiation.getArg(0)) and
|
||||
exists(Function func |
|
||||
instantiation.getScope() = func and
|
||||
@@ -328,7 +300,10 @@ predicate call2(CallNode call, ControlFlowNode func, ControlFlowNode arg0, Contr
|
||||
arg1 = call.getArg(1)
|
||||
}
|
||||
|
||||
predicate call3(CallNode call, ControlFlowNode func, ControlFlowNode arg0, ControlFlowNode arg1, ControlFlowNode arg2) {
|
||||
predicate call3(
|
||||
CallNode call, ControlFlowNode func, ControlFlowNode arg0, ControlFlowNode arg1,
|
||||
ControlFlowNode arg2
|
||||
) {
|
||||
not exists(call.getArg(3)) and
|
||||
func = call.getFunction() and
|
||||
arg0 = call.getArg(0) and
|
||||
@@ -337,9 +312,11 @@ predicate call3(CallNode call, ControlFlowNode func, ControlFlowNode arg0, Contr
|
||||
}
|
||||
|
||||
bindingset[self, function]
|
||||
predicate method_binding(AttrNode instantiation, ObjectInternal self, CallableObjectInternal function, PointsToContext context) {
|
||||
exists(ObjectInternal obj, string name |
|
||||
receiver(instantiation, context, obj, name) |
|
||||
predicate method_binding(
|
||||
AttrNode instantiation, ObjectInternal self, CallableObjectInternal function,
|
||||
PointsToContext context
|
||||
) {
|
||||
exists(ObjectInternal obj, string name | receiver(instantiation, context, obj, name) |
|
||||
exists(ObjectInternal cls |
|
||||
cls = obj.getClass() and
|
||||
cls != ObjectInternal::superType() and
|
||||
@@ -356,41 +333,45 @@ predicate method_binding(AttrNode instantiation, ObjectInternal self, CallableOb
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/** Helper for method_binding */
|
||||
pragma [noinline]
|
||||
pragma[noinline]
|
||||
predicate receiver(AttrNode instantiation, PointsToContext context, ObjectInternal obj, string name) {
|
||||
PointsToInternal::pointsTo(instantiation.getObject(name), context, obj, _)
|
||||
}
|
||||
|
||||
/** Helper self parameters: `def meth(self, ...): ...`. */
|
||||
pragma [noinline]
|
||||
private predicate self_parameter(ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls) {
|
||||
pragma[noinline]
|
||||
private predicate self_parameter(
|
||||
ParameterDefinition def, PointsToContext context, PythonClassObjectInternal cls
|
||||
) {
|
||||
def.isSelf() and
|
||||
/* Exclude the special parameter name `.0` which is used for unfolded comprehensions. */
|
||||
def.getName() != ".0" and
|
||||
exists(Function scope |
|
||||
def.getScope() = scope and
|
||||
context.isRuntime() and context.appliesToScope(scope) and
|
||||
context.isRuntime() and
|
||||
context.appliesToScope(scope) and
|
||||
scope.getScope() = cls.getScope() and
|
||||
concrete_class(cls) and
|
||||
/* We want to allow decorated functions, otherwise we lose a lot of useful information.
|
||||
/*
|
||||
* We want to allow decorated functions, otherwise we lose a lot of useful information.
|
||||
* However, we want to exclude any function whose arguments are permuted by the decorator.
|
||||
* In general we can't do that, but we can special case the most common ones.
|
||||
*/
|
||||
|
||||
neither_class_nor_static_method(scope)
|
||||
)
|
||||
}
|
||||
|
||||
private cached predicate concrete_class(PythonClassObjectInternal cls) {
|
||||
cached
|
||||
private predicate concrete_class(PythonClassObjectInternal cls) {
|
||||
cls.getClass() != abcMetaClassObject()
|
||||
or
|
||||
exists(Class c |
|
||||
c = cls.getScope() and
|
||||
not exists(c.getMetaClass())
|
||||
|
|
||||
forall(Function f |
|
||||
f.getScope() = c |
|
||||
|
|
||||
forall(Function f | f.getScope() = c |
|
||||
not exists(Raise r, Name ex |
|
||||
r.getScope() = f and
|
||||
(r.getException() = ex or r.getException().(Call).getFunc() = ex) and
|
||||
@@ -402,8 +383,7 @@ private cached predicate concrete_class(PythonClassObjectInternal cls) {
|
||||
|
||||
private PythonClassObjectInternal abcMetaClassObject() {
|
||||
/* Avoid using points-to and thus negative recursion */
|
||||
exists(Class abcmeta |
|
||||
result.getScope() = abcmeta |
|
||||
exists(Class abcmeta | result.getScope() = abcmeta |
|
||||
abcmeta.getName() = "ABCMeta" and
|
||||
abcmeta.getScope().getName() = "abc"
|
||||
)
|
||||
@@ -412,19 +392,19 @@ private PythonClassObjectInternal abcMetaClassObject() {
|
||||
private predicate neither_class_nor_static_method(Function f) {
|
||||
not exists(f.getADecorator())
|
||||
or
|
||||
exists(ControlFlowNode deco |
|
||||
deco = f.getADecorator().getAFlowNode() |
|
||||
exists(ObjectInternal o |
|
||||
PointsToInternal::pointsTo(deco, _, o, _) |
|
||||
exists(ControlFlowNode deco | deco = f.getADecorator().getAFlowNode() |
|
||||
exists(ObjectInternal o | PointsToInternal::pointsTo(deco, _, o, _) |
|
||||
o != ObjectInternal::staticMethod() and
|
||||
o != ObjectInternal::classMethod()
|
||||
)
|
||||
or not deco instanceof NameNode
|
||||
or
|
||||
not deco instanceof NameNode
|
||||
)
|
||||
}
|
||||
|
||||
predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) {
|
||||
ctx.isImport() and imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and
|
||||
ctx.isImport() and
|
||||
imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and
|
||||
(
|
||||
not exists(Module m | m.getName() = name) and
|
||||
not exists(Builtin b | b.isModule() and b.getName() = name)
|
||||
@@ -441,41 +421,41 @@ predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name)
|
||||
)
|
||||
}
|
||||
|
||||
/* Helper for missing modules to determine if name `x.y` is a module `x.y` or
|
||||
/*
|
||||
* Helper for missing modules to determine if name `x.y` is a module `x.y` or
|
||||
* an attribute `y` of module `x`. This list should be added to as required.
|
||||
*/
|
||||
|
||||
predicate common_module_name(string name) {
|
||||
name = "zope.interface"
|
||||
or
|
||||
name = "six.moves"
|
||||
}
|
||||
|
||||
/** A declaration of a class, either a built-in class or a source definition
|
||||
/**
|
||||
* A declaration of a class, either a built-in class or a source definition
|
||||
* This acts as a helper for ClassObjectInternal allowing some lookup without
|
||||
* recursion.
|
||||
*/
|
||||
library class ClassDecl extends @py_object {
|
||||
|
||||
ClassDecl() {
|
||||
this.(Builtin).isClass() and not this = Builtin::unknownType()
|
||||
or
|
||||
this.(ControlFlowNode).getNode() instanceof ClassExpr
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = "ClassDecl"
|
||||
}
|
||||
string toString() { result = "ClassDecl" }
|
||||
|
||||
/** Gets the class scope for Python class declarations */
|
||||
Class getClass() {
|
||||
result = this.(ControlFlowNode).getNode().(ClassExpr).getInnerScope()
|
||||
}
|
||||
Class getClass() { result = this.(ControlFlowNode).getNode().(ClassExpr).getInnerScope() }
|
||||
|
||||
/** Holds if this class declares the attribute `name` */
|
||||
predicate declaresAttribute(string name) {
|
||||
exists(this.(Builtin).getMember(name))
|
||||
or
|
||||
exists(SsaVariable var | name = var.getId() and var.getAUse() = this.getClass().getANormalExit())
|
||||
exists(SsaVariable var |
|
||||
name = var.getId() and var.getAUse() = this.getClass().getANormalExit()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the name of this class */
|
||||
@@ -485,11 +465,11 @@ library class ClassDecl extends @py_object {
|
||||
result = this.getClass().getName()
|
||||
}
|
||||
|
||||
/** Whether this is a class whose instances must be treated specially, rather than as generic instances.
|
||||
/**
|
||||
* Whether this is a class whose instances must be treated specially, rather than as generic instances.
|
||||
*/
|
||||
predicate isSpecial() {
|
||||
exists(string name |
|
||||
this = Builtin::special(name) |
|
||||
exists(string name | this = Builtin::special(name) |
|
||||
name = "type" or
|
||||
name = "super" or
|
||||
name = "bool" or
|
||||
@@ -505,16 +485,15 @@ library class ClassDecl extends @py_object {
|
||||
|
||||
/** Holds if for class `C`, `C()` returns an instance of `C` */
|
||||
predicate callReturnsInstance() {
|
||||
exists(Class pycls |
|
||||
pycls = this.getClass() |
|
||||
exists(Class pycls | pycls = this.getClass() |
|
||||
/* Django does this, so we need to account for it */
|
||||
not exists(Function init, LocalVariable self |
|
||||
/* `self.__class__ = ...` in the `__init__` method */
|
||||
pycls.getInitMethod() = init and
|
||||
self.isSelf() and self.getScope() = init and
|
||||
self.isSelf() and
|
||||
self.getScope() = init and
|
||||
exists(AttrNode a | a.isStore() and a.getObject("__class__") = self.getAUse())
|
||||
)
|
||||
and
|
||||
) and
|
||||
not exists(Function new | new.getName() = "__new__" and new.getScope() = pycls)
|
||||
)
|
||||
or
|
||||
@@ -527,11 +506,9 @@ library class ClassDecl extends @py_object {
|
||||
m.getName() = "_abcoll"
|
||||
or
|
||||
m.getName() = "_collections_abc"
|
||||
|
|
||||
|
|
||||
this.getClass().getScope() = m and
|
||||
this.getName() = name
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user