mirror of
https://github.com/github/codeql.git
synced 2026-01-11 05:30:24 +01:00
256 lines
7.9 KiB
Plaintext
256 lines
7.9 KiB
Plaintext
import python
|
|
private import semmle.python.objects.TObject
|
|
private import semmle.python.objects.ObjectInternal
|
|
private import semmle.python.pointsto.PointsTo
|
|
private import semmle.python.pointsto.PointsToContext
|
|
private import semmle.python.pointsto.MRO
|
|
private import semmle.python.types.Builtins
|
|
|
|
abstract class SequenceObjectInternal extends ObjectInternal {
|
|
/** Gets the `n`th item of this sequence, if one exists. */
|
|
abstract ObjectInternal getItem(int n);
|
|
|
|
override boolean booleanValue() {
|
|
this.length() = 0 and result = false
|
|
or
|
|
this.length() != 0 and result = true
|
|
}
|
|
|
|
override boolean isDescriptor() { result = false }
|
|
|
|
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 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) + ")" }
|
|
|
|
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..."
|
|
or
|
|
result = this.item(n) + ", " + this.contents(n + 1)
|
|
}
|
|
|
|
private string item(int n) {
|
|
result = bounded_toString(this.getItem(n))
|
|
or
|
|
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. */
|
|
override ClassDecl getClassDeclaration() { none() }
|
|
|
|
/** True if this "object" is a class. */
|
|
override boolean isClass() { result = false }
|
|
|
|
override ObjectInternal getClass() { result = ObjectInternal::builtin("tuple") }
|
|
|
|
/**
|
|
* True if this "object" can be meaningfully analyzed 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
|
|
* the origin of `obj`.
|
|
*/
|
|
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
|
|
|
|
/**
|
|
* 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 int intValue() { none() }
|
|
|
|
override string strValue() { none() }
|
|
|
|
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
|
|
|
pragma[noinline]
|
|
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { 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 Builtin getBuiltin() { this = TBuiltinTuple(result) }
|
|
|
|
override ControlFlowNode getOrigin() { none() }
|
|
|
|
override ObjectInternal getItem(int n) { result.getBuiltin() = this.getBuiltin().getItem(n) }
|
|
|
|
override int length() {
|
|
exists(Builtin b |
|
|
b = this.getBuiltin() and
|
|
result = count(int n | exists(b.getItem(n)))
|
|
)
|
|
}
|
|
|
|
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 ControlFlowNode getOrigin() { this = TPythonTuple(result, _) }
|
|
|
|
override ObjectInternal getItem(int n) {
|
|
exists(TupleNode t, PointsToContext context |
|
|
this = TPythonTuple(t, context) and
|
|
PointsToInternal::pointsTo(t.getElement(n), context, result, _)
|
|
)
|
|
}
|
|
|
|
override int length() {
|
|
exists(TupleNode t |
|
|
this = TPythonTuple(t, _) and
|
|
result = count(int n | exists(t.getElement(n)))
|
|
)
|
|
}
|
|
|
|
override predicate useOriginAsLegacyObject() { none() }
|
|
|
|
override predicate isNotSubscriptedType() { any() }
|
|
}
|
|
|
|
/** A tuple created by a `*` parameter */
|
|
class VarargsTupleObjectInternal extends TVarargsTuple, TupleObjectInternal {
|
|
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
|
|
|
override Builtin getBuiltin() { 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, _)
|
|
)
|
|
}
|
|
|
|
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
|
|
* 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 ObjectInternal getItem(int n) {
|
|
n = 0 and result = TInt(major_version())
|
|
or
|
|
n = 1 and result = TInt(minor_version())
|
|
}
|
|
|
|
override predicate introducedAt(ControlFlowNode node, PointsToContext context) { none() }
|
|
|
|
/** Gets the class declaration for this object, if it is a declared class. */
|
|
override ClassDecl getClassDeclaration() {
|
|
result = Builtin::special("sys").getMember("version_info").getClass()
|
|
}
|
|
|
|
/** True if this "object" is a class. */
|
|
override boolean isClass() { result = false }
|
|
|
|
override ObjectInternal getClass() { result.getBuiltin() = this.getClassDeclaration() }
|
|
|
|
override predicate notTestableForEquality() { none() }
|
|
|
|
/**
|
|
* 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
|
|
* objects.
|
|
*/
|
|
override ControlFlowNode getOrigin() { none() }
|
|
|
|
/**
|
|
* 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
|
|
* the origin of `obj` with callee context `callee`.
|
|
*/
|
|
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
|
|
none()
|
|
}
|
|
|
|
override int intValue() { none() }
|
|
|
|
override string strValue() { none() }
|
|
|
|
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
|
|
|
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
|
|
|
|
override predicate attributesUnknown() { none() }
|
|
|
|
override predicate subscriptUnknown() { none() }
|
|
|
|
override int length() { result = 5 }
|
|
|
|
override predicate functionAndOffset(CallableObjectInternal function, int offset) { none() }
|
|
|
|
override predicate useOriginAsLegacyObject() { any() }
|
|
|
|
override predicate isNotSubscriptedType() { any() }
|
|
}
|