mirror of
https://github.com/github/codeql.git
synced 2026-05-14 19:29:28 +02:00
Python: Port UndefinedGlobal.ql
Uses most of the machinery we have built up by now to implement this, so hopefully it should be an easy comparison. Also, extends the `monkeyPatchedBuiltin` with an additional way to patch built-ins (because this was needed to get a test to pass). No test changes.
This commit is contained in:
@@ -2005,10 +2005,18 @@ module DuckTyping {
|
||||
* Holds if `name` is monkey-patched into the builtins module.
|
||||
*/
|
||||
predicate monkeyPatchedBuiltin(string name) {
|
||||
exists(DataFlow::AttrWrite aw |
|
||||
API::moduleImport("builtins").getAValueReachableFromSource().asExpr() =
|
||||
aw.getObject().asExpr() and
|
||||
aw.getAttributeName() = name
|
||||
any(DataFlow::AttrWrite aw)
|
||||
.writes(API::moduleImport("builtins").getAValueReachableFromSource(), name, _)
|
||||
or
|
||||
// B.__dict__["name"] = value
|
||||
exists(SubscriptNode subscr |
|
||||
subscr.isStore() and
|
||||
subscr.getObject() =
|
||||
API::moduleImport("builtins")
|
||||
.getMember("__dict__")
|
||||
.getAValueReachableFromSource()
|
||||
.asCfgNode() and
|
||||
subscr.getIndex().getNode().(StringLiteral).getText() = name
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
private import LegacyPointsTo
|
||||
private import semmle.python.dataflow.new.internal.ImportResolution
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.types.ImportTime
|
||||
import Variables.MonkeyPatched
|
||||
import Loop
|
||||
|
||||
predicate guarded_against_name_error(Name u) {
|
||||
@@ -32,10 +33,13 @@ predicate guarded_against_name_error(Name u) {
|
||||
}
|
||||
|
||||
predicate contains_unknown_import_star(Module m) {
|
||||
exists(ImportStar imp | imp.getScope() = m |
|
||||
exists(ModuleValue imported | imported.importedAs(imp.getImportedModuleName()) |
|
||||
not imported.hasCompleteExportInfo()
|
||||
)
|
||||
exists(ImportStar imp, Module imported |
|
||||
imp.getScope() = m and
|
||||
ImportResolution::getModuleImportedByImportStar(imp) = imported
|
||||
|
|
||||
// The imported module dynamically creates attributes, so we can't
|
||||
// enumerate its exports.
|
||||
exists(Function f | f.getName() = "__getattr__" and f.getScope() = imported)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -60,9 +64,9 @@ predicate undefined_use_in_function(Name u) {
|
||||
)
|
||||
) and
|
||||
not u.getEnclosingModule().(ImportTimeScope).definesName(u.getId()) and
|
||||
not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and
|
||||
not globallyDefinedName(u.getId()) and
|
||||
not exists(SsaVariableWithPointsTo var | var.getAUse().getNode() = u and not var.maybeUndefined()) and
|
||||
not ImportResolution::module_export(u.getEnclosingModule(), u.getId(), _) and
|
||||
not DuckTyping::globallyDefinedName(u.getId()) and
|
||||
not Reachability::maybeUndefined(u) and
|
||||
not guarded_against_name_error(u) and
|
||||
not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__")
|
||||
}
|
||||
@@ -70,20 +74,18 @@ predicate undefined_use_in_function(Name u) {
|
||||
predicate undefined_use_in_class_or_module(Name u) {
|
||||
exists(GlobalVariable v | u.uses(v)) and
|
||||
not u.getScope().getScope*() instanceof Function and
|
||||
exists(SsaVariableWithPointsTo var | var.getAUse().getNode() = u | var.maybeUndefined()) and
|
||||
Reachability::maybeUndefined(u) and
|
||||
not guarded_against_name_error(u) and
|
||||
not exists(ModuleValue m | m.getScope() = u.getEnclosingModule() | m.hasAttribute(u.getId())) and
|
||||
not u.getEnclosingModule().(ImportTimeScope).definesName(u.getId()) and
|
||||
not ImportResolution::module_export(u.getEnclosingModule(), u.getId(), _) and
|
||||
not (u.getEnclosingModule().isPackageInit() and u.getId() = "__path__") and
|
||||
not globallyDefinedName(u.getId())
|
||||
not DuckTyping::globallyDefinedName(u.getId())
|
||||
}
|
||||
|
||||
predicate use_of_exec(Module m) {
|
||||
exists(Exec exec | exec.getScope() = m)
|
||||
or
|
||||
exists(CallNode call, FunctionValue exec | exec.getACall() = call and call.getScope() = m |
|
||||
exec = Value::named("exec") or
|
||||
exec = Value::named("execfile")
|
||||
)
|
||||
API::builtin(["exec", "execfile"]).getACall().getScope() = m
|
||||
}
|
||||
|
||||
predicate undefined_use(Name u) {
|
||||
@@ -92,11 +94,10 @@ predicate undefined_use(Name u) {
|
||||
or
|
||||
undefined_use_in_function(u)
|
||||
) and
|
||||
not monkey_patched_builtin(u.getId()) and
|
||||
not DuckTyping::monkeyPatchedBuiltin(u.getId()) and
|
||||
not contains_unknown_import_star(u.getEnclosingModule()) and
|
||||
not use_of_exec(u.getEnclosingModule()) and
|
||||
not exists(u.getVariable().getAStore()) and
|
||||
not u.(ExprWithPointsTo).pointsTo(_) and
|
||||
not probably_defined_in_loop(u)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user