Skip to content

Commit afb1129

Browse files
committed
C++: Ensure that postfix crement operations are handled properly in dataflow SSA.
1 parent 57ae1e9 commit afb1129

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,25 @@ abstract private class OperandBasedUse extends UseImpl {
364364
OperandBasedUse() { any() }
365365

366366
final override predicate hasIndexInBlock(IRBlock block, int index) {
367-
operand.getUse() = block.getInstruction(index)
367+
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
368+
// predicate's implementation.
369+
exists(BaseSourceVariableInstruction base | base = this.getBase() |
370+
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
371+
then
372+
exists(Operand op, int indirectionIndex, int indirection |
373+
indirectionIndex = this.getIndirectionIndex() and
374+
indirection = this.getIndirection() and
375+
op =
376+
min(Operand cand, int i |
377+
isUse(_, cand, base, indirection, indirectionIndex) and
378+
block.getInstruction(i) = cand.getUse()
379+
|
380+
cand order by i
381+
) and
382+
block.getInstruction(index) = op.getUse()
383+
)
384+
else operand.getUse() = block.getInstruction(index)
385+
)
368386
}
369387

370388
final Operand getOperand() { result = operand }

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

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,46 @@ abstract private class OperandBasedUse extends UseImpl {
122122
override string toString() { result = operand.toString() }
123123

124124
final override predicate hasIndexInBlock(IRBlock block, int index) {
125-
operand.getUse() = block.getInstruction(index)
125+
// Ideally, this would just be implemented as:
126+
// ```
127+
// operand.getUse() = block.getInstruction(index)
128+
// ```
129+
// but because the IR generated for a snippet such as
130+
// ```
131+
// int x = *p++;
132+
// ```
133+
// looks like
134+
// ```
135+
// r1(glval<int>) = VariableAddress[x] :
136+
// r2(glval<int *>) = VariableAddress[p] :
137+
// r3(int *) = Load[p] : &:r2, m1
138+
// r4(int) = Constant[1] :
139+
// r5(int *) = PointerAdd[4] : r3, r4
140+
// m3(int *) = Store[p] : &:r2, r5
141+
// r6(int *) = CopyValue : r3
142+
// r7(int) = Load[?] : &:r6, ~m2
143+
// m2(int) = Store[x] : &:r1, r7
144+
// ```
145+
// we need to ensure that the `r3` operand of the `CopyValue` instruction isn't seen as a fresh use
146+
// of `p` that happens after the increment. So if the base instruction of this use comes from a
147+
// post-fix crement operation we set the index of the SSA use that wraps the `r3` operand at the
148+
// `CopyValue` instruction to be the same index as the `r3` operand at the `PointerAdd` instruction.
149+
// This ensures that the SSA library doesn't create flow from the `PointerAdd` to `r6`.
150+
exists(BaseSourceVariableInstruction base | base = this.getBase() |
151+
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
152+
then
153+
exists(Operand op |
154+
op =
155+
min(Operand cand, int i |
156+
isUse(_, cand, base, _, _) and
157+
block.getInstruction(i) = cand.getUse()
158+
|
159+
cand order by i
160+
) and
161+
block.getInstruction(index) = op.getUse()
162+
)
163+
else operand.getUse() = block.getInstruction(index)
164+
)
126165
}
127166

128167
final override Cpp::Location getLocation() { result = operand.getLocation() }

0 commit comments

Comments
 (0)