Skip to content

Commit 34decd3

Browse files
committed
C++: Add more general public predicates to work with abstract values.
1 parent f4eb5f5 commit 34decd3

File tree

1 file changed

+50
-20
lines changed

1 file changed

+50
-20
lines changed

cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ class GuardCondition extends Expr {
7272
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
7373
}
7474

75+
/**
76+
* Holds if this condition controls `controlled`, meaning that `controlled` is only
77+
* entered if the value of this condition is `v`.
78+
*
79+
* For details on what "controls" mean, see the QLDoc for `controls`.
80+
*/
81+
cached
82+
predicate valueControls(BasicBlock controlled, AbstractValue v) { none() }
83+
7584
/**
7685
* Holds if this condition controls `controlled`, meaning that `controlled` is only
7786
* entered if the value of this condition is `testIsTrue`.
@@ -99,7 +108,9 @@ class GuardCondition extends Expr {
99108
* true (for `&&`) or false (for `||`) branch.
100109
*/
101110
cached
102-
predicate controls(BasicBlock controlled, boolean testIsTrue) { none() }
111+
final predicate controls(BasicBlock controlled, boolean testIsTrue) {
112+
this.valueControls(controlled, any(BooleanValue bv | bv.getValue() = testIsTrue))
113+
}
103114

104115
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
105116
cached
@@ -136,13 +147,13 @@ private class GuardConditionFromBinaryLogicalOperator extends GuardCondition {
136147
this.(BinaryLogicalOperation).getAnOperand() instanceof GuardCondition
137148
}
138149

139-
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
150+
override predicate valueControls(BasicBlock controlled, AbstractValue v) {
140151
exists(BinaryLogicalOperation binop, GuardCondition lhs, GuardCondition rhs |
141152
this = binop and
142153
lhs = binop.getLeftOperand() and
143154
rhs = binop.getRightOperand() and
144-
lhs.controls(controlled, testIsTrue) and
145-
rhs.controls(controlled, testIsTrue)
155+
lhs.valueControls(controlled, v) and
156+
rhs.valueControls(controlled, v)
146157
)
147158
}
148159

@@ -184,10 +195,10 @@ private class GuardConditionFromIR extends GuardCondition {
184195

185196
GuardConditionFromIR() { this = ir.getUnconvertedResultExpression() }
186197

187-
override predicate controls(BasicBlock controlled, boolean testIsTrue) {
198+
override predicate valueControls(BasicBlock controlled, AbstractValue v) {
188199
// This condition must determine the flow of control; that is, this
189200
// node must be a top-level condition.
190-
this.controlsBlock(controlled, testIsTrue)
201+
this.controlsBlock(controlled, v)
191202
}
192203

193204
/** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
@@ -240,9 +251,9 @@ private class GuardConditionFromIR extends GuardCondition {
240251
* predicate does not necessarily hold for binary logical operations like
241252
* `&&` and `||`. See the detailed explanation on predicate `controls`.
242253
*/
243-
private predicate controlsBlock(BasicBlock controlled, boolean testIsTrue) {
254+
private predicate controlsBlock(BasicBlock controlled, AbstractValue v) {
244255
exists(IRBlock irb |
245-
ir.controls(irb, testIsTrue) and
256+
ir.valueControls(irb, v) and
246257
nonExcludedIRAndBasicBlock(irb, controlled) and
247258
not isUnreachedBlock(irb)
248259
)
@@ -319,29 +330,48 @@ class IRGuardCondition extends Instruction {
319330
* true (for `&&`) or false (for `||`) branch.
320331
*/
321332
cached
322-
predicate controls(IRBlock controlled, boolean testIsTrue) {
333+
predicate valueControls(IRBlock controlled, AbstractValue v) {
323334
// This condition must determine the flow of control; that is, this
324335
// node must be a top-level condition.
325-
this.controlsBlock(controlled, testIsTrue)
336+
this.controlsBlock(controlled, v)
326337
or
327338
exists(IRGuardCondition ne |
328339
this = ne.(LogicalNotInstruction).getUnary() and
329-
ne.controls(controlled, testIsTrue.booleanNot())
340+
ne.valueControls(controlled, v.getDualValue())
330341
)
331342
}
332343

344+
cached
345+
predicate controls(IRBlock controlled, boolean testIsTrue) {
346+
this.valueControls(controlled, any(BooleanValue bv | bv.getValue() = testIsTrue))
347+
}
348+
333349
/**
334350
* Holds if the control-flow edge `(pred, succ)` may be taken only if
335-
* the value of this condition is `testIsTrue`.
351+
* the value of this condition is `v`.
336352
*/
337353
cached
338-
predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) {
354+
predicate valueControlsEdge(IRBlock pred, IRBlock succ, AbstractValue v) {
339355
pred.getASuccessor() = succ and
340-
this.controls(pred, testIsTrue)
356+
this.valueControls(pred, v)
341357
or
342-
succ = this.getBranchSuccessor(testIsTrue) and
343-
branch.(ConditionalBranchInstruction).getCondition() = this and
344-
branch.getBlock() = pred
358+
succ = this.getBranchSuccessor(v) and
359+
(
360+
branch.(ConditionalBranchInstruction).getCondition() = this and
361+
branch.getBlock() = pred
362+
or
363+
branch.(SwitchInstruction).getExpression() = this and
364+
branch.getBlock() = pred
365+
)
366+
}
367+
368+
/**
369+
* Holds if the control-flow edge `(pred, succ)` may be taken only if
370+
* the value of this condition is `testIsTrue`.
371+
*/
372+
cached
373+
final predicate controlsEdge(IRBlock pred, IRBlock succ, boolean testIsTrue) {
374+
this.valueControlsEdge(pred, succ, any(BooleanValue bv | bv.getValue() = testIsTrue))
345375
}
346376

347377
/**
@@ -440,11 +470,11 @@ class IRGuardCondition extends Instruction {
440470

441471
/**
442472
* Holds if this condition controls `block`, meaning that `block` is only
443-
* entered if the value of this condition is `testIsTrue`. This helper
473+
* entered if the value of this condition is `v`. This helper
444474
* predicate does not necessarily hold for binary logical operations like
445475
* `&&` and `||`. See the detailed explanation on predicate `controls`.
446476
*/
447-
private predicate controlsBlock(IRBlock controlled, boolean testIsTrue) {
477+
private predicate controlsBlock(IRBlock controlled, AbstractValue v) {
448478
not isUnreachedBlock(controlled) and
449479
//
450480
// For this block to control the block `controlled` with `testIsTrue` the
@@ -485,7 +515,7 @@ class IRGuardCondition extends Instruction {
485515
// that `this` strictly dominates `controlled` so that isn't necessary to check
486516
// directly.
487517
exists(IRBlock succ |
488-
succ = this.getBranchSuccessor(testIsTrue) and
518+
succ = this.getBranchSuccessor(v) and
489519
this.hasDominatingEdgeTo(succ) and
490520
succ.dominates(controlled)
491521
)

0 commit comments

Comments
 (0)