mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge pull request #6650 from yoff/python-dataflow/init-time
Python: Import time dataflow
This commit is contained in:
@@ -152,6 +152,7 @@ class DataFlowExpr = Expr;
|
||||
* Flow comes from definitions, uses and refinements.
|
||||
*/
|
||||
// TODO: Consider constraining `nodeFrom` and `nodeTo` to be in the same scope.
|
||||
// If they have different enclosing callables, we get consistency errors.
|
||||
module EssaFlow {
|
||||
predicate essaFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Definition
|
||||
@@ -228,35 +229,60 @@ module EssaFlow {
|
||||
//--------
|
||||
/**
|
||||
* This is the local flow predicate that is used as a building block in global
|
||||
* data flow. It is a strict subset of the `localFlowStep` predicate, as it
|
||||
* excludes SSA flow through instance fields.
|
||||
* data flow.
|
||||
*
|
||||
* Local flow can happen either at import time, when the module is initialised
|
||||
* or at runtime when callables in the module are called.
|
||||
*/
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// If there is ESSA-flow out of a node `node`, we want flow
|
||||
// If there is local flow out of a node `node`, we want flow
|
||||
// both out of `node` and any post-update node of `node`.
|
||||
exists(Node node |
|
||||
EssaFlow::essaFlowStep(node, nodeTo) and
|
||||
nodeFrom = update(node) and
|
||||
(
|
||||
not node instanceof EssaNode or
|
||||
not nodeTo instanceof EssaNode or
|
||||
localEssaStep(node, nodeTo)
|
||||
importTimeLocalFlowStep(node, nodeTo) or
|
||||
runtimeLocalFlowStep(node, nodeTo)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is an Essa flow step from `nodeFrom` to `nodeTo` that does not switch between
|
||||
* local and global SSA variables.
|
||||
* Holds if `node` is found at the top level of a module.
|
||||
*/
|
||||
private predicate localEssaStep(EssaNode nodeFrom, EssaNode nodeTo) {
|
||||
EssaFlow::essaFlowStep(nodeFrom, nodeTo) and
|
||||
(
|
||||
nodeFrom.getVar() instanceof GlobalSsaVariable and
|
||||
nodeTo.getVar() instanceof GlobalSsaVariable
|
||||
or
|
||||
not nodeFrom.getVar() instanceof GlobalSsaVariable and
|
||||
not nodeTo.getVar() instanceof GlobalSsaVariable
|
||||
pragma[inline]
|
||||
predicate isTopLevel(Node node) { node.getScope() instanceof Module }
|
||||
|
||||
/** Holds if there is local flow from `nodeFrom` to `nodeTo` at import time. */
|
||||
predicate importTimeLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// As a proxy for whether statements can be executed at import time,
|
||||
// we check if they appear at the top level.
|
||||
// This will miss statements inside functions called from the top level.
|
||||
isTopLevel(nodeFrom) and
|
||||
isTopLevel(nodeTo) and
|
||||
EssaFlow::essaFlowStep(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
/** Holds if there is local flow from `nodeFrom` to `nodeTo` at runtime. */
|
||||
predicate runtimeLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
// Anything not at the top level can be executed at runtime.
|
||||
not isTopLevel(nodeFrom) and
|
||||
not isTopLevel(nodeTo) and
|
||||
EssaFlow::essaFlowStep(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
/** `ModuleVariable`s are accessed via jump steps at runtime. */
|
||||
predicate runtimeJumpStep(Node nodeFrom, Node nodeTo) {
|
||||
// Module variable read
|
||||
nodeFrom.(ModuleVariableNode).getARead() = nodeTo
|
||||
or
|
||||
// Module variable write
|
||||
nodeFrom = nodeTo.(ModuleVariableNode).getAWrite()
|
||||
or
|
||||
// Setting the possible values of the variable at the end of import time
|
||||
exists(SsaVariable def |
|
||||
def = any(SsaVariable var).getAnUltimateDefinition() and
|
||||
def.getDefinition() = nodeFrom.asCfgNode() and
|
||||
def.getVariable() = nodeTo.(ModuleVariableNode).getVariable()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -860,11 +886,7 @@ string ppReprType(DataFlowType t) { none() }
|
||||
* taken into account.
|
||||
*/
|
||||
predicate jumpStep(Node nodeFrom, Node nodeTo) {
|
||||
// Module variable read
|
||||
nodeFrom.(ModuleVariableNode).getARead() = nodeTo
|
||||
or
|
||||
// Module variable write
|
||||
nodeFrom = nodeTo.(ModuleVariableNode).getAWrite()
|
||||
runtimeJumpStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Read of module attribute:
|
||||
exists(AttrRead r, ModuleValue mv |
|
||||
|
||||
@@ -332,7 +332,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
|
||||
override Scope getScope() { result = mod }
|
||||
|
||||
override string toString() {
|
||||
result = "ModuleVariableNode for " + var.toString() + " in " + mod.toString()
|
||||
result = "ModuleVariableNode for " + mod.getName() + "." + var.getId()
|
||||
}
|
||||
|
||||
/** Gets the module in which this variable appears. */
|
||||
|
||||
Reference in New Issue
Block a user