Skip to content

Commit bb39b8c

Browse files
committed
C++: Use SSA data flow integration module.
1 parent 199f7be commit bb39b8c

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
@@ -620,117 +620,45 @@ class PostFieldUpdateNode extends PostUpdateNodeImpl {
620620
/**
621621
* INTERNAL: do not use.
622622
*
623-
* A phi node produced by the shared SSA library, viewed as a node in a data flow graph.
623+
* A synthesized SSA node produced by the shared SSA library, viewed as a node
624+
* in a data flow graph.
624625
*/
625-
class SsaPhiNode extends Node, TSsaPhiNode {
626-
Ssa::PhiNode phi;
626+
class SsaSynthNode extends Node, TSsaSynthNode {
627+
Ssa::SynthNode node;
627628

628-
SsaPhiNode() { this = TSsaPhiNode(phi) }
629+
SsaSynthNode() { this = TSsaSynthNode(node) }
629630

630-
/** Gets the phi node associated with this node. */
631-
Ssa::PhiNode getPhiNode() { result = phi }
631+
/** Gets the synthesized SSA node associated with this node. */
632+
Ssa::SynthNode getSynthNode() { result = node }
632633

633634
override DataFlowCallable getEnclosingCallable() {
634635
result.asSourceCallable() = this.getFunction()
635636
}
636637

637-
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
638+
override Declaration getFunction() { result = node.getBasicBlock().getEnclosingFunction() }
638639

639-
override DataFlowType getType() {
640-
exists(Ssa::SourceVariable sv |
641-
this.getPhiNode().definesAt(sv, _, _, _) and
642-
result = sv.getType()
643-
)
644-
}
640+
override DataFlowType getType() { result = node.getSourceVariable().getType() }
645641

646-
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
642+
override predicate isGLValue() { node.getSourceVariable().isGLValue() }
647643

648-
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
649-
650-
override string toStringImpl() { result = phi.toString() }
651-
652-
/**
653-
* Gets a node that is used as input to this phi node.
654-
* `fromBackEdge` is true if data flows along a back-edge,
655-
* and `false` otherwise.
656-
*/
657-
cached
658-
final Node getAnInput(boolean fromBackEdge) {
659-
result.(SsaPhiInputNode).getPhiNode() = phi and
660-
exists(IRBlock bPhi, IRBlock bResult |
661-
bPhi = phi.getBasicBlock() and bResult = result.getBasicBlock()
662-
|
663-
if bPhi.dominates(bResult) then fromBackEdge = true else fromBackEdge = false
664-
)
665-
}
666-
667-
/** Gets a node that is used as input to this phi node. */
668-
final Node getAnInput() { result = this.getAnInput(_) }
669-
670-
/** Gets the source variable underlying this phi node. */
671-
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
644+
final override Location getLocationImpl() { result = node.getLocation() }
672645

673-
/**
674-
* Holds if this phi node is a phi-read node.
675-
*
676-
* Phi-read nodes are like normal phi nodes, but they are inserted based
677-
* on reads instead of writes.
678-
*/
679-
predicate isPhiRead() { phi.isPhiRead() }
646+
override string toStringImpl() { result = node.toString() }
680647
}
681648

682649
/**
683-
* INTERNAL: Do not use.
684-
*
685-
* A node that is used as an input to a phi node.
686-
*
687-
* This class exists to allow more powerful barrier guards. Consider this
688-
* example:
689-
*
690-
* ```cpp
691-
* int x = source();
692-
* if(!safe(x)) {
693-
* x = clear();
694-
* }
695-
* // phi node for x here
696-
* sink(x);
697-
* ```
698-
*
699-
* At the phi node for `x` it is neither the case that `x` is dominated by
700-
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
701-
*
702-
* By inserting a "phi input" node as the last entry in the basic block that
703-
* defines the inputs to the phi we can conclude that each of those inputs are
704-
* safe to pass to `sink`.
650+
* Holds if `n` has a local flow step that goes through a back-edge.
705651
*/
706-
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
707-
Ssa::PhiNode phi;
708-
IRBlock block;
709-
710-
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
711-
712-
/** Gets the phi node associated with this node. */
713-
Ssa::PhiNode getPhiNode() { result = phi }
714-
715-
/** Gets the basic block in which this input originates. */
716-
IRBlock getBlock() { result = block }
717-
718-
override DataFlowCallable getEnclosingCallable() {
719-
result.asSourceCallable() = this.getFunction()
720-
}
721-
722-
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
723-
724-
override DataFlowType getType() { result = this.getSourceVariable().getType() }
725-
726-
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
727-
728-
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
729-
730-
override string toStringImpl() { result = "Phi input" }
731-
732-
/** Gets the source variable underlying this phi node. */
733-
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
652+
cached
653+
predicate flowsToBackEdge(Node n) {
654+
exists(Node succ, IRBlock bb1, IRBlock bb2 |
655+
Ssa::ssaFlow(n, succ) and
656+
bb1 = n.getBasicBlock() and
657+
bb2 = succ.getBasicBlock() and
658+
bb1 != bb2 and
659+
bb2.dominates(bb1) and
660+
bb1.getASuccessor+() = bb2
661+
)
734662
}
735663

736664
/**
@@ -1308,7 +1236,7 @@ class UninitializedNode extends Node {
13081236
exists(Ssa::Definition def, Ssa::SourceVariable sv |
13091237
def.getIndirectionIndex() = 0 and
13101238
def.getValue().asInstruction() instanceof UninitializedInstruction and
1311-
Ssa::defToNode(this, def, sv, _, _, _) and
1239+
Ssa::defToNode(this, def, sv) and
13121240
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
13131241
)
13141242
}
@@ -1821,15 +1749,9 @@ private module Cached {
18211749
cached
18221750
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
18231751
(
1824-
// Post update node -> Node flow
1825-
Ssa::postUpdateFlow(nodeFrom, nodeTo)
1826-
or
18271752
// Def-use/Use-use flow
18281753
Ssa::ssaFlow(nodeFrom, nodeTo)
18291754
or
1830-
// Phi input -> Phi
1831-
nodeFrom.(SsaPhiInputNode).getPhiNode() = nodeTo.(SsaPhiNode).getPhiNode()
1832-
or
18331755
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
18341756
or
18351757
// Operand -> Instruction flow
@@ -1844,9 +1766,6 @@ private module Cached {
18441766
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
18451767
)
18461768
or
1847-
// Phi node -> Node flow
1848-
Ssa::fromPhiNode(nodeFrom, nodeTo)
1849-
or
18501769
// Indirect operand -> (indirect) instruction flow
18511770
indirectionOperandFlow(nodeFrom, nodeTo)
18521771
or
@@ -2290,22 +2209,6 @@ class ContentSet instanceof Content {
22902209
}
22912210
}
22922211

2293-
pragma[nomagic]
2294-
private predicate guardControlsPhiInput(
2295-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2296-
) {
2297-
phi.hasInputFromBlock(def, _, _, _, input) and
2298-
(
2299-
g.controls(input, branch)
2300-
or
2301-
exists(EdgeKind kind |
2302-
g.getBlock() = input and
2303-
kind = getConditionalEdge(branch) and
2304-
input.getSuccessor(kind) = phi.getBasicBlock()
2305-
)
2306-
)
2307-
}
2308-
23092212
/**
23102213
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
23112214
*
@@ -2337,6 +2240,10 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
23372240
)
23382241
}
23392242

2243+
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
2244+
guardChecks(g, n.asOperand().getDef().getConvertedResultExpression(), branch)
2245+
}
2246+
23402247
/**
23412248
* Gets an expression node that is safely guarded by the given guard check.
23422249
*
@@ -2377,14 +2284,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
23772284
controls(g, result, edge)
23782285
)
23792286
or
2380-
exists(
2381-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2382-
|
2383-
guardChecks(g, def.getARead().asOperand().getDef().getConvertedResultExpression(), branch) and
2384-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2385-
pragma[only_bind_into](phi)) and
2386-
result = TSsaPhiInputNode(phi, input)
2387-
)
2287+
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
23882288
}
23892289

23902290
/**
@@ -2433,6 +2333,13 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24332333
)
24342334
}
24352335

2336+
private predicate guardChecksIndirectNode(
2337+
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
2338+
) {
2339+
guardChecks(g, n.asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
2340+
branch)
2341+
}
2342+
24362343
/**
24372344
* Gets an indirect expression node with indirection index `indirectionIndex` that is
24382345
* safely guarded by the given guard check.
@@ -2475,16 +2382,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24752382
controls(g, result, edge)
24762383
)
24772384
or
2478-
exists(
2479-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2480-
|
2481-
guardChecks(g,
2482-
def.getARead().asIndirectOperand(indirectionIndex).getDef().getConvertedResultExpression(),
2483-
branch) and
2484-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2485-
pragma[only_bind_into](phi)) and
2486-
result = TSsaPhiInputNode(phi, input)
2487-
)
2385+
result =
2386+
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
24882387
}
24892388
}
24902389

@@ -2493,14 +2392,6 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24932392
*/
24942393
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
24952394

2496-
private EdgeKind getConditionalEdge(boolean branch) {
2497-
branch = true and
2498-
result instanceof TrueEdge
2499-
or
2500-
branch = false and
2501-
result instanceof FalseEdge
2502-
}
2503-
25042395
/**
25052396
* Provides a set of barrier nodes for a guard that validates an instruction.
25062397
*
@@ -2517,6 +2408,10 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25172408
)
25182409
}
25192410

2411+
private predicate guardChecksNode(IRGuardCondition g, Node n, boolean branch) {
2412+
instructionGuardChecks(g, n.asOperand().getDef(), branch)
2413+
}
2414+
25202415
/** Gets a node that is safely guarded by the given guard check. */
25212416
Node getABarrierNode() {
25222417
exists(IRGuardCondition g, ValueNumber value, boolean edge |
@@ -2525,14 +2420,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25252420
controls(g, result, edge)
25262421
)
25272422
or
2528-
exists(
2529-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2530-
|
2531-
instructionGuardChecks(g, def.getARead().asOperand().getDef(), branch) and
2532-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2533-
pragma[only_bind_into](phi)) and
2534-
result = TSsaPhiInputNode(phi, input)
2535-
)
2423+
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
25362424
}
25372425

25382426
bindingset[value, n]
@@ -2544,6 +2432,12 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25442432
)
25452433
}
25462434

2435+
private predicate guardChecksIndirectNode(
2436+
IRGuardCondition g, Node n, boolean branch, int indirectionIndex
2437+
) {
2438+
instructionGuardChecks(g, n.asIndirectOperand(indirectionIndex).getDef(), branch)
2439+
}
2440+
25472441
/**
25482442
* Gets an indirect node with indirection index `indirectionIndex` that is
25492443
* safely guarded by the given guard check.
@@ -2555,14 +2449,8 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25552449
controls(g, result, edge)
25562450
)
25572451
or
2558-
exists(
2559-
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
2560-
|
2561-
instructionGuardChecks(g, def.getARead().asIndirectOperand(indirectionIndex).getDef(), branch) and
2562-
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
2563-
pragma[only_bind_into](phi)) and
2564-
result = TSsaPhiInputNode(phi, input)
2565-
)
2452+
result =
2453+
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
25662454
}
25672455
}
25682456

0 commit comments

Comments
 (0)