Python: Autoformat objects.

This commit is contained in:
Taus Brock-Nannestad
2020-03-20 16:36:07 +01:00
parent 165dcd37a1
commit d8b942f922
10 changed files with 1250 additions and 1870 deletions

View File

@@ -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() }
}
}

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -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() }
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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() }
}

View File

@@ -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
)
}
}