Skip to content

Commit 9375e57

Browse files
committed
C++: Use SSA data flow integration module.
1 parent c7ff2f5 commit 9375e57

File tree

8 files changed

+220
-336
lines changed

8 files changed

+220
-336
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ predicate nodeIsHidden(Node n) {
13181318
or
13191319
n instanceof InitialGlobalValue
13201320
or
1321-
n instanceof SsaPhiInputNode
1321+
n instanceof SsaSynthNode
13221322
}
13231323

13241324
predicate neverSkipInPathGraph(Node n) {
@@ -1632,9 +1632,7 @@ private Instruction getAnInstruction(Node n) {
16321632
not n instanceof InstructionNode and
16331633
result = n.asOperand().getUse()
16341634
or
1635-
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
1636-
or
1637-
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
1635+
result = n.(SsaSynthNode).getBasicBlock().getFirstInstruction()
16381636
or
16391637
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
16401638
or

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 58 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import ExprNodes
2727
* - `VariableNode`, which is used to model flow through global variables.
2828
* - `PostUpdateNodeImpl`, which is used to model the state of an object after
2929
* an update after a number of loads.
30-
* - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA
30+
* - `SsaSynthNode`, which represents synthesized nodes as computed by the shared SSA
3131
* library.
3232
* - `RawIndirectOperand`, which represents the value of `operand` after
3333
* loading the address a number of times.
@@ -47,8 +47,7 @@ private newtype TIRDataFlowNode =
4747
or
4848
Ssa::isModifiableByCall(operand, indirectionIndex)
4949
} or
50-
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
51-
TSsaPhiNode(Ssa::PhiNode phi) or
50+
TSsaSynthNode(Ssa::SynthNode n) or
5251
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
5352
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
5453
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
@@ -184,10 +183,11 @@ class Node extends TIRDataFlowNode {
184183
or
185184
this.asOperand().getUse() = block.getInstruction(i)
186185
or
187-
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
188-
or
189-
this.(SsaPhiInputNode).getBlock() = block and
190-
i = block.getInstructionCount()
186+
exists(Ssa::SynthNode ssaNode |
187+
this.(SsaSynthNode).getSynthNode() = ssaNode and
188+
ssaNode.getBasicBlock() = block and
189+
ssaNode.getIndex() = i
190+
)
191191
or
192192
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
193193
or
@@ -686,117 +686,45 @@ class PostFieldUpdateNode extends PostUpdateNodeImpl {
686686
/**
687687
* INTERNAL: do not use.
688688
*
689-
* A phi node produced by the shared SSA library, viewed as a node in a data flow graph.
689+
* A synthesized SSA node produced by the shared SSA library, viewed as a node
690+
* in a data flow graph.
690691
*/
691-
class SsaPhiNode extends Node, TSsaPhiNode {
692-
Ssa::PhiNode phi;
692+
class SsaSynthNode extends Node, TSsaSynthNode {
693+
Ssa::SynthNode node;
693694

694-
SsaPhiNode() { this = TSsaPhiNode(phi) }
695+
SsaSynthNode() { this = TSsaSynthNode(node) }
695696

696-
/** Gets the phi node associated with this node. */
697-
Ssa::PhiNode getPhiNode() { result = phi }
697+
/** Gets the synthesized SSA node associated with this node. */
698+
Ssa::SynthNode getSynthNode() { result = node }
698699

699700
override DataFlowCallable getEnclosingCallable() {
700701
result.asSourceCallable() = this.getFunction()
701702
}
702703

703-
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
704+
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
704705

705-
override DataFlowType getType() {
706-
exists(Ssa::SourceVariable sv |
707-
this.getPhiNode().definesAt(sv, _, _, _) and
708-
result = sv.getType()
709-
)
710-
}
706+
override DataFlowType getType() { result = node.getSourceVariable().getType() }
711707

712-
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
708+
override predicate isGLValue() { node.getSourceVariable().isGLValue() }
713709

714-
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
715-
716-
override string toStringImpl() { result = phi.toString() }
717-
718-
/**
719-
* Gets a node that is used as input to this phi node.
720-
* `fromBackEdge` is true if data flows along a back-edge,
721-
* and `false` otherwise.
722-
*/
723-
cached
724-
final Node getAnInput(boolean fromBackEdge) {
725-
result.(SsaPhiInputNode).getPhiNode() = phi and
726-
exists(IRBlock bPhi, IRBlock bResult |
727-
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
728-
|
729-
if bPhi.dominates(bResult) then fromBackEdge = true else fromBackEdge = false
730-
)
731-
}
732-
733-
/** Gets a node that is used as input to this phi node. */
734-
final Node getAnInput() { result = this.getAnInput(_) }
735-
736-
/** Gets the source variable underlying this phi node. */
737-
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
710+
final override Location getLocationImpl() { result = node.getLocation() }
738711

739-
/**
740-
* Holds if this phi node is a phi-read node.
741-
*
742-
* Phi-read nodes are like normal phi nodes, but they are inserted based
743-
* on reads instead of writes.
744-
*/
745-
predicate isPhiRead() { phi.isPhiRead() }
712+
override string toStringImpl() { result = node.toString() }
746713
}
747714

748715
/**
749-
* INTERNAL: Do not use.
750-
*
751-
* A node that is used as an input to a phi node.
752-
*
753-
* This class exists to allow more powerful barrier guards. Consider this
754-
* example:
755-
*
756-
* ```cpp
757-
* int x = source();
758-
* if(!safe(x)) {
759-
* x = clear();
760-
* }
761-
* // phi node for x here
762-
* sink(x);
763-
* ```
764-
*
765-
* At the phi node for `x` it is neither the case that `x` is dominated by
766-
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
767-
*
768-
* By inserting a "phi input" node as the last entry in the basic block that
769-
* defines the inputs to the phi we can conclude that each of those inputs are
770-
* safe to pass to `sink`.
716+
* Holds if `n` has a local flow step that goes through a back-edge.
771717
*/
772-
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
773-
Ssa::PhiNode phi;
774-
IRBlock block;
775-
776-
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
777-
778-
/** Gets the phi node associated with this node. */
779-
Ssa::PhiNode getPhiNode() { result = phi }
780-
781-
/** Gets the basic block in which this input originates. */
782-
IRBlock getBlock() { result = block }
783-
784-
override DataFlowCallable getEnclosingCallable() {
785-
result.asSourceCallable() = this.getFunction()
786-
}
787-
788-
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
789-
790-
override DataFlowType getType() { result = this.getSourceVariable().getType() }
791-
792-
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
793-
794-
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
795-
796-
override string toStringImpl() { result = "Phi input" }
797-
798-
/** Gets the source variable underlying this phi node. */
799-
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
718+
cached
719+
predicate flowsToBackEdge(Node n) {
720+
exists(Node succ, IRBlock bb1, IRBlock bb2 |
721+
Ssa::ssaFlow(n, succ) and
722+
bb1 = n.getBasicBlock() and
723+
bb2 = succ.getBasicBlock() and
724+
bb1 != bb2 and
725+
bb2.dominates(bb1) and
726+
bb1.getASuccessor+() = bb2
727+
)
800728
}
801729

802730
/**
@@ -1374,7 +1302,7 @@ class UninitializedNode extends Node {
13741302
exists(Ssa::Definition def, Ssa::SourceVariable sv |
13751303
def.getIndirectionIndex() = 0 and
13761304
def.getValue().asInstruction() instanceof UninitializedInstruction and
1377-
Ssa::defToNode(this, def, sv, _, _, _) and
1305+
Ssa::defToNode(this, def, sv) and
13781306
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
13791307
)
13801308
}
@@ -1887,15 +1815,9 @@ private module Cached {
18871815
cached
18881816
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
18891817
(
1890-
// Post update node -> Node flow
1891-
Ssa::postUpdateFlow(nodeFrom, nodeTo)
1892-
or
18931818
// Def-use/Use-use flow
18941819
Ssa::ssaFlow(nodeFrom, nodeTo)
18951820
or
1896-
// Phi input -> Phi
1897-
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
1898-
or
18991821
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
19001822
or
19011823
// Operand -> Instruction flow
@@ -1910,9 +1832,6 @@ private module Cached {
19101832
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
19111833
)
19121834
or
1913-
// Phi node -> Node flow
1914-
Ssa::fromPhiNode(nodeFrom, nodeTo)
1915-
or
19161835
// Indirect operand -> (indirect) instruction flow
19171836
indirectionOperandFlow(nodeFrom, nodeTo)
19181837
or
@@ -2356,22 +2275,6 @@ class ContentSet instanceof Content {
23562275
}
23572276
}
23582277

2359-
pragma[nomagic]
2360-
private predicate guardControlsPhiInput(
2361-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2362-
) {
2363-
phi.hasInputFromBlock(def, _, _, _, input) and
2364-
(
2365-
g.controls(input, branch)
2366-
or
2367-
exists(EdgeKind kind |
2368-
g.getBlock() = input and
2369-
kind = getConditionalEdge(branch) and
2370-
input.getSuccessor(kind) = phi.getBasicBlock()
2371-
)
2372-
)
2373-
}
2374-
23752278
/**
23762279
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
23772280
*
@@ -2403,6 +2306,10 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24032306
)
24042307
}
24052308

2309+
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
2310+
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch)
2311+
}
2312+
24062313
/**
24072314
* Gets an expression node that is safely guarded by the given guard check.
24082315
*
@@ -2443,14 +2350,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24432350
controls(g, result, edge)
24442351
)
24452352
or
2446-
exists(
2447-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2448-
|
2449-
guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and
2450-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2451-
pragma[only_bind_into](phi)) and
2452-
result = TSsaPhiInputNode(phi, input)
2453-
)
2353+
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
24542354
}
24552355

24562356
/**
@@ -2499,6 +2399,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24992399
)
25002400
}
25012401

2402+
private predicate guardChecksIndirectNode(
2403+
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
2404+
) {
2405+
guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
2406+
branch)
2407+
}
2408+
25022409
/**
25032410
* Gets an indirect expression node with indirection index `indirectionIndex` that is
25042411
* safely guarded by the given guard check.
@@ -2541,16 +2448,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
25412448
controls(g, result, edge)
25422449
)
25432450
or
2544-
exists(
2545-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2546-
|
2547-
guardChecks(g,
2548-
def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
2549-
branch) and
2550-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2551-
pragma[only_bind_into](phi)) and
2552-
result = TSsaPhiInputNode(phi, input)
2553-
)
2451+
result =
2452+
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
25542453
}
25552454
}
25562455

@@ -2559,14 +2458,6 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
25592458
*/
25602459
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
25612460

2562-
private EdgeKind getConditionalEdge(boolean branch) {
2563-
branch = true and
2564-
result instanceof TrueEdge
2565-
or
2566-
branch = false and
2567-
result instanceof FalseEdge
2568-
}
2569-
25702461
/**
25712462
* Provides a set of barrier nodes for a guard that validates an instruction.
25722463
*
@@ -2583,6 +2474,10 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25832474
)
25842475
}
25852476

2477+
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
2478+
instructionGuardChecks(g, n.asOperand().getDef(), branch)
2479+
}
2480+
25862481
/** Gets a node that is safely guarded by the given guard check. */
25872482
Node getABarrierNode() {
25882483
exists(IRGuardCondition g, ValueNumber value, boolean edge |
@@ -2591,14 +2486,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25912486
controls(g, result, edge)
25922487
)
25932488
or
2594-
exists(
2595-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2596-
|
2597-
instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and
2598-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2599-
pragma[only_bind_into](phi)) and
2600-
result = TSsaPhiInputNode(phi, input)
2601-
)
2489+
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
26022490
}
26032491

26042492
bindingset[value, n]
@@ -2610,6 +2498,12 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
26102498
)
26112499
}
26122500

2501+
private predicate guardChecksIndirectNode(
2502+
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
2503+
) {
2504+
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch)
2505+
}
2506+
26132507
/**
26142508
* Gets an indirect node with indirection index `indirectionIndex` that is
26152509
* safely guarded by the given guard check.
@@ -2621,14 +2515,8 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
26212515
controls(g, result, edge)
26222516
)
26232517
or
2624-
exists(
2625-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2626-
|
2627-
instructionGuardChecks(g, def.getARead().asIndirectOperand(indirectionIndex).getDef(), branch) and
2628-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2629-
pragma[only_bind_into](phi)) and
2630-
result = TSsaPhiInputNode(phi, input)
2631-
)
2518+
result =
2519+
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
26322520
}
26332521
}
26342522

0 commit comments

Comments
 (0)