Skip to content
Merged
Changes from 1 commit
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
85 changes: 56 additions & 29 deletions shared/ssa/codeql/ssa/Ssa.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,13 @@ module Make<LocationSig Location, InputSig<Location> Input> {

/** Holds if `guard` controls block `bb` upon evaluating to `branch`. */
predicate guardControlsBlock(Guard guard, BasicBlock bb, boolean branch);

/**
* Holds if `WriteDefinition`s should be included as an intermediate node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is restricted to certain WriteDefinitions, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no. Flipping this switch will remove all certain writes from the use-use steps. It will also cause us to step over uncertain write nodes for the RHS-to-first-use steps, but those nodes will remain in the graph as stepping stones from prior uses. It's potentially possible to skip over uncertain writes when stepping from prior uses, but that requires some additional analysis to ensure that we only do so when it won't cause blowups, and the potential gain seemed so small that I didn't bother with that particular graph reduction.

* between the assigned `Expr` or `Parameter` and the first read of the SSA
* definition.
*/
default predicate includeWriteDefsInFlowStep() { any() }
}

/**
Expand Down Expand Up @@ -1783,42 +1790,29 @@ module Make<LocationSig Location, InputSig<Location> Input> {
exists(DefinitionExt def |
nodeFrom.(SsaDefinitionExtNodeImpl).getDefExt() = def and
def.definesAt(v, bb, i, _) and
isUseStep = false
isUseStep = false and
if DfInput::includeWriteDefsInFlowStep()
then any()
else (
def instanceof PhiNode or
def instanceof PhiReadNode or
DfInput::allowFlowIntoUncertainDef(def)
)
)
or
[nodeFrom, nodeFrom.(ExprPostUpdateNode).getPreUpdateNode()].(ReadNode).readsAt(bb, i, v) and
isUseStep = true
}

/**
* Holds if there is a local flow step from `nodeFrom` to `nodeTo`.
*
* `isUseStep` is `true` when `nodeFrom` is a (post-update) read node and
* `nodeTo` is a read node or phi (read) node.
*/
predicate localFlowStep(SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
exists(Definition def |
// Flow from assignment into SSA definition
DfInput::ssaDefAssigns(def, nodeFrom.(ExprNode).getExpr())
or
// Flow from parameter into entry definition
DfInput::ssaDefInitializesParam(def, nodeFrom.(ParameterNode).getParameter())
|
nodeTo.(SsaDefinitionNode).getDefinition() = def and
v = def.getSourceVariable() and
isUseStep = false
)
or
private predicate flowFromRefToNode(SourceVariable v, BasicBlock bb1, int i1, Node nodeTo) {
// Flow from definition/read to next read
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
flowOutOf(nodeFrom, v, bb1, i1, isUseStep) and
exists(BasicBlock bb2, int i2 |
AdjacentSsaRefs::adjacentRefRead(bb1, i1, bb2, i2, v) and
nodeTo.(ReadNode).readsAt(bb2, i2, v)
)
or
// Flow from definition/read to next uncertain write
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
flowOutOf(nodeFrom, v, bb1, i1, isUseStep) and
exists(BasicBlock bb2, int i2 |
AdjacentSsaRefs::adjacentRefRead(bb1, i1, bb2, i2, v) and
exists(UncertainWriteDefinition def2 |
DfInput::allowFlowIntoUncertainDef(def2) and
Expand All @@ -1828,12 +1822,43 @@ module Make<LocationSig Location, InputSig<Location> Input> {
)
or
// Flow from definition/read to phi input
exists(BasicBlock bb, int i, BasicBlock input, BasicBlock bbPhi, DefinitionExt phi |
flowOutOf(nodeFrom, v, bb, i, isUseStep) and
AdjacentSsaRefs::adjacentRefPhi(bb, i, input, bbPhi, v) and
exists(BasicBlock input, BasicBlock bbPhi, DefinitionExt phi |
AdjacentSsaRefs::adjacentRefPhi(bb1, i1, input, bbPhi, v) and
nodeTo = TSsaInputNode(phi, input) and
phi.definesAt(v, bbPhi, -1, _)
)
}

/**
* Holds if there is a local flow step from `nodeFrom` to `nodeTo`.
*
* `isUseStep` is `true` when `nodeFrom` is a (post-update) read node and
* `nodeTo` is a read node or phi (read) node.
*/
predicate localFlowStep(SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
exists(Definition def |
// Flow from assignment into SSA definition
DfInput::ssaDefAssigns(def, nodeFrom.(ExprNode).getExpr())
or
// Flow from parameter into entry definition
DfInput::ssaDefInitializesParam(def, nodeFrom.(ParameterNode).getParameter())
|
isUseStep = false and
if DfInput::includeWriteDefsInFlowStep()
then
nodeTo.(SsaDefinitionNode).getDefinition() = def and
v = def.getSourceVariable()
else
exists(BasicBlock bb1, int i1 |
def.definesAt(v, bb1, i1) and
flowFromRefToNode(v, bb1, i1, nodeTo)
)
)
or
exists(BasicBlock bb1, int i1 |
flowOutOf(nodeFrom, v, bb1, i1, isUseStep) and
flowFromRefToNode(v, bb1, i1, nodeTo)
)
or
// Flow from input node to def
exists(DefinitionExt def |
Expand All @@ -1853,8 +1878,10 @@ module Make<LocationSig Location, InputSig<Location> Input> {
// Flow from parameter into entry definition
DfInput::ssaDefInitializesParam(def, nodeFrom.(ParameterNode).getParameter())
|
nodeTo.(SsaDefinitionNode).getDefinition() = def and
v = def.getSourceVariable()
v = def.getSourceVariable() and
if DfInput::includeWriteDefsInFlowStep()
then nodeTo.(SsaDefinitionNode).getDefinition() = def
else nodeTo.(ExprNode).getExpr() = DfInput::getARead(def)
)
or
// Flow from SSA definition to read
Expand Down