Skip to content

Commit 85d0efc

Browse files
committed
C++: Make the last use of a node before entering the phi node map to a phi input dataflow node.
1 parent d020f93 commit 85d0efc

File tree

1 file changed

+96
-47
lines changed

1 file changed

+96
-47
lines changed

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

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -657,19 +657,9 @@ class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
657657
*/
658658
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
659659
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
660-
or
661-
exists(PhiNode phi |
662-
lastRefRedefExt(_, sv, bb1, i1, phi) and
663-
phi.definesAt(sv, bb2, i2, _)
664-
)
665660
}
666661

667662
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
668-
exists(Phi phi |
669-
phi.asPhi().definesAt(sv, bb, i, _) and
670-
nodeTo = phi.getNode()
671-
)
672-
or
673663
exists(UseImpl use |
674664
use.hasIndexInBlock(bb, i, sv) and
675665
nodeTo = use.getNode()
@@ -735,25 +725,14 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
735725
}
736726

737727
/**
738-
* The reason for this predicate is a bit annoying:
739-
* We cannot mark a `PointerArithmeticInstruction` that computes an offset based on some SSA
740-
* variable `x` as a use of `x` since this creates taint-flow in the following example:
741-
* ```c
742-
* int x = array[source]
743-
* sink(*array)
744-
* ```
745-
* This is because `source` would flow from the operand of `PointerArithmeticInstruction` to the
746-
* result of the instruction, and into the `IndirectOperand` that represents the value of `*array`.
747-
* Then, via use-use flow, flow will arrive at `*array` in `sink(*array)`.
748-
*
749-
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
750-
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
728+
* Holds if `node` is a phi input node that should receive flow from the
729+
* definition to (or use of) `sv` at `(bb1, i1)`.
751730
*/
752-
private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
753-
exists(IRBlock bb1, int i1, Node adjusted |
754-
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
755-
nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
756-
adjacentDefRead(bb1, i1, sv, bb2, i2)
731+
private predicate phiToNode(SsaPhiInputNode node, SourceVariable sv, IRBlock bb1, int i1) {
732+
exists(PhiNode phi, IRBlock input |
733+
phi.hasInputFromBlock(_, sv, bb1, i1, input) and
734+
node.getPhiNode() = phi and
735+
node.getBlock() = input
757736
)
758737
}
759738

@@ -768,10 +747,14 @@ private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, I
768747
private predicate ssaFlowImpl(
769748
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
770749
) {
771-
exists(IRBlock bb2, int i2 |
772-
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
773-
adjacentDefRead(bb1, i1, sv, bb2, i2) and
774-
useToNode(bb2, i2, sv, nodeTo)
750+
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
751+
(
752+
exists(IRBlock bb2, int i2 |
753+
adjacentDefRead(bb1, i1, sv, bb2, i2) and
754+
useToNode(bb2, i2, sv, nodeTo)
755+
)
756+
or
757+
phiToNode(nodeTo, sv, bb1, i1)
775758
) and
776759
nodeFrom != nodeTo
777760
}
@@ -780,7 +763,7 @@ private predicate ssaFlowImpl(
780763
private Node getAPriorDefinition(DefinitionExt next) {
781764
exists(IRBlock bb, int i, SourceVariable sv |
782765
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
783-
pragma[only_bind_into](i), next) and
766+
pragma[only_bind_into](i), _, next) and
784767
nodeToDefOrUse(result, sv, bb, i, _)
785768
)
786769
}
@@ -887,9 +870,32 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
887870
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
888871
*/
889872
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
890-
exists(SourceVariable sv, IRBlock bb2, int i2 |
891-
adjustForPointerArith(pun, sv, bb2, i2) and
892-
useToNode(bb2, i2, sv, n)
873+
// The reason for this predicate is a bit annoying:
874+
// We cannot mark a `PointerArithmeticInstruction` that computes an offset
875+
// based on some SSA
876+
// variable `x` as a use of `x` since this creates taint-flow in the
877+
// following example:
878+
// ```c
879+
// int x = array[source]
880+
// sink(*array)
881+
// ```
882+
// This is because `source` would flow from the operand of `PointerArithmetic`
883+
// instruction to the result of the instruction, and into the `IndirectOperand`
884+
// that represents the value of `*array`. Then, via use-use flow, flow will
885+
// arrive at `*array` in `sink(*array)`.
886+
// So this predicate recurses back along conversions and `PointerArithmetic`
887+
// instructions to find the first use that has provides use-use flow, and
888+
// uses that target as the target of the `nodeFrom`.
889+
exists(Node adjusted, IRBlock bb1, int i1, SourceVariable sv |
890+
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
891+
useToNode(bb1, i1, sv, adjusted)
892+
|
893+
exists(IRBlock bb2, int i2 |
894+
adjacentDefRead(bb1, i1, sv, bb2, i2) and
895+
useToNode(bb2, i2, sv, n)
896+
)
897+
or
898+
phiToNode(n, sv, bb1, i1)
893899
)
894900
}
895901

@@ -944,11 +950,16 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
944950

945951
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
946952
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
947-
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
953+
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1 |
948954
phi = nodeFrom.getPhiNode() and
949-
phi.definesAt(sv, bb1, i1, _) and
950-
adjacentDefRead(bb1, i1, sv, bb2, i2) and
951-
useToNode(bb2, i2, sv, nodeTo)
955+
phi.definesAt(sv, bb1, i1, _)
956+
|
957+
exists(IRBlock bb2, int i2 |
958+
adjacentDefRead(bb1, i1, sv, bb2, i2) and
959+
useToNode(bb2, i2, sv, nodeTo)
960+
)
961+
or
962+
phiToNode(nodeTo, sv, bb1, i1)
952963
)
953964
}
954965

@@ -1022,12 +1033,16 @@ module SsaCached {
10221033
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
10231034
* `def`. The reference is last because it can reach another write `next`,
10241035
* without passing through another read or write.
1036+
*
1037+
* The path from node `i` in `bb` to `next` goes via basic block `input`,
1038+
* which is either a predecessor of the basic block of `next`, or `input` =
1039+
* `bb` in case `next` occurs in basic block `bb`.
10251040
*/
10261041
cached
10271042
predicate lastRefRedefExt(
1028-
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
1043+
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input, DefinitionExt next
10291044
) {
1030-
SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
1045+
SsaImpl::lastRefRedefExt(def, sv, bb, i, input, next)
10311046
}
10321047

10331048
cached
@@ -1191,7 +1206,7 @@ class Phi extends TPhi, SsaDef {
11911206

11921207
override string toString() { result = phi.toString() }
11931208

1194-
SsaPhiNode getNode() { result.getPhiNode() = phi }
1209+
SsaPhiInputNode getNode(IRBlock block) { result.getPhiNode() = phi and result.getBlock() = block }
11951210

11961211
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlockExt(phi, bb) }
11971212

@@ -1200,6 +1215,23 @@ class Phi extends TPhi, SsaDef {
12001215

12011216
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
12021217

1218+
/**
1219+
* An static single assignment (SSA) definition that is used as an input to a
1220+
* phi or phi-read node.
1221+
*/
1222+
class PhiInputNodeExt extends SsaImpl::DefinitionExt {
1223+
PhiNode phi;
1224+
1225+
PhiInputNodeExt() { this = SsaCached::phiHasInputFromBlockExt(phi, _) }
1226+
1227+
/** Gets the phi or phi-read node that receives this node as input. */
1228+
PhiNode getPhi() { result = phi }
1229+
1230+
predicate hasInputFromBlock(DefinitionExt def, IRBlock input) {
1231+
SsaCached::lastRefRedefExt(def, _, _, _, input, this)
1232+
}
1233+
}
1234+
12031235
/**
12041236
* An static single assignment (SSA) phi node.
12051237
*
@@ -1219,13 +1251,21 @@ class PhiNode extends SsaImpl::DefinitionExt {
12191251
*/
12201252
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
12211253

1222-
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
1223-
predicate hasInputFromBlock(Definition inp, IRBlock bb) {
1224-
inp = SsaCached::phiHasInputFromBlockExt(this, bb)
1254+
/**
1255+
* Holds if the node at index `i` in `bb` is a last reference to SSA
1256+
* definition `def` of `sv`. The reference is last because it can reach
1257+
* this phi node, without passing through another read or write.
1258+
*
1259+
* The path from node `i` in `bb` to this phi node goes via basic block
1260+
* `input`, which is either a predecessor of the basic block of this phi
1261+
* node, or `input` = `bb` in case this phi node occurs in basic block `bb`.
1262+
*/
1263+
predicate hasInputFromBlock(DefinitionExt def, SourceVariable sv, IRBlock bb, int i, IRBlock input) {
1264+
SsaCached::lastRefRedefExt(def, sv, bb, i, input, this)
12251265
}
12261266

12271267
/** Gets a definition that is an input to this phi node. */
1228-
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
1268+
final Definition getAnInput() { this.hasInputFromBlock(result, _, _, _, _) }
12291269
}
12301270

12311271
/** An static single assignment (SSA) definition. */
@@ -1240,6 +1280,15 @@ class DefinitionExt extends SsaImpl::DefinitionExt {
12401280
result = this.getAPhiInputOrPriorDefinition*() and
12411281
not result instanceof PhiNode
12421282
}
1283+
1284+
/** Gets a node that represents a read of this SSA definition. */
1285+
Node getARead() {
1286+
exists(SourceVariable sv, IRBlock bb, int i | SsaCached::ssaDefReachesReadExt(sv, this, bb, i) |
1287+
useToNode(bb, i, sv, result)
1288+
or
1289+
phiToNode(result, sv, bb, i)
1290+
)
1291+
}
12431292
}
12441293

12451294
class Definition = SsaImpl::Definition;

0 commit comments

Comments
 (0)