Skip to content

Commit d15e388

Browse files
committed
C++: Get rid of the case range constant value with and instead implement 'rangeGuard'.
1 parent 13cde4d commit d15e388

File tree

4 files changed

+63
-65
lines changed

4 files changed

+63
-65
lines changed

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

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -125,41 +125,16 @@ module GuardsInput implements SharedGuards::InputSig<Cpp::Location, Instruction,
125125
// In order to have an "integer constant" for a switch case
126126
// we misuse the first instruction (which is always a NoOp instruction)
127127
// as a constant with the switch case's value.
128-
exists(CaseEdge edge |
129-
this = any(SwitchInstruction switch).getSuccessor(edge) and
130-
value = edge.getValue().toInt()
128+
exists(CaseEdge edge | this = any(SwitchInstruction switch).getSuccessor(edge) |
129+
value = edge.getMaxValue().toInt()
130+
or
131+
value = edge.getMinValue().toInt()
131132
)
132133
}
133134

134135
override int asIntegerValue() { result = value }
135136
}
136137

137-
/**
138-
* The instruction representing the constant expression in a case statement.
139-
*
140-
* Since the IR does not have an instruction for this (as this is represented
141-
* by the edge) we use the `NoOp` instruction which is always generated.
142-
*/
143-
private class CaseConstant extends ConstantExpr instanceof NoOpInstruction {
144-
SwitchInstruction switch;
145-
SwitchEdge edge;
146-
147-
CaseConstant() { this = switch.getSuccessor(edge) }
148-
149-
override ConstantValue asConstantValue() {
150-
exists(string minValue, string maxValue |
151-
edge.getMinValue() = minValue and
152-
edge.getMaxValue() = maxValue and
153-
result.isRange(minValue, maxValue)
154-
)
155-
}
156-
157-
predicate hasEdge(SwitchInstruction switch_, SwitchEdge edge_) {
158-
switch_ = switch and
159-
edge_ = edge
160-
}
161-
}
162-
163138
private predicate nonNullExpr(Instruction i) {
164139
i instanceof VariableAddressInstruction
165140
or
@@ -234,7 +209,12 @@ module GuardsInput implements SharedGuards::InputSig<Cpp::Location, Instruction,
234209
/**
235210
* Gets the constant expression of this case.
236211
*/
237-
ConstantExpr asConstantCase() { result.(CaseConstant).hasEdge(switch, edge) }
212+
ConstantExpr asConstantCase() {
213+
// Note: This only has a value if there is a unique value for the case.
214+
// So the will not be a result when using the GCC case range extension.
215+
// Instead, we model these using the `LogicInput_v1::rangeGuard` predicate.
216+
result.asIntegerValue() = this.getEdge().getValue().toInt()
217+
}
238218
}
239219

240220
abstract private class BinExpr extends Expr instanceof BinaryInstruction {
@@ -446,6 +426,23 @@ private module LogicInput_v1 implements GuardsImpl::LogicInputSig {
446426
g1.(ConditionalBranchInstruction).getCondition() = g2 and
447427
v1.asBooleanValue() = v2.asBooleanValue()
448428
}
429+
430+
predicate rangeGuard(
431+
GuardsImpl::PreGuard guard, GuardValue val, GuardsInput::Expr e, int k, boolean upper
432+
) {
433+
exists(SwitchInstruction switch, string minValue, string maxValue |
434+
switch.getSuccessor(EdgeKind::caseEdge(minValue, maxValue)) = guard and
435+
e = switch.getExpression() and
436+
minValue != maxValue and
437+
val.asBooleanValue() = true
438+
|
439+
upper = false and
440+
k = minValue.toInt()
441+
or
442+
upper = true and
443+
k = maxValue.toInt()
444+
)
445+
}
449446
}
450447

451448
class GuardValue = GuardsImpl::GuardValue;
@@ -1707,15 +1704,16 @@ private module Cached {
17071704
exists(string minValue, string maxValue |
17081705
test.getExpressionOperand() = op and
17091706
exists(test.getSuccessor(EdgeKind::caseEdge(minValue, maxValue))) and
1710-
value.asConstantValue().isRange(minValue, maxValue) and
17111707
minValue < maxValue
17121708
|
17131709
// op <= k => op < k - 1
17141710
isLt = true and
1715-
maxValue.toInt() = k - 1
1711+
maxValue.toInt() = k - 1 and
1712+
value.isIntRange(k - 1, true)
17161713
or
17171714
isLt = false and
1718-
minValue.toInt() = k
1715+
minValue.toInt() = k and
1716+
value.isIntRange(k, false)
17191717
)
17201718
}
17211719

cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -490,22 +490,22 @@
490490
| test.cpp:69:12:69:12 | i | i == 0 when i is 0 |
491491
| test.cpp:69:12:69:12 | i | i == 1 when i is 1 |
492492
| test.cpp:69:12:69:12 | i | i == 2 when i is 2 |
493-
| test.cpp:73:30:73:30 | i | i < 11 when i is 0..10 |
494-
| test.cpp:73:30:73:30 | i | i < 21 when i is 11..20 |
495-
| test.cpp:73:30:73:30 | i | i >= 0 when i is 0..10 |
496-
| test.cpp:73:30:73:30 | i | i >= 11 when i is 11..20 |
497-
| test.cpp:74:10:74:10 | i | i < 11 when i is 0..10 |
498-
| test.cpp:74:10:74:10 | i | i < 21 when i is 11..20 |
499-
| test.cpp:74:10:74:10 | i | i >= 0 when i is 0..10 |
500-
| test.cpp:74:10:74:10 | i | i >= 11 when i is 11..20 |
501-
| test.cpp:76:12:76:12 | i | i < 11 when i is 0..10 |
502-
| test.cpp:76:12:76:12 | i | i < 21 when i is 11..20 |
503-
| test.cpp:76:12:76:12 | i | i >= 0 when i is 0..10 |
504-
| test.cpp:76:12:76:12 | i | i >= 11 when i is 11..20 |
505-
| test.cpp:79:12:79:12 | i | i < 11 when i is 0..10 |
506-
| test.cpp:79:12:79:12 | i | i < 21 when i is 11..20 |
507-
| test.cpp:79:12:79:12 | i | i >= 0 when i is 0..10 |
508-
| test.cpp:79:12:79:12 | i | i >= 11 when i is 11..20 |
493+
| test.cpp:73:30:73:30 | i | i < 11 when i is Upper bound 10 |
494+
| test.cpp:73:30:73:30 | i | i < 21 when i is Upper bound 20 |
495+
| test.cpp:73:30:73:30 | i | i >= 0 when i is Lower bound 0 |
496+
| test.cpp:73:30:73:30 | i | i >= 11 when i is Lower bound 11 |
497+
| test.cpp:74:10:74:10 | i | i < 11 when i is Upper bound 10 |
498+
| test.cpp:74:10:74:10 | i | i < 21 when i is Upper bound 20 |
499+
| test.cpp:74:10:74:10 | i | i >= 0 when i is Lower bound 0 |
500+
| test.cpp:74:10:74:10 | i | i >= 11 when i is Lower bound 11 |
501+
| test.cpp:76:12:76:12 | i | i < 11 when i is Upper bound 10 |
502+
| test.cpp:76:12:76:12 | i | i < 21 when i is Upper bound 20 |
503+
| test.cpp:76:12:76:12 | i | i >= 0 when i is Lower bound 0 |
504+
| test.cpp:76:12:76:12 | i | i >= 11 when i is Lower bound 11 |
505+
| test.cpp:79:12:79:12 | i | i < 11 when i is Upper bound 10 |
506+
| test.cpp:79:12:79:12 | i | i < 21 when i is Upper bound 20 |
507+
| test.cpp:79:12:79:12 | i | i >= 0 when i is Lower bound 0 |
508+
| test.cpp:79:12:79:12 | i | i >= 11 when i is Lower bound 11 |
509509
| test.cpp:93:6:93:6 | c | c != 0 when c is true |
510510
| test.cpp:93:6:93:6 | c | c != 1 when c is false |
511511
| test.cpp:93:6:93:6 | c | c == 0 when c is false |
@@ -1304,7 +1304,7 @@
13041304
| test.cpp:330:7:330:7 | b | b != 1 when b is false |
13051305
| test.cpp:330:7:330:7 | b | b == 0 when b is false |
13061306
| test.cpp:330:7:330:7 | b | b == 1 when b is true |
1307-
| test.cpp:334:11:334:11 | x | x < 51 when x is 40..50 |
1308-
| test.cpp:334:11:334:11 | x | x >= 40 when x is 40..50 |
1309-
| test.cpp:338:9:338:9 | x | x < 51 when x is 40..50 |
1310-
| test.cpp:338:9:338:9 | x | x >= 40 when x is 40..50 |
1307+
| test.cpp:334:11:334:11 | x | x < 51 when x is Upper bound 50 |
1308+
| test.cpp:334:11:334:11 | x | x >= 40 when x is Lower bound 40 |
1309+
| test.cpp:338:9:338:9 | x | x < 51 when x is Upper bound 50 |
1310+
| test.cpp:338:9:338:9 | x | x >= 40 when x is Lower bound 40 |

cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,18 @@
178178
| test.cpp:42:13:42:20 | call to getABool | true | test.cpp:43:9:45:23 | { ... } |
179179
| test.cpp:60:31:60:31 | i | 0 | test.cpp:62:5:64:12 | case ...: |
180180
| test.cpp:60:31:60:31 | i | 1 | test.cpp:65:5:66:10 | case ...: |
181+
| test.cpp:60:31:60:31 | i | 10 | test.cpp:62:5:64:12 | case ...: |
181182
| test.cpp:61:10:61:10 | i | 0 | test.cpp:62:5:64:12 | case ...: |
182183
| test.cpp:61:10:61:10 | i | 1 | test.cpp:65:5:66:10 | case ...: |
183-
| test.cpp:73:30:73:30 | i | 0..10 | test.cpp:75:5:77:12 | case ...: |
184-
| test.cpp:73:30:73:30 | i | 11..20 | test.cpp:78:5:79:10 | case ...: |
185-
| test.cpp:74:10:74:10 | i | 0..10 | test.cpp:75:5:77:12 | case ...: |
186-
| test.cpp:74:10:74:10 | i | 11..20 | test.cpp:78:5:79:10 | case ...: |
184+
| test.cpp:61:10:61:10 | i | 10 | test.cpp:62:5:64:12 | case ...: |
185+
| test.cpp:73:30:73:30 | i | Lower bound 0 | test.cpp:75:5:77:12 | case ...: |
186+
| test.cpp:73:30:73:30 | i | Lower bound 11 | test.cpp:78:5:79:10 | case ...: |
187+
| test.cpp:73:30:73:30 | i | Upper bound 10 | test.cpp:75:5:77:12 | case ...: |
188+
| test.cpp:73:30:73:30 | i | Upper bound 20 | test.cpp:78:5:79:10 | case ...: |
189+
| test.cpp:74:10:74:10 | i | Lower bound 0 | test.cpp:75:5:77:12 | case ...: |
190+
| test.cpp:74:10:74:10 | i | Lower bound 11 | test.cpp:78:5:79:10 | case ...: |
191+
| test.cpp:74:10:74:10 | i | Upper bound 10 | test.cpp:75:5:77:12 | case ...: |
192+
| test.cpp:74:10:74:10 | i | Upper bound 20 | test.cpp:78:5:79:10 | case ...: |
187193
| test.cpp:92:31:92:31 | c | not null | test.cpp:93:9:94:7 | { ... } |
188194
| test.cpp:93:6:93:6 | c | not null | test.cpp:93:9:94:7 | { ... } |
189195
| test.cpp:93:6:93:6 | c | true | test.cpp:93:9:94:7 | { ... } |
@@ -328,9 +334,7 @@
328334
| test.cpp:318:6:318:18 | ... != ... | true | test.cpp:318:21:320:3 | { ... } |
329335
| test.cpp:318:7:318:12 | ... < ... | 0 | test.cpp:320:10:322:3 | { ... } |
330336
| test.cpp:318:7:318:12 | ... < ... | not 0 | test.cpp:318:21:320:3 | { ... } |
331-
| test.cpp:327:46:327:46 | b | false | test.cpp:336:3:338:7 | case ...: |
332337
| test.cpp:327:46:327:46 | b | true | test.cpp:331:3:332:10 | { ... } |
333-
| test.cpp:329:11:329:13 | call to foo | 40..50 | test.cpp:336:3:338:7 | case ...: |
334-
| test.cpp:330:7:330:7 | b | false | test.cpp:336:3:338:7 | case ...: |
335338
| test.cpp:330:7:330:7 | b | true | test.cpp:331:3:332:10 | { ... } |
336-
| test.cpp:334:11:334:11 | x | 40..50 | test.cpp:336:3:338:7 | case ...: |
339+
| test.cpp:334:11:334:11 | x | Lower bound 40 | test.cpp:336:3:338:7 | case ...: |
340+
| test.cpp:334:11:334:11 | x | Upper bound 50 | test.cpp:336:3:338:7 | case ...: |

cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,12 +1295,8 @@ unary
12951295
| test.cpp:318:6:318:18 | ... != ... | test.cpp:318:7:318:12 | ... < ... | != | 0 | test.cpp:318:21:320:3 | { ... } |
12961296
| test.cpp:318:6:318:18 | ... != ... | test.cpp:318:7:318:12 | ... < ... | == | 0 | test.cpp:320:10:322:3 | { ... } |
12971297
| test.cpp:327:46:327:46 | b | test.cpp:330:7:330:7 | b | != | 0 | test.cpp:331:3:332:10 | { ... } |
1298-
| test.cpp:327:46:327:46 | b | test.cpp:330:7:330:7 | b | != | 1 | test.cpp:336:3:338:7 | case ...: |
1299-
| test.cpp:327:46:327:46 | b | test.cpp:330:7:330:7 | b | == | 0 | test.cpp:336:3:338:7 | case ...: |
13001298
| test.cpp:327:46:327:46 | b | test.cpp:330:7:330:7 | b | == | 1 | test.cpp:331:3:332:10 | { ... } |
13011299
| test.cpp:330:7:330:7 | b | test.cpp:330:7:330:7 | b | != | 0 | test.cpp:331:3:332:10 | { ... } |
1302-
| test.cpp:330:7:330:7 | b | test.cpp:330:7:330:7 | b | != | 1 | test.cpp:336:3:338:7 | case ...: |
1303-
| test.cpp:330:7:330:7 | b | test.cpp:330:7:330:7 | b | == | 0 | test.cpp:336:3:338:7 | case ...: |
13041300
| test.cpp:330:7:330:7 | b | test.cpp:330:7:330:7 | b | == | 1 | test.cpp:331:3:332:10 | { ... } |
13051301
| test.cpp:334:11:334:11 | x | test.cpp:334:11:334:11 | x | < | 51 | test.cpp:336:3:338:7 | case ...: |
13061302
| test.cpp:334:11:334:11 | x | test.cpp:334:11:334:11 | x | >= | 40 | test.cpp:336:3:338:7 | case ...: |

0 commit comments

Comments
 (0)