mirror of
https://github.com/github/codeql.git
synced 2026-06-23 05:37:02 +02:00
Preparatory refactor for the shared-CFG dataflow migration. Deprecates the AstNode.getAFlowNode() cached predicate on the public Python QL API and rewrites all ~140 internal callers across lib/, src/, test/, and tools/ from `expr.getAFlowNode() = cfgNode` to `cfgNode.getNode() = expr`, using ControlFlowNode.getNode() which already exists in Flow.qll. The predicate itself is preserved (with a deprecation note pointing at the new pattern) so external users do not experience churn — they can migrate at their own pace and the AST/CFG hierarchies still get the intended untangling once the deprecation eventually elapses. Semantic noop verified by: - All 361 lib/ + src/ queries compile clean. - All 122 ControlFlow + PointsTo library-tests pass. - All 64 dataflow library-tests pass. - All 113 Variables/Exceptions/Expressions/Statements/Functions/Imports/ Security/CWE-798/ModificationOfParameterWithDefault query-tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
91 lines
2.6 KiB
Plaintext
91 lines
2.6 KiB
Plaintext
/**
|
|
* @name Unresolved import
|
|
* @description An unresolved import may result in reduced coverage and accuracy of analysis.
|
|
* @kind problem
|
|
* @problem.severity info
|
|
* @id py/import-failure
|
|
*/
|
|
|
|
import python
|
|
private import LegacyPointsTo
|
|
|
|
ImportExpr alternative_import(ImportExpr ie) {
|
|
exists(Alias thisalias, Alias otheralias |
|
|
(thisalias.getValue() = ie or thisalias.getValue().(ImportMember).getModule() = ie) and
|
|
(otheralias.getValue() = result or otheralias.getValue().(ImportMember).getModule() = result) and
|
|
(
|
|
exists(If i | i.getBody().contains(ie) and i.getOrelse().contains(result))
|
|
or
|
|
exists(If i | i.getBody().contains(result) and i.getOrelse().contains(ie))
|
|
or
|
|
exists(Try t | t.getBody().contains(ie) and t.getAHandler().contains(result))
|
|
or
|
|
exists(Try t | t.getBody().contains(result) and t.getAHandler().contains(ie))
|
|
)
|
|
)
|
|
}
|
|
|
|
string os_specific_import(ImportExpr ie) {
|
|
exists(string name | name = ie.getImportedModuleName() |
|
|
name.matches("org.python.%") and result = "java"
|
|
or
|
|
name.matches("java.%") and result = "java"
|
|
or
|
|
name.matches("Carbon.%") and result = "darwin"
|
|
or
|
|
result = "win32" and
|
|
(
|
|
name = "_winapi" or
|
|
name = "_win32api" or
|
|
name = "_winreg" or
|
|
name = "nt" or
|
|
name.matches("win32%") or
|
|
name = "ntpath"
|
|
)
|
|
or
|
|
result = "linux2" and
|
|
(name = "posix" or name = "posixpath")
|
|
or
|
|
result = "unsupported" and
|
|
(name = "__pypy__" or name = "ce" or name.matches("riscos%"))
|
|
)
|
|
}
|
|
|
|
string get_os() { py_flags_versioned("sys.platform", result, major_version().toString()) }
|
|
|
|
predicate ok_to_fail(ImportExpr ie) {
|
|
alternative_import(ie).(ExprWithPointsTo).refersTo(_)
|
|
or
|
|
os_specific_import(ie) != get_os()
|
|
}
|
|
|
|
final class FinalControlFlowNode = ControlFlowNode;
|
|
|
|
class VersionTest extends FinalControlFlowNode {
|
|
VersionTest() {
|
|
exists(string name |
|
|
name.matches("%version%") and
|
|
this.(CompareNode)
|
|
.getAChild+()
|
|
.(ControlFlowNodeWithPointsTo)
|
|
.pointsTo(Module::named("sys").attr(name))
|
|
)
|
|
}
|
|
|
|
string toString() { result = "VersionTest" }
|
|
}
|
|
|
|
/** A guard on the version of the Python interpreter */
|
|
class VersionGuard extends ConditionBlock {
|
|
VersionGuard() { this.getLastNode() instanceof VersionTest }
|
|
}
|
|
|
|
from ImportExpr ie, ControlFlowNode ieCfg
|
|
where
|
|
ieCfg.getNode() = ie and
|
|
not ie.(ExprWithPointsTo).refersTo(_) and
|
|
exists(Context c | c.appliesTo(ieCfg)) and
|
|
not ok_to_fail(ie) and
|
|
not exists(VersionGuard guard | guard.controls(ieCfg.getBasicBlock(), _))
|
|
select ie, "Unable to resolve import of '" + ie.getImportedModuleName() + "'."
|