Skip to content

Commit e04c75d

Browse files
committed
C++: Introduce a new phi input dataflow node.
1 parent 888a831 commit e04c75d

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,8 @@ predicate nodeIsHidden(Node n) {
13361336
n instanceof FinalGlobalValue
13371337
or
13381338
n instanceof InitialGlobalValue
1339+
or
1340+
n instanceof SsaPhiInputNode
13391341
}
13401342

13411343
predicate neverSkipInPathGraph(Node n) {
@@ -1634,6 +1636,8 @@ private Instruction getAnInstruction(Node n) {
16341636
or
16351637
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
16361638
or
1639+
result = n.(SsaPhiInputNode).getBasicBlock().getFirstInstruction()
1640+
or
16371641
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
16381642
or
16391643
not n instanceof IndirectInstruction and

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ private newtype TIRDataFlowNode =
4545
or
4646
Ssa::isModifiableByCall(operand, indirectionIndex)
4747
} or
48+
TSsaPhiInputNode(Ssa::PhiNode phi, IRBlock input) { phi.hasInputFromBlock(_, _, _, _, input) } or
4849
TSsaPhiNode(Ssa::PhiNode phi) or
4950
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
5051
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
@@ -170,6 +171,9 @@ class Node extends TIRDataFlowNode {
170171
or
171172
this.(SsaPhiNode).getPhiNode().getBasicBlock() = block and i = -1
172173
or
174+
this.(SsaPhiInputNode).getBlock() = block and
175+
i = block.getInstructionCount()
176+
or
173177
this.(RawIndirectOperand).getOperand().getUse() = block.getInstruction(i)
174178
or
175179
this.(RawIndirectInstruction).getInstruction() = block.getInstruction(i)
@@ -654,6 +658,58 @@ class SsaPhiNode extends Node, TSsaPhiNode {
654658
predicate isPhiRead() { phi.isPhiRead() }
655659
}
656660

661+
/**
662+
* INTERNAL: Do not use.
663+
*
664+
* A note that is used as an input to a phi node.
665+
*
666+
* This class exists to allow more powerful barrier guards. Consider this
667+
* example:
668+
*
669+
* ```cpp
670+
* int x = source();
671+
* if(!safe(x)) {
672+
* x = clear();
673+
* }
674+
* // phi node for x here
675+
* sink(x);
676+
* ```
677+
*
678+
* At the phi node for `x` it is neither the case that `x` is dominated by
679+
* `safe(x)`, or is the case that the phi is dominated by a clearing of `x`.
680+
*
681+
* However, by inserting an "phi input" nodes as the last entry in the basic
682+
* block that defines the inputs to the phi we can conclude that each of those
683+
* inputs are safe to pass to `sink`.
684+
*/
685+
class SsaPhiInputNode extends Node, TSsaPhiInputNode {
686+
Ssa::PhiNode phi;
687+
IRBlock block;
688+
689+
SsaPhiInputNode() { this = TSsaPhiInputNode(phi, block) }
690+
691+
/** Gets the phi node associated with this node. */
692+
Ssa::PhiNode getPhiNode() { result = phi }
693+
694+
/** Gets the basic block in which this input originates. */
695+
IRBlock getBlock() { result = block }
696+
697+
override Declaration getEnclosingCallable() { result = this.getFunction() }
698+
699+
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
700+
701+
override DataFlowType getType() { result = this.getSourceVariable().getType() }
702+
703+
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
704+
705+
final override Location getLocationImpl() { result = block.getLastInstruction().getLocation() }
706+
707+
override string toStringImpl() { result = "Phi input" }
708+
709+
/** Gets the source variable underlying this phi node. */
710+
Ssa::SourceVariable getSourceVariable() { result = phi.getSourceVariable() }
711+
}
712+
657713
/**
658714
* INTERNAL: do not use.
659715
*

0 commit comments

Comments
 (0)