Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 8 additions & 85 deletions python/ql/src/semmle/python/Flow.qll
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import python
import semmle.python.flow.NameNode
private import semmle.python.pointsto.PointsTo
private import semmle.python.Pruning

/* Note about matching parent and child nodes and CFG splitting:
*
Expand Down Expand Up @@ -33,10 +32,6 @@ private AstNode toAst(ControlFlowNode n) {
*/
class ControlFlowNode extends @py_flow_node {

cached ControlFlowNode() {
Pruner::reachable(this)
}

/** Whether this control flow node is a load (including those in augmented assignments) */
predicate isLoad() {
exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this))
Expand Down Expand Up @@ -180,8 +175,7 @@ class ControlFlowNode extends @py_flow_node {

/** Gets a successor of this flow node */
ControlFlowNode getASuccessor() {
py_successors(this, result) and
not Pruner::unreachableEdge(this, result)
py_successors(this, result)
}

/** Gets the immediate dominator of this flow node */
Expand Down Expand Up @@ -973,91 +967,21 @@ predicate defined_by(NameNode def, Variable v) {
exists(NameNode p | defined_by(p, v) and p.getASuccessor() = def and not p.defines(v))
}

/* Combine extractor-generated basic block after pruning */

private class BasicBlockPart extends @py_flow_node {

string toString() { result = "Basic block part" }

BasicBlockPart() {
py_flow_bb_node(_, _, this, _) and
Pruner::reachable(this)
}

predicate isHead() {
count(this.(ControlFlowNode).getAPredecessor()) != 1
or
exists(ControlFlowNode pred | pred = this.(ControlFlowNode).getAPredecessor() | strictcount(pred.getASuccessor()) > 1)
}

private BasicBlockPart previous() {
not this.isHead() and
py_flow_bb_node(this.(ControlFlowNode).getAPredecessor(), _, result, _)
}

BasicBlockPart getHead() {
this.isHead() and result = this
or
result = this.previous().getHead()
}

predicate isLast() {
not exists(BasicBlockPart part | part.previous() = this)
}

int length() {
result = max(int j | py_flow_bb_node(_, _, this, j)) + 1
}

int startIndex() {
this.isHead() and result = 0
or
exists(BasicBlockPart prev |
prev = this.previous() and
result = prev.startIndex() + prev.length()
)
}

predicate contains(ControlFlowNode node) {
py_flow_bb_node(node, _, this, _)
}

int indexOf(ControlFlowNode node) {
py_flow_bb_node(node, _, this, result)
}

ControlFlowNode lastNode() {
this.indexOf(result) = max(this.indexOf(_))
}

BasicBlockPart getImmediateDominator() {
result.contains(this.(ControlFlowNode).getImmediateDominator())
}

}

/** A basic block (ignoring exceptional flow edges to scope exit) */
class BasicBlock extends @py_flow_node {

BasicBlock() {
this.(BasicBlockPart).isHead()
}

private BasicBlockPart getAPart() {
result.getHead() = this
py_flow_bb_node(_, _, this, _)
}

/** Whether this basic block contains the specified node */
predicate contains(ControlFlowNode node) {
this.getAPart().contains(node)
py_flow_bb_node(node, _, this, _)
}

/** Gets the nth node in this basic block */
ControlFlowNode getNode(int n) {
exists(BasicBlockPart part |
part = this.getAPart() and
n = part.startIndex() + part.indexOf(result)
)
py_flow_bb_node(result, _, this, n)
}

string toString() {
Expand All @@ -1077,7 +1001,7 @@ class BasicBlock extends @py_flow_node {
}

cached BasicBlock getImmediateDominator() {
this.getAPart().getImmediateDominator() = result.getAPart()
this.firstNode().getImmediateDominator().getBasicBlock() = result
}

/** Dominance frontier of a node x is the set of all nodes `other` such that `this` dominates a predecessor
Expand All @@ -1093,10 +1017,9 @@ class BasicBlock extends @py_flow_node {

/** Gets the last node in this basic block */
ControlFlowNode getLastNode() {
exists(BasicBlockPart part |
part = this.getAPart() and
part.isLast() and
result = part.lastNode()
exists(int i |
this.getNode(i) = result and
i = max(int j | py_flow_bb_node(_, _, this, j))
)
}

Expand Down
Loading