Files
codeql/python/ql/src/Imports/ModuleLevelCyclicImport.ql
Taus 6b64443c49 Python: Port cyclic import queries
The new CyclicImports.qll is a fairly straight port of Cyclic.qll, with
the main changes being:

- We now use Module instead of ModuleValue everywhere
- We use getModuleReference instead of pointsTo
- is_import_time was replaced with a use of `ImportTimeScope`

The predicate that changed the most is `stmt_imports`, which in the
original just did `s.getASubExpression().pointsTo(result)`. The new
version has three branches, one for each kind of import, and with
special handling of imports from within a submodule (which is not
something that should be flagged).

No test changes.
2026-03-09 17:22:07 +00:00

33 lines
1.5 KiB
Plaintext

/**
* @name Module-level cyclic import
* @description Module uses member of cyclically imported module, which can lead to failure at import time.
* @kind problem
* @tags reliability
* correctness
* types
* @problem.severity error
* @sub-severity low
* @precision high
* @comprehension 0.5
* @id py/unsafe-cyclic-import
*/
import python
import CyclicImports
private import semmle.python.dataflow.new.internal.ImportResolution
// This is a potentially crashing bug if
// 1. the imports in the whole cycle are lexically outside a def (and so executed at import time)
// 2. there is a use ('M.foo' or 'from M import foo') of the imported module that is lexically outside a def
// 3. 'foo' is defined in M after the import in M which completes the cycle.
// then if we import the 'used' module, we will reach the cyclic import, start importing the 'using'
// module, hit the 'use', and then crash due to the imported symbol not having been defined yet
from Module m1, Stmt imp, Module m2, string attr, Expr use, ControlFlowNode defn
where failing_import_due_to_cycle(m1, m2, imp, defn, use, attr)
select use,
"'" + attr + "' may not be defined if module $@ is imported before module $@, as the $@ of " +
attr + " occurs after the cyclic $@ of " + ImportResolution::moduleName(m2) + ".",
// Arguments for the placeholders in the above message:
m1, ImportResolution::moduleName(m1), m2, ImportResolution::moduleName(m2), defn, "definition",
imp, "import"