mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Python: Add ADTs for ints and strings. Add some global data-flow.
This commit is contained in:
111
python/ql/src/semmle/python/objects/Classes.qll
Normal file
111
python/ql/src/semmle/python/objects/Classes.qll
Normal file
@@ -0,0 +1,111 @@
|
||||
import python
|
||||
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo2
|
||||
private import semmle.python.pointsto.PointsToContext2
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
|
||||
abstract class ClassObjectInternal extends ObjectInternal {
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override predicate isClass() { any() }
|
||||
|
||||
override predicate notClass() { none() }
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// TO DO .. Result should (in most cases) be an instance
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {
|
||||
|
||||
Class getScope() {
|
||||
exists(ClassDef def |
|
||||
this = TPythonClassObject(def.getAFlowNode()) and
|
||||
result = def.getDefinedClass()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = this.getScope().toString()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
exists(DefinitionNode def |
|
||||
this = TPythonClassObject(def) and
|
||||
node = def.getValue() and
|
||||
context.appliesTo(node)
|
||||
)
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
this = TPythonClassObject(result)
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("FunctionType"))
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TPythonClassObject(result)
|
||||
}
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
exists(PythonFunctionObjectInternal init |
|
||||
// TO DO... Lookup init...
|
||||
none() |
|
||||
init.getScope() = scope and paramOffset = 1
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObject {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinClassObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "builtin class " + this.getBuiltin().getName()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
this = TBuiltinClassObject(result)
|
||||
}
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
256
python/ql/src/semmle/python/objects/Constants.qll
Normal file
256
python/ql/src/semmle/python/objects/Constants.qll
Normal file
@@ -0,0 +1,256 @@
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo2
|
||||
private import semmle.python.pointsto.PointsToContext2
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
|
||||
abstract class BooleanObjectInternal extends ObjectInternal {
|
||||
|
||||
BooleanObjectInternal() {
|
||||
this = TTrue() or this = TFalse()
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("bool"))
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// Booleans aren't callable
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TrueObjectInternal extends BooleanObjectInternal, TTrue {
|
||||
|
||||
override string toString() {
|
||||
result = "True"
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
node.(NameNode).getId() = "True" and context.appliesTo(node)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FalseObjectInternal extends BooleanObjectInternal, TFalse {
|
||||
|
||||
override string toString() {
|
||||
result = "False"
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = false
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
node.(NameNode).getId() = "False" and context.appliesTo(node)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class NoneObjectInternal extends ObjectInternal, TNone {
|
||||
|
||||
override string toString() {
|
||||
result = "None"
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = false
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("NoneType"))
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
node.(NameNode).getId() = "None" and context.appliesTo(node)
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// None isn't callable
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class IntObjectInternal extends ObjectInternal, TInt {
|
||||
|
||||
override string toString() {
|
||||
result = this.intValue().toString()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
context.appliesTo(node) and
|
||||
node.getNode().(IntegerLiteral).getValue() = this.intValue()
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("int"))
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// ints aren't callable
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override int intValue() {
|
||||
this = TInt(result)
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.intValue() = 0 and result = false
|
||||
or
|
||||
this.intValue() != 0 and result = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class StringObjectInternal extends ObjectInternal, TString {
|
||||
|
||||
override string toString() {
|
||||
result = "'" + this.strValue().toString() + "'"
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
context.appliesTo(node) and
|
||||
node.getNode().(StrConst).getText() = this.strValue()
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("str"))
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// strings aren't callable
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override string strValue() {
|
||||
this = TString(result)
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
this.strValue() = "" and result = false
|
||||
or
|
||||
this.strValue() != "" and result = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
219
python/ql/src/semmle/python/objects/Modules.qll
Normal file
219
python/ql/src/semmle/python/objects/Modules.qll
Normal file
@@ -0,0 +1,219 @@
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.pointsto.PointsTo2
|
||||
private import semmle.python.pointsto.PointsToContext2
|
||||
private import semmle.python.types.Builtins
|
||||
|
||||
abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
|
||||
abstract string getName();
|
||||
|
||||
abstract Module getSourceModule();
|
||||
|
||||
abstract predicate isBuiltin();
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// Modules aren't callable
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
result = this.getSourceModule().getEntryNode()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class BuiltinModuleObjectInternal extends ModuleObjectInternal, TBuiltinModuleObject {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinModuleObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "builtin module " + this.getBuiltin().getName()
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = this.getBuiltin().getName()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Module getSourceModule() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isBuiltin() {
|
||||
any()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
Folder getFolder() {
|
||||
this = TPackageObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "package " + this.getName()
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = moduleNameFromFile(this.getFolder())
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Module getSourceModule() {
|
||||
result.getFile() = this.getFolder().getFile("__init__.py")
|
||||
}
|
||||
|
||||
PythonModuleObjectInternal getInitModule() {
|
||||
result = TPythonModule(this.getSourceModule())
|
||||
}
|
||||
|
||||
predicate hasNoInitModule() {
|
||||
exists(Folder f |
|
||||
f = this.getFolder() and
|
||||
not exists(f.getFile("__init__.py"))
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
ModuleObjectInternal submodule(string name) {
|
||||
result.getName() = this.getName() + "." + name
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
|
||||
this.getOrigin().getLocation().hasLocationInfo(fp, bl, bc, el, ec)
|
||||
or
|
||||
this.hasNoInitModule() and fp = this.getFolder().getAbsolutePath() and
|
||||
bl = 0 and bc = 0 and el = 0 and ec = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "package " + this.getName()
|
||||
}
|
||||
|
||||
override string getName() {
|
||||
result = this.getSourceModule().getName()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Module getSourceModule() {
|
||||
this = TPythonModule(result)
|
||||
}
|
||||
|
||||
PythonModuleObjectInternal getInitModule() {
|
||||
result = TPythonModule(this.getSourceModule())
|
||||
}
|
||||
|
||||
override predicate isBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
518
python/ql/src/semmle/python/objects/ObjectInternal.qll
Normal file
518
python/ql/src/semmle/python/objects/ObjectInternal.qll
Normal file
@@ -0,0 +1,518 @@
|
||||
import python
|
||||
|
||||
private import semmle.python.objects.TObject
|
||||
private import semmle.python.pointsto.PointsTo2
|
||||
private import semmle.python.pointsto.PointsToContext2
|
||||
private import semmle.python.types.Builtins
|
||||
import semmle.python.objects.Modules
|
||||
import semmle.python.objects.Classes
|
||||
import semmle.python.objects.Constants
|
||||
|
||||
abstract class ObjectInternal extends TObject {
|
||||
|
||||
abstract string toString();
|
||||
|
||||
/** The boolean value of this object, if it has one */
|
||||
abstract boolean booleanValue();
|
||||
|
||||
/** Holds if this object may be true or false when evaluated as a bool */
|
||||
abstract predicate maybe();
|
||||
|
||||
abstract predicate introduced(ControlFlowNode node, PointsToContext2 context);
|
||||
|
||||
/** Gets the class declaration for this object, if it is a declared class. */
|
||||
abstract ClassDecl getClassDeclaration();
|
||||
|
||||
abstract predicate isClass();
|
||||
|
||||
abstract predicate notClass();
|
||||
|
||||
abstract ObjectInternal getClass();
|
||||
|
||||
/** Holds if whatever this "object" represents can be meaningfully analysed for
|
||||
* truth or false in comparisons. For example, `None` or `int` can be, but `int()`
|
||||
* or an unknown string cannot.
|
||||
*/
|
||||
abstract predicate isComparable();
|
||||
|
||||
/** The negation of `isComparable()` */
|
||||
abstract predicate notComparable();
|
||||
|
||||
/** 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()`.
|
||||
*/
|
||||
abstract Builtin getBuiltin();
|
||||
|
||||
/** Gets a control flow node that represents the source origin of this
|
||||
* objects.
|
||||
* All objects (except unknown and undefined values) should return
|
||||
* exactly one result for either this method or `getBuiltin()`.
|
||||
*/
|
||||
abstract ControlFlowNode getOrigin();
|
||||
|
||||
/** Holds if `obj` is the result of calling `this` and `origin` is
|
||||
* the origin of `obj`.
|
||||
*/
|
||||
abstract predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin);
|
||||
|
||||
predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
|
||||
this.getOrigin().getLocation().hasLocationInfo(fp, bl, bc, el, ec)
|
||||
}
|
||||
|
||||
/** The integer value of things that have integer values.
|
||||
* That is, ints and bools.
|
||||
*/
|
||||
int intValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
/** The integer value of things that have integer values.
|
||||
* That is, strings.
|
||||
*/
|
||||
string strValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate calleeAndOffset(Function scope, int paramOffset) { none() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PythonFunctionObjectInternal extends ObjectInternal, TPythonFunctionObject {
|
||||
|
||||
Function getScope() {
|
||||
exists(CallableExpr expr |
|
||||
this = TPythonFunctionObject(expr.getAFlowNode()) and
|
||||
result = expr.getInnerScope()
|
||||
)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = this.getScope().toString()
|
||||
}
|
||||
|
||||
/** The boolean value of this object, if it has one */
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
/** Holds if this object may be true or false when evaluated as a bool */
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
this = TPythonFunctionObject(node) and context.appliesTo(node)
|
||||
}
|
||||
|
||||
/** INTERNAL */
|
||||
override ClassDecl getClassDeclaration() { none() }
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(Builtin::special("FunctionType"))
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
this = TPythonFunctionObject(result)
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
exists(Function func, ControlFlowNode rval |
|
||||
func = this.getScope() and
|
||||
callee.appliesToScope(func) and
|
||||
rval = func.getAReturnValueFlowNode() and
|
||||
PointsTo2::points_to(rval, callee, obj, origin)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate calleeAndOffset(Function scope, int paramOffset) {
|
||||
scope = this.getScope() and paramOffset = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// BOUND METHODS
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
class BuiltinFunctionObjectInternal extends ObjectInternal, TBuiltinFunctionObject {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinFunctionObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "builtin function " + this.getBuiltin().getName()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// TO DO .. Result should be be a unknown value of a known class if the return type is known or just an unknown.
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BuiltinMethodObjectInternal extends ObjectInternal, TBuiltinMethodObject {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinMethodObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
result = "builtin method " + this.getBuiltin().getName()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
result = true
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// TO DO .. Result should be be a unknown value of a known class if the return type is known or just an unknown.
|
||||
none()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
this = TBuiltinOpaqueObject(result)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
// TO DO ... Depends on class. `this.getClass().instancesAlways(result)`
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate maybe() {
|
||||
// TO DO ... Depends on class. `this.getClass().instancesMaybe()`
|
||||
any()
|
||||
}
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TBuiltinClassObject(this.getBuiltin().getClass())
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() and
|
||||
callee_for_object(callee, this)
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private predicate callee_for_object(PointsToContext2 callee, ObjectInternal obj) {
|
||||
exists(CallNode call, PointsToContext2 caller |
|
||||
callee.fromCall(call, caller) and
|
||||
PointsTo2::points_to(call.getFunction(), caller, obj, _)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class UnknownClassInternal extends ObjectInternal, TUnknownClass {
|
||||
|
||||
override string toString() {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate maybe() { any() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
result = Builtin::unknownType()
|
||||
}
|
||||
|
||||
override predicate isClass() { any() }
|
||||
|
||||
override predicate notClass() { none() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TUnknownClass()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() and
|
||||
callee_for_object(callee, this)
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UnknownInternal extends ObjectInternal, TUnknown {
|
||||
|
||||
override string toString() {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate maybe() { any() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
result = TUnknownClass()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() and
|
||||
callee_for_object(callee, this)
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UndefinedInternal extends ObjectInternal, TUndefined {
|
||||
|
||||
override string toString() {
|
||||
none()
|
||||
}
|
||||
|
||||
override boolean booleanValue() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate maybe() { none() }
|
||||
|
||||
override ClassDecl getClassDeclaration() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isClass() { none() }
|
||||
|
||||
override predicate notClass() { any() }
|
||||
|
||||
override ObjectInternal getClass() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate introduced(ControlFlowNode node, PointsToContext2 context) {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate isComparable() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate notComparable() {
|
||||
any()
|
||||
}
|
||||
|
||||
override Builtin getBuiltin() {
|
||||
none()
|
||||
}
|
||||
|
||||
override predicate callResult(PointsToContext2 callee, ObjectInternal obj, CfgOrigin origin) {
|
||||
// Accessing an undefined value raises a NameError, but if during import it probably
|
||||
// means that we missed an import.
|
||||
obj = ObjectInternal::unknown() and origin = CfgOrigin::unknown() and
|
||||
callee.getOuter().isImport()
|
||||
}
|
||||
|
||||
override ControlFlowNode getOrigin() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module ObjectInternal {
|
||||
|
||||
ObjectInternal bool(boolean b) {
|
||||
b = true and result = TTrue()
|
||||
or
|
||||
b = false and result = TFalse()
|
||||
}
|
||||
|
||||
ObjectInternal none_() {
|
||||
result = TNone()
|
||||
}
|
||||
|
||||
|
||||
ObjectInternal unknown() {
|
||||
result = TUnknown()
|
||||
}
|
||||
|
||||
ObjectInternal unknownClass() {
|
||||
result = TUnknownClass()
|
||||
}
|
||||
|
||||
ObjectInternal undefined() {
|
||||
result = TUndefined()
|
||||
}
|
||||
|
||||
ObjectInternal builtin(string name) {
|
||||
result = TBuiltinClassObject(Builtin::builtin(name))
|
||||
or
|
||||
result = TBuiltinFunctionObject(Builtin::builtin(name))
|
||||
or
|
||||
result = TBuiltinOpaqueObject(Builtin::builtin(name))
|
||||
}
|
||||
|
||||
ObjectInternal sysModules() {
|
||||
result = TBuiltinOpaqueObject(Builtin::special("sys").getMember("modules"))
|
||||
}
|
||||
|
||||
ObjectInternal fromInt(int n) {
|
||||
result = TInt(n)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,8 +41,39 @@ newtype TObject =
|
||||
TUnknownClass()
|
||||
or
|
||||
TUndefined()
|
||||
or
|
||||
TInt(int n) {
|
||||
// Powers of 2 are used for flags
|
||||
is_power_2(n) or
|
||||
// And all combinations of flags up to 2^8
|
||||
n in [0..511] or
|
||||
// Any number explicitly mentioned in the source code.
|
||||
exists(Num num |
|
||||
n = num.getN().toInt() or
|
||||
exists(UnaryExpr neg | neg.getOp() instanceof USub and neg.getOperand() = num)
|
||||
and n = -num.getN().toInt()
|
||||
)
|
||||
}
|
||||
or
|
||||
TString(string s) {
|
||||
// Any string explicitly mentioned in the source code.
|
||||
exists(StrConst str |
|
||||
s = str.getText()
|
||||
)
|
||||
or
|
||||
// Any string from the library put in the DB by the extractor.
|
||||
exists(string quoted_string, Builtin bltn |
|
||||
quoted_string = bltn.getName() and
|
||||
s = quoted_string.regexpCapture("[bu]'([\\s\\S]*)'", 1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private predicate is_power_2(int n) {
|
||||
n = 1 or
|
||||
exists(int half | is_power_2(half) and n = half*2)
|
||||
}
|
||||
|
||||
library class ClassDecl extends @py_object {
|
||||
|
||||
ClassDecl() {
|
||||
|
||||
@@ -101,9 +101,9 @@ module PointsTo2 {
|
||||
or
|
||||
origin = f and compare_expr_points_to(f, context, value)
|
||||
or
|
||||
origin = f and not_points_to(f, context, value)
|
||||
origin = f and unary_points_to(f, context, value)
|
||||
or
|
||||
origin = f and value.instantiated(f, context)
|
||||
origin = f and value.introduced(f, context)
|
||||
or
|
||||
InterModulePointsTo::import_points_to(f, context, value, origin)
|
||||
or
|
||||
@@ -255,7 +255,7 @@ module PointsTo2 {
|
||||
|
||||
pragma [nomagic]
|
||||
private predicate ssa_node_definition_points_to_unpruned(EssaNodeDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
parameter_points_to(def, context, value, origin)
|
||||
InterProceduralPointsTo::parameter_points_to(def, context, value, origin)
|
||||
or
|
||||
assignment_points_to(def, context, value, origin)
|
||||
//// TO DO...
|
||||
@@ -320,32 +320,6 @@ module PointsTo2 {
|
||||
}
|
||||
|
||||
|
||||
/** Points-to for parameter. `def foo(param): ...`. */
|
||||
pragma [noinline]
|
||||
private predicate parameter_points_to(ParameterDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
positional_parameter_points_to(def, context, value, origin)
|
||||
//// TO DO...
|
||||
// or
|
||||
// named_parameter_points_to(def, context, value, origin)
|
||||
// or
|
||||
// default_parameter_points_to(def, context, value, origin)
|
||||
// or
|
||||
// special_parameter_points_to(def, context, value, origin)
|
||||
}
|
||||
|
||||
/** Helper for `parameter_points_to` */
|
||||
pragma [noinline]
|
||||
private predicate positional_parameter_points_to(ParameterDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
/// To do...
|
||||
//exists(PointsToContext2 caller, ControlFlowNode arg |
|
||||
// points_to(arg, caller, value, origin) and
|
||||
// Flow::callsite_argument_transfer(arg, caller, def, context)
|
||||
//)
|
||||
//or
|
||||
not def.isSelf() and not def.getParameter().isVarargs() and not def.getParameter().isKwargs() and
|
||||
context.isRuntime() and value = ObjectInternal::unknown() and origin = def.getDefiningNode()
|
||||
}
|
||||
|
||||
/** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */
|
||||
pragma [nomagic]
|
||||
private predicate ssa_phi_points_to(PhiFunction phi, PointsToContext2 context, ObjectInternal value, CfgOrigin origin) {
|
||||
@@ -365,13 +339,12 @@ module PointsTo2 {
|
||||
pragma [noinline]
|
||||
private predicate scope_entry_points_to(ScopeEntryDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
/* Transfer from another scope */
|
||||
/// To do...
|
||||
//exists(EssaVariable var, PointsToContext2 outer, CfgOrigin orig |
|
||||
// Flow::scope_entry_value_transfer(var, outer, def, context) and
|
||||
// ssa_variable_points_to(var, outer, value, orig) and
|
||||
// origin = orig.asCfgNodeOrHere(def.getDefiningNode())
|
||||
//)
|
||||
//or
|
||||
exists(EssaVariable var, PointsToContext2 outer, CfgOrigin orig |
|
||||
InterProceduralPointsTo::scope_entry_value_transfer(var, outer, def, context) and
|
||||
ssa_variable_points_to(var, outer, value, orig) and
|
||||
origin = orig.asCfgNodeOrHere(def.getDefiningNode())
|
||||
)
|
||||
or
|
||||
/* Undefined variable */
|
||||
exists(Scope scope |
|
||||
not def.getVariable().getName() = "__name__" and
|
||||
@@ -411,48 +384,68 @@ module PointsTo2 {
|
||||
private predicate compare_expr_points_to(CompareNode cmp, PointsToContext2 context, ObjectInternal value) {
|
||||
exists(ControlFlowNode a, ControlFlowNode b, ObjectInternal o1, ObjectInternal o2 |
|
||||
exists(boolean is |
|
||||
equality_test(cmp, a, is, b) and
|
||||
points_to(a, context, o1, _) and
|
||||
points_to(b, context, o2, _) |
|
||||
(o1.isComparable() and o2.isComparable()) and
|
||||
(
|
||||
o1 = o2 and value = ObjectInternal::bool(is)
|
||||
or
|
||||
o1 != o2 and value = ObjectInternal::bool(is.booleanNot())
|
||||
)
|
||||
or
|
||||
(o1.notComparable() or o2.notComparable()) and
|
||||
value = ObjectInternal::bool(_)
|
||||
)
|
||||
// TO DO -- Comparison of int and string constants. Version tests and the like.
|
||||
//or
|
||||
//const_compare(cmp, context, comp, strict)
|
||||
// exists(int comp, boolean strict |
|
||||
// const_compare(cmp, context, comp, strict)
|
||||
// |
|
||||
// comp = -1 and value = theTrueObject()
|
||||
// or
|
||||
// comp = 0 and strict = false and value = ObjectInternal::bool(true)
|
||||
// or
|
||||
// comp = 0 and strict = true and value = ObjectInternal::bool(false)
|
||||
// or
|
||||
// comp = 1 and value = ObjectInternal::bool(false)
|
||||
// )
|
||||
equality_test(cmp, a, is, b) and
|
||||
points_to(a, context, o1, _) and
|
||||
points_to(b, context, o2, _) |
|
||||
(o1.isComparable() and o2.isComparable()) and
|
||||
(
|
||||
o1 = o2 and value = ObjectInternal::bool(is)
|
||||
or
|
||||
o1 != o2 and value = ObjectInternal::bool(is.booleanNot())
|
||||
)
|
||||
or
|
||||
(o1.notComparable() or o2.notComparable()) and
|
||||
value = ObjectInternal::bool(_)
|
||||
)
|
||||
or
|
||||
exists(boolean strict |
|
||||
inequality(cmp, a, b, strict) and
|
||||
points_to(a, context, o1, _) and
|
||||
points_to(b, context, o2, _) |
|
||||
o1.intValue() < o2.intValue() and value = ObjectInternal::bool(true)
|
||||
or
|
||||
o1.intValue() > o2.intValue() and value = ObjectInternal::bool(false)
|
||||
or
|
||||
o1.intValue() = o2.intValue() and value = ObjectInternal::bool(strict.booleanNot())
|
||||
or
|
||||
o1.strValue() < o2.strValue() and value = ObjectInternal::bool(true)
|
||||
or
|
||||
o1.strValue() > o2.strValue() and value = ObjectInternal::bool(false)
|
||||
or
|
||||
o1.strValue() = o2.strValue() and value = ObjectInternal::bool(strict.booleanNot())
|
||||
)
|
||||
// or
|
||||
// value = version_tuple_compare(cmp, context)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate not_points_to(UnaryExprNode f, PointsToContext2 context, ObjectInternal value) {
|
||||
f.getNode().getOp() instanceof Not and
|
||||
exists(ObjectInternal operand |
|
||||
/** Helper for comparisons. */
|
||||
predicate inequality(CompareNode cmp, ControlFlowNode lesser, ControlFlowNode greater, boolean strict) {
|
||||
exists(Cmpop op |
|
||||
cmp.operands(lesser, op, greater) and op.getSymbol() = "<" and strict = true
|
||||
or
|
||||
cmp.operands(lesser, op, greater) and op.getSymbol() = "<=" and strict = false
|
||||
or
|
||||
cmp.operands(greater, op, lesser) and op.getSymbol() = ">" and strict = true
|
||||
or
|
||||
cmp.operands(greater, op, lesser) and op.getSymbol() = ">=" and strict = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate unary_points_to(UnaryExprNode f, PointsToContext2 context, ObjectInternal value) {
|
||||
exists(Unaryop op, ObjectInternal operand |
|
||||
op = f.getNode().getOp() and
|
||||
points_to(f.getOperand(), context, operand, _)
|
||||
|
|
||||
operand.maybe() and value = ObjectInternal::bool(_)
|
||||
op instanceof Not and operand.maybe() and value = ObjectInternal::bool(_)
|
||||
or
|
||||
operand.booleanValue() = false and value = ObjectInternal::bool(true)
|
||||
op instanceof Not and operand.booleanValue() = false and value = ObjectInternal::bool(true)
|
||||
or
|
||||
operand.booleanValue() = true and value = ObjectInternal::bool(false)
|
||||
op instanceof Not and operand.booleanValue() = true and value = ObjectInternal::bool(false)
|
||||
or
|
||||
op instanceof USub and value = ObjectInternal::fromInt(-operand.intValue())
|
||||
or
|
||||
operand = ObjectInternal::unknown() and value = operand
|
||||
)
|
||||
}
|
||||
|
||||
@@ -589,6 +582,122 @@ module InterProceduralPointsTo {
|
||||
)
|
||||
}
|
||||
|
||||
/** Points-to for parameter. `def foo(param): ...`. */
|
||||
pragma [noinline]
|
||||
predicate parameter_points_to(ParameterDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
positional_parameter_points_to(def, context, value, origin)
|
||||
or
|
||||
named_parameter_points_to(def, context, value, origin)
|
||||
or
|
||||
default_parameter_points_to(def, context, value, origin)
|
||||
// or
|
||||
// special_parameter_points_to(def, context, value, origin)
|
||||
}
|
||||
|
||||
/** Helper for `parameter_points_to` */
|
||||
pragma [noinline]
|
||||
private predicate positional_parameter_points_to(ParameterDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
exists(PointsToContext2 caller, ControlFlowNode arg |
|
||||
PointsTo2::points_to(arg, caller, value, origin) and
|
||||
callsite_argument_transfer(arg, caller, def, context)
|
||||
)
|
||||
or
|
||||
not def.isSelf() and not def.getParameter().isVarargs() and not def.getParameter().isKwargs() and
|
||||
context.isRuntime() and value = ObjectInternal::unknown() and origin = def.getDefiningNode()
|
||||
}
|
||||
|
||||
|
||||
/** Helper for `parameter_points_to` */
|
||||
pragma [noinline]
|
||||
private predicate named_parameter_points_to(ParameterDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
exists(CallNode call, PointsToContext2 caller, PythonFunctionObjectInternal func, string name |
|
||||
context.fromCall(call, func, caller) and
|
||||
def.getParameter() = func.getScope().getArgByName(name) and
|
||||
PointsTo2::points_to(call.getArgByName(name), caller, value, origin)
|
||||
)
|
||||
}
|
||||
|
||||
/** Helper for parameter_points_to */
|
||||
private predicate default_parameter_points_to(ParameterDefinition def, PointsToContext2 context, ObjectInternal value, ControlFlowNode origin) {
|
||||
exists(PointsToContext2 imp | imp.isImport() | PointsTo2::points_to(def.getDefault(), imp, value, origin)) and
|
||||
context_for_default_value(def, context)
|
||||
}
|
||||
|
||||
/** Helper for default_parameter_points_to */
|
||||
pragma [noinline]
|
||||
private predicate context_for_default_value(ParameterDefinition def, PointsToContext2 context) {
|
||||
context.isRuntime()
|
||||
or
|
||||
exists(PointsToContext2 caller, CallNode call, PythonFunctionObjectInternal func, int n |
|
||||
context.fromCall(call, func, caller) and
|
||||
func.getScope().getArg(n) = def.getParameter() and
|
||||
not exists(call.getArg(n)) and
|
||||
not exists(call.getArgByName(def.getParameter().asName().getId())) and
|
||||
not exists(call.getNode().getKwargs()) and
|
||||
not exists(call.getNode().getStarargs())
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the `(argument, caller)` pair matches up with `(param, callee)` pair across call. */
|
||||
cached predicate callsite_argument_transfer(ControlFlowNode argument, PointsToContext2 caller, ParameterDefinition param, PointsToContext2 callee) {
|
||||
exists(CallNode call, Function func, int n, int offset |
|
||||
callsite_calls_function(call, caller, func, callee, offset) and
|
||||
argument = call.getArg(n) and
|
||||
param.getParameter() = func.getArg(n+offset)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate callsite_calls_function(CallNode call, PointsToContext2 caller, Function scope, PointsToContext2 callee, int parameter_offset) {
|
||||
callee.fromCall(call, caller) and
|
||||
exists(ObjectInternal func |
|
||||
PointsTo2::points_to(call.getFunction(), caller, func, _) and
|
||||
func.calleeAndOffset(scope, parameter_offset)
|
||||
)
|
||||
}
|
||||
|
||||
/** Model the transfer of values at scope-entry points. Transfer from `(pred_var, pred_context)` to `(succ_def, succ_context)`. */
|
||||
cached predicate scope_entry_value_transfer(EssaVariable pred_var, PointsToContext2 pred_context, ScopeEntryDefinition succ_def, PointsToContext2 succ_context) {
|
||||
scope_entry_value_transfer_from_earlier(pred_var, pred_context, succ_def, succ_context)
|
||||
// TO DO...
|
||||
//or
|
||||
//callsite_entry_value_transfer(pred_var, pred_context, succ_def, succ_context)
|
||||
//or
|
||||
//pred_context.isImport() and pred_context = succ_context and
|
||||
//class_entry_value_transfer(pred_var, succ_def)
|
||||
}
|
||||
|
||||
/** Helper for `scope_entry_value_transfer`. Transfer of values from a temporally earlier scope to later scope.
|
||||
* Earlier and later scopes are, for example, a module and functions in that module, or an __init__ method and another method. */
|
||||
pragma [noinline]
|
||||
private predicate scope_entry_value_transfer_from_earlier(EssaVariable pred_var, PointsToContext2 pred_context, ScopeEntryDefinition succ_def, PointsToContext2 succ_context) {
|
||||
exists(Scope pred_scope, Scope succ_scope |
|
||||
BaseFlow::scope_entry_value_transfer_from_earlier(pred_var, pred_scope, succ_def, succ_scope) and
|
||||
succ_context.appliesToScope(succ_scope)
|
||||
|
|
||||
succ_context.isRuntime() and succ_context = pred_context
|
||||
or
|
||||
pred_context.isImport() and pred_scope instanceof ImportTimeScope and
|
||||
(succ_context.fromRuntime() or
|
||||
/* A call made at import time, but from another module. Assume this module has been fully imported. */
|
||||
succ_context.isCall() and exists(CallNode call | succ_context.fromCall(call, _) and call.getEnclosingModule() != pred_scope))
|
||||
or
|
||||
/* If predecessor scope is main, then we assume that any global defined exactly once
|
||||
* is available to all functions. Although not strictly true, this gives less surprising
|
||||
* results in practice. */
|
||||
pred_context.isMain() and pred_scope instanceof Module and succ_context.fromRuntime() and
|
||||
exists(Variable v |
|
||||
v = pred_var.getSourceVariable() and
|
||||
not strictcount(v.getAStore()) > 1
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(NonEscapingGlobalVariable var |
|
||||
var = pred_var.getSourceVariable() and var = succ_def.getSourceVariable() and
|
||||
pred_var.getAUse() = succ_context.getRootCall() and pred_context.isImport() and
|
||||
succ_context.appliesToScope(succ_def.getScope())
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Gets the `value, origin` that `f` would refer to if it has not been assigned some other value */
|
||||
@@ -630,6 +739,8 @@ module Conditionals {
|
||||
//or
|
||||
result = equalityEvaluatesTo(expr, use, context, val, origin)
|
||||
or
|
||||
result = inequalityEvaluatesTo(expr, use, context, val, origin)
|
||||
or
|
||||
//result = callable_test_evaluates_boolean(expr, use, context, val, origin)
|
||||
//or
|
||||
//result = hasattr_test_evaluates_boolean(expr, use, context, val, origin)
|
||||
@@ -677,4 +788,33 @@ module Conditionals {
|
||||
)
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
private boolean inequalityEvaluatesTo(ControlFlowNode expr, ControlFlowNode use, PointsToContext2 context, ObjectInternal val, ControlFlowNode origin) {
|
||||
exists(ControlFlowNode r, boolean sense |
|
||||
contains_interesting_expression_within_test(expr, use) |
|
||||
exists(boolean strict, ObjectInternal other |
|
||||
(
|
||||
PointsTo2::inequality(expr, use, r, strict) and sense = true
|
||||
or
|
||||
PointsTo2::inequality(expr, r, use, strict) and sense = false
|
||||
) and
|
||||
PointsTo2::points_to(use, context, val, origin) and
|
||||
PointsTo2::points_to(r, context, other, _)
|
||||
|
|
||||
val.intValue() < other.intValue() and result = sense
|
||||
or
|
||||
val.intValue() > other.intValue() and result = sense.booleanNot()
|
||||
or
|
||||
val.intValue() = other.intValue() and result = strict.booleanXor(sense)
|
||||
or
|
||||
val.strValue() < other.strValue() and result = sense
|
||||
or
|
||||
val.strValue() > other.strValue() and result = sense.booleanNot()
|
||||
or
|
||||
val.strValue() = other.strValue() and result = strict.booleanXor(sense)
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ private import semmle.python.objects.ObjectInternal
|
||||
*/
|
||||
|
||||
private int given_cost() {
|
||||
exists(string depth |
|
||||
exists(string depth |
|
||||
py_flags_versioned("context.cost", depth, _) and
|
||||
result = depth.toInt()
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user