mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python: Remove some negation from points-to, in preparation for ADT Objects.
This commit is contained in:
@@ -139,7 +139,7 @@ module PointsTo {
|
||||
var.getSourceVariable().getName() = name and
|
||||
ssa_variable_points_to(var, imp, obj, cls, orig) and
|
||||
imp.isImport() and
|
||||
not obj = undefinedVariable() |
|
||||
obj != undefinedVariable() |
|
||||
origin = origin_from_object_or_here(orig, exit)
|
||||
)
|
||||
or
|
||||
@@ -147,7 +147,7 @@ module PointsTo {
|
||||
exists(EssaVariable var, PointsToContext imp |
|
||||
var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = "*" |
|
||||
SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and
|
||||
imp.isImport() and not obj = undefinedVariable()
|
||||
imp.isImport() and obj != undefinedVariable()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ module PointsTo {
|
||||
/** Holds if `f` is the instantiation of an object, `cls(...)`. */
|
||||
cached predicate instantiation(CallNode f, PointsToContext context, ClassObject cls) {
|
||||
points_to(f.getFunction(), context, cls, _, _) and
|
||||
not cls = theTypeType() and
|
||||
cls != theTypeType() and
|
||||
Types::callToClassWillReturnInstance(cls)
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ module PointsTo {
|
||||
)
|
||||
or
|
||||
exists(Object obj |
|
||||
not obj = undefinedVariable() and
|
||||
obj != undefinedVariable() and
|
||||
py_module_attributes(mod.getModule(), name, obj, _, _)
|
||||
) and result = true
|
||||
or
|
||||
@@ -346,7 +346,7 @@ module PointsTo {
|
||||
private boolean package_exports_boolean(PackageObject pack, string name) {
|
||||
explicitly_imported(pack.submodule(name)) and
|
||||
(
|
||||
not exists(pack.getInitModule())
|
||||
pack.hasNoInitModule()
|
||||
or
|
||||
exists(ModuleObject init |
|
||||
pack.getInitModule() = init |
|
||||
@@ -382,9 +382,11 @@ module PointsTo {
|
||||
exists(Object value |
|
||||
points_to(guard.getLastNode(), context, value, _, _)
|
||||
|
|
||||
guard.controls(b, true) and not value.booleanValue() = false
|
||||
guard.controls(b, _) and value.maybe()
|
||||
or
|
||||
guard.controls(b, false) and not value.booleanValue() = true
|
||||
guard.controls(b, true) and value.booleanValue() = true
|
||||
or
|
||||
guard.controls(b, false) and value.booleanValue() = false
|
||||
)
|
||||
or
|
||||
/* Assume the true edge of an assert is reachable (except for assert 0/False) */
|
||||
@@ -403,9 +405,11 @@ module PointsTo {
|
||||
exists(ConditionBlock guard, Object value |
|
||||
points_to(guard.getLastNode(), context, value, _, _)
|
||||
|
|
||||
guard.controlsEdge(pred, succ, true) and not value.booleanValue() = false
|
||||
guard.controlsEdge(pred, succ, _) and value.maybe()
|
||||
or
|
||||
guard.controlsEdge(pred, succ, false) and not value.booleanValue() = true
|
||||
guard.controlsEdge(pred, succ, true) and value.booleanValue() = true
|
||||
or
|
||||
guard.controlsEdge(pred, succ, false) and value.booleanValue() = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -554,7 +558,7 @@ module PointsTo {
|
||||
/** Gets an object pointed to by a use (of a variable). */
|
||||
private predicate use_points_to(NameNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
|
||||
exists(ObjectOrCfg origin_or_obj |
|
||||
not value = undefinedVariable() and
|
||||
value != undefinedVariable() and
|
||||
use_points_to_maybe_origin(f, context, value, cls, origin_or_obj) |
|
||||
origin = origin_from_object_or_here(origin_or_obj, f)
|
||||
)
|
||||
@@ -578,7 +582,7 @@ module PointsTo {
|
||||
pragma [noinline]
|
||||
private predicate class_or_module_attribute(Object obj, string name, Object value, ClassObject cls, ObjectOrCfg orig) {
|
||||
/* Normal class attributes */
|
||||
Types::class_attribute_lookup(obj, name, value, cls, orig) and not cls = theStaticMethodType() and not cls = theClassMethodType()
|
||||
Types::class_attribute_lookup(obj, name, value, cls, orig) and cls != theStaticMethodType() and cls != theClassMethodType()
|
||||
or
|
||||
/* Static methods of the class */
|
||||
exists(CallNode sm | Types::class_attribute_lookup(obj, name, sm, theStaticMethodType(), _) and sm.getArg(0) = value and cls = thePyFunctionType() and orig = value)
|
||||
@@ -849,9 +853,13 @@ module PointsTo {
|
||||
exists(Object operand |
|
||||
points_to(f.getOperand(), context, operand, _, _)
|
||||
|
|
||||
not operand.booleanValue() = true and value = theTrueObject()
|
||||
operand.maybe() and value = theTrueObject()
|
||||
or
|
||||
not operand.booleanValue() = false and value = theFalseObject()
|
||||
operand.maybe() and value = theFalseObject()
|
||||
or
|
||||
operand.booleanValue() = false and value = theTrueObject()
|
||||
or
|
||||
operand.booleanValue() = true and value = theFalseObject()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -999,17 +1007,18 @@ module PointsTo {
|
||||
pragma [noinline]
|
||||
predicate call_points_to_builtin_function(CallNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
|
||||
exists(BuiltinCallable b |
|
||||
not b = builtin_object("isinstance") and
|
||||
not b = builtin_object("issubclass") and
|
||||
not b = builtin_object("callable") and
|
||||
b != builtin_object("isinstance") and
|
||||
b != builtin_object("issubclass") and
|
||||
b != builtin_object("callable") and
|
||||
f = get_a_call(b, context) and
|
||||
cls = b.getAReturnType()
|
||||
) and
|
||||
f = origin and
|
||||
if cls = theNoneType() then
|
||||
value = theNoneObject()
|
||||
else
|
||||
value = f
|
||||
(
|
||||
cls = theNoneType() and value = theNoneObject()
|
||||
or
|
||||
cls != theNoneType() and value = f
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if call is to an object that always returns its first argument.
|
||||
@@ -1156,7 +1165,7 @@ module PointsTo {
|
||||
cls != theSuperType() and
|
||||
exists(Object o |
|
||||
/* list.__init__() is not a call to type.__init__() */
|
||||
not o instanceof ClassObject |
|
||||
o.notClass() |
|
||||
points_to(n.(AttrNode).getObject(name), context, o, cls, _)
|
||||
)
|
||||
or
|
||||
@@ -1199,12 +1208,14 @@ module PointsTo {
|
||||
|
||||
/** Holds if `func` implicitly returns the `None` object */
|
||||
predicate implicitly_returns(PyFunctionObject func, Object none_, ClassObject noneType) {
|
||||
noneType = theNoneType() and not func.getFunction().isGenerator() and none_ = theNoneObject() and
|
||||
(
|
||||
not exists(func.getAReturnedNode()) and exists(func.getFunction().getANormalExit())
|
||||
or
|
||||
exists(Return ret | ret.getScope() = func.getFunction() and not exists(ret.getValue()))
|
||||
)
|
||||
noneType = theNoneType() and none_ = theNoneObject() and
|
||||
exists(Function f |
|
||||
f = func.getFunction() and not f.isGenerator()
|
||||
|
|
||||
not exists(Return ret | ret.getScope() = f) and exists(f.getANormalExit())
|
||||
or
|
||||
exists(Return ret | ret.getScope() = f and not exists(ret.getValue()))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1240,7 +1251,10 @@ module PointsTo {
|
||||
* 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
|
||||
not strictcount(pred_var.getSourceVariable().(Variable).getAStore()) > 1
|
||||
exists(Variable v |
|
||||
v = pred_var.getSourceVariable() and
|
||||
not strictcount(v.getAStore()) > 1
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(NonEscapingGlobalVariable var |
|
||||
@@ -1567,8 +1581,8 @@ module PointsTo {
|
||||
deco = f.getADecorator().getAFlowNode() |
|
||||
exists(Object o |
|
||||
points_to(deco, _, o, _, _) |
|
||||
not o = theStaticMethodType() and
|
||||
not o = theClassMethodType()
|
||||
o != theStaticMethodType() and
|
||||
o != theClassMethodType()
|
||||
)
|
||||
or not deco instanceof NameNode
|
||||
)
|
||||
@@ -1585,7 +1599,7 @@ module PointsTo {
|
||||
|
|
||||
obj instanceof ClassObject and value = obj and cls = objcls
|
||||
or
|
||||
not obj instanceof ClassObject and value = objcls and cls = Types::class_get_meta_class(objcls)
|
||||
obj.notClass() and value = objcls and cls = Types::class_get_meta_class(objcls)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1703,16 +1717,17 @@ module PointsTo {
|
||||
call = def.getCall() and
|
||||
var = def.getSourceVariable() and
|
||||
context.untrackableCall(call) and
|
||||
exists(PyFunctionObject modifier |
|
||||
exists(PyFunctionObject modifier, Function f |
|
||||
f = modifier.getFunction() and
|
||||
call = get_a_call(modifier, context) and
|
||||
not modifies_escaping_variable(modifier, var)
|
||||
not modifies_escaping_variable(f, var)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate modifies_escaping_variable(FunctionObject modifier, PythonSsaSourceVariable var) {
|
||||
private predicate modifies_escaping_variable(Function modifier, PythonSsaSourceVariable var) {
|
||||
exists(var.redefinedAtCallSite()) and
|
||||
modifier.getFunction().getBody().contains(var.(Variable).getAStore())
|
||||
modifier.getBody().contains(var.(Variable).getAStore())
|
||||
}
|
||||
|
||||
pragma [noinline]
|
||||
@@ -2316,7 +2331,7 @@ module PointsTo {
|
||||
or
|
||||
cls = theObjectType() and result = 0
|
||||
or
|
||||
exists(builtin_base_type(cls)) and not cls = theObjectType() and result = 1
|
||||
exists(builtin_base_type(cls)) and cls != theObjectType() and result = 1
|
||||
or
|
||||
cls = theUnknownType() and result = 1
|
||||
}
|
||||
@@ -2472,7 +2487,7 @@ module PointsTo {
|
||||
/** INTERNAL -- Use `ClassObject.declaredAttribute(name). instead. */
|
||||
cached predicate class_declared_attribute(ClassObject owner, string name, Object value, ClassObject vcls, ObjectOrCfg origin) {
|
||||
/* Note that src_var must be a local variable, we aren't interested in the value that any global variable may hold */
|
||||
not value = undefinedVariable() and
|
||||
value != undefinedVariable() and
|
||||
exists(EssaVariable var, LocalVariable src_var |
|
||||
var.getSourceVariable() = src_var and
|
||||
src_var.getId() = name and
|
||||
@@ -2557,7 +2572,12 @@ module PointsTo {
|
||||
or
|
||||
exists(int i | failed_inference(class_base_type(cls, i), _) and reason = "Failed inference for base class at position " + i)
|
||||
or
|
||||
exists(int i | strictcount(class_base_type(cls, i)) > 1 and reason = "Multiple bases at position " + i)
|
||||
exists(int i, Object base1, Object base2 |
|
||||
base1 = class_base_type(cls, i) and
|
||||
base2 = class_base_type(cls, i) and
|
||||
base1 != base2 and
|
||||
reason = "Multiple bases at position " + i
|
||||
)
|
||||
or
|
||||
exists(int i, int j | class_base_type(cls, i) = class_base_type(cls, j) and i != j and reason = "Duplicate bases classes")
|
||||
or
|
||||
@@ -2577,7 +2597,7 @@ module PointsTo {
|
||||
|
||||
private ClassObject declared_meta_class(ClassObject cls) {
|
||||
exists(Object obj |
|
||||
ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) |
|
||||
ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) |
|
||||
result = obj
|
||||
or
|
||||
obj = unknownValue() and result = theUnknownType()
|
||||
@@ -2593,28 +2613,30 @@ module PointsTo {
|
||||
|
||||
private boolean has_metaclass_var_metaclass(ClassObject cls) {
|
||||
exists(Object obj |
|
||||
ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) |
|
||||
ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) |
|
||||
obj = undefinedVariable() and result = false
|
||||
or
|
||||
obj != undefinedVariable() and result = true
|
||||
)
|
||||
or
|
||||
not exists(metaclass_var(cls)) and result = false
|
||||
exists(Class pycls |
|
||||
pycls = cls.getPyClass() and
|
||||
not exists(metaclass_var(pycls)) and result = false
|
||||
)
|
||||
}
|
||||
|
||||
private boolean has_declared_metaclass(ClassObject cls) {
|
||||
py_cobjecttypes(cls, _) and result = true
|
||||
or
|
||||
not cls.isBuiltin() and
|
||||
result = has_six_add_metaclass(cls).booleanOr(has_metaclass_var_metaclass(cls))
|
||||
}
|
||||
|
||||
private EssaVariable metaclass_var(ClassObject cls) {
|
||||
result.getASourceUse() = cls.getPyClass().getMetaClass().getAFlowNode()
|
||||
private EssaVariable metaclass_var(Class cls) {
|
||||
result.getASourceUse() = cls.getMetaClass().getAFlowNode()
|
||||
or
|
||||
major_version() = 2 and not exists(cls.getPyClass().getMetaClass()) and
|
||||
major_version() = 2 and not exists(cls.getMetaClass()) and
|
||||
result.getName() = "__metaclass__" and
|
||||
cls.getPyClass().(ImportTimeScope).entryEdge(result.getAUse(), _)
|
||||
cls.(ImportTimeScope).entryEdge(result.getAUse(), _)
|
||||
}
|
||||
|
||||
private ClassObject get_inherited_metaclass(ClassObject cls) {
|
||||
@@ -2624,7 +2646,7 @@ module PointsTo {
|
||||
exists(Object base |
|
||||
base = class_base_type(cls, _) and
|
||||
result = theUnknownType() |
|
||||
not base instanceof ClassObject
|
||||
base.notClass()
|
||||
or
|
||||
base = theUnknownType()
|
||||
)
|
||||
|
||||
@@ -392,6 +392,10 @@ class ClassObject extends Object {
|
||||
result.getFunction().refersTo(this)
|
||||
}
|
||||
|
||||
predicate notClass() {
|
||||
none()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The 'str' class. This is the same as the 'bytes' class for
|
||||
|
||||
@@ -226,6 +226,14 @@ class PackageObject extends ModuleObject {
|
||||
result.getModule() = this.getModule().getInitModule()
|
||||
}
|
||||
|
||||
/** Holds if this package has no `__init__.py` file. */
|
||||
predicate hasNoInitModule() {
|
||||
not exists(Module m |
|
||||
m.isPackageInit() and
|
||||
m.getFile().getParent() = this.getPath()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate exportsComplete() {
|
||||
not exists(this.getInitModule())
|
||||
or
|
||||
|
||||
@@ -151,6 +151,14 @@ class Object extends @py_object {
|
||||
)
|
||||
}
|
||||
|
||||
final predicate maybe() {
|
||||
not exists(this.booleanValue())
|
||||
}
|
||||
|
||||
predicate notClass() {
|
||||
any()
|
||||
}
|
||||
|
||||
/** Holds if this object can be referred to by `longName`
|
||||
* For example, the modules `dict` in the `sys` module
|
||||
* has the long name `sys.modules` and the name `os.path.join`
|
||||
|
||||
Reference in New Issue
Block a user