@@ -7,371 +7,7 @@ import cpp
7
7
import semmle.code.cpp.controlflow.BasicBlocks
8
8
import semmle.code.cpp.controlflow.SSA
9
9
import semmle.code.cpp.controlflow.Dominance
10
-
11
- /**
12
- * A Boolean condition that guards one or more basic blocks. This includes
13
- * operands of logical operators but not switch statements.
14
- */
15
- class GuardCondition extends Expr {
16
- GuardCondition ( ) { is_condition ( this ) }
17
-
18
- /**
19
- * Holds if this condition controls `block`, meaning that `block` is only
20
- * entered if the value of this condition is `testIsTrue`.
21
- *
22
- * Illustration:
23
- *
24
- * ```
25
- * [ (testIsTrue) ]
26
- * [ this ----------------succ ---- controlled ]
27
- * [ | | ]
28
- * [ (testIsFalse) | ------ ... ]
29
- * [ other ]
30
- * ```
31
- *
32
- * The predicate holds if all paths to `controlled` go via the `testIsTrue`
33
- * edge of the control-flow graph. In other words, the `testIsTrue` edge
34
- * must dominate `controlled`. This means that `controlled` must be
35
- * dominated by both `this` and `succ` (the target of the `testIsTrue`
36
- * edge). It also means that any other edge into `succ` must be a back-edge
37
- * from a node which is dominated by `succ`.
38
- *
39
- * The short-circuit boolean operations have slightly surprising behavior
40
- * here: because the operation itself only dominates one branch (due to
41
- * being short-circuited) then it will only control blocks dominated by the
42
- * true (for `&&`) or false (for `||`) branch.
43
- */
44
- cached
45
- predicate controls ( BasicBlock controlled , boolean testIsTrue ) {
46
- // This condition must determine the flow of control; that is, this
47
- // node must be a top-level condition.
48
- this .controlsBlock ( controlled , testIsTrue )
49
- or
50
- exists ( BinaryLogicalOperation binop , GuardCondition lhs , GuardCondition rhs |
51
- this = binop and
52
- lhs = binop .getLeftOperand ( ) and
53
- rhs = binop .getRightOperand ( ) and
54
- lhs .controls ( controlled , testIsTrue ) and
55
- rhs .controls ( controlled , testIsTrue )
56
- )
57
- or
58
- exists ( GuardCondition ne , GuardCondition operand |
59
- this = operand and
60
- operand = ne .( NotExpr ) .getOperand ( ) and
61
- ne .controls ( controlled , testIsTrue .booleanNot ( ) )
62
- )
63
- }
64
-
65
- /** Holds if (determined by this guard) `left < right + k` evaluates to `isLessThan` if this expression evaluates to `testIsTrue`. */
66
- cached
67
- predicate comparesLt ( Expr left , Expr right , int k , boolean isLessThan , boolean testIsTrue ) {
68
- compares_lt ( this , left , right , k , isLessThan , testIsTrue )
69
- }
70
-
71
- /**
72
- * Holds if (determined by this guard) `left < right + k` must be `isLessThan` in `block`.
73
- * If `isLessThan = false` then this implies `left >= right + k`.
74
- */
75
- cached
76
- predicate ensuresLt ( Expr left , Expr right , int k , BasicBlock block , boolean isLessThan ) {
77
- exists ( boolean testIsTrue |
78
- compares_lt ( this , left , right , k , isLessThan , testIsTrue ) and this .controls ( block , testIsTrue )
79
- )
80
- }
81
-
82
- /** Holds if (determined by this guard) `left == right + k` evaluates to `areEqual` if this expression evaluates to `testIsTrue`. */
83
- cached
84
- predicate comparesEq ( Expr left , Expr right , int k , boolean areEqual , boolean testIsTrue ) {
85
- compares_eq ( this , left , right , k , areEqual , testIsTrue )
86
- }
87
-
88
- /**
89
- * Holds if (determined by this guard) `left == right + k` must be `areEqual` in `block`.
90
- * If `areEqual = false` then this implies `left != right + k`.
91
- */
92
- cached
93
- predicate ensuresEq ( Expr left , Expr right , int k , BasicBlock block , boolean areEqual ) {
94
- exists ( boolean testIsTrue |
95
- compares_eq ( this , left , right , k , areEqual , testIsTrue ) and this .controls ( block , testIsTrue )
96
- )
97
- }
98
-
99
- /**
100
- * Holds if this condition controls `block`, meaning that `block` is only
101
- * entered if the value of this condition is `testIsTrue`. This helper
102
- * predicate does not necessarily hold for binary logical operations like
103
- * `&&` and `||`. See the detailed explanation on predicate `controls`.
104
- */
105
- private predicate controlsBlock ( BasicBlock controlled , boolean testIsTrue ) {
106
- exists ( BasicBlock thisblock | thisblock .contains ( this ) |
107
- exists ( BasicBlock succ |
108
- testIsTrue = true and succ = this .getATrueSuccessor ( )
109
- or
110
- testIsTrue = false and succ = this .getAFalseSuccessor ( )
111
- |
112
- bbDominates ( succ , controlled ) and
113
- forall ( BasicBlock pred | pred .getASuccessor ( ) = succ |
114
- pred = thisblock or bbDominates ( succ , pred ) or not reachable ( pred )
115
- )
116
- )
117
- )
118
- }
119
- }
120
-
121
- private predicate is_condition ( Expr guard ) {
122
- guard .isCondition ( )
123
- or
124
- is_condition ( guard .( BinaryLogicalOperation ) .getAnOperand ( ) )
125
- or
126
- exists ( NotExpr cond | is_condition ( cond ) and cond .getOperand ( ) = guard )
127
- }
128
-
129
- /*
130
- * Simplification of equality expressions:
131
- * Simplify conditions in the source to the canonical form l op r + k.
132
- */
133
-
134
- /**
135
- * Holds if `left == right + k` is `areEqual` given that test is `testIsTrue`.
136
- *
137
- * Beware making mistaken logical implications here relating `areEqual` and `testIsTrue`.
138
- */
139
- private predicate compares_eq (
140
- Expr test , Expr left , Expr right , int k , boolean areEqual , boolean testIsTrue
141
- ) {
142
- /* The simple case where the test *is* the comparison so areEqual = testIsTrue xor eq. */
143
- exists ( boolean eq | simple_comparison_eq ( test , left , right , k , eq ) |
144
- areEqual = true and testIsTrue = eq
145
- or
146
- areEqual = false and testIsTrue = eq .booleanNot ( )
147
- )
148
- or
149
- logical_comparison_eq ( test , left , right , k , areEqual , testIsTrue )
150
- or
151
- /* a == b + k => b == a - k */
152
- exists ( int mk | k = - mk | compares_eq ( test , right , left , mk , areEqual , testIsTrue ) )
153
- or
154
- complex_eq ( test , left , right , k , areEqual , testIsTrue )
155
- or
156
- /* (x is true => (left == right + k)) => (!x is false => (left == right + k)) */
157
- exists ( boolean isFalse | testIsTrue = isFalse .booleanNot ( ) |
158
- compares_eq ( test .( NotExpr ) .getOperand ( ) , left , right , k , areEqual , isFalse )
159
- )
160
- }
161
-
162
- /**
163
- * If `test => part` and `part => left == right + k` then `test => left == right + k`.
164
- * Similarly for the case where `test` is false.
165
- */
166
- private predicate logical_comparison_eq (
167
- BinaryLogicalOperation test , Expr left , Expr right , int k , boolean areEqual , boolean testIsTrue
168
- ) {
169
- exists ( boolean partIsTrue , Expr part | test .impliesValue ( part , partIsTrue , testIsTrue ) |
170
- compares_eq ( part , left , right , k , areEqual , partIsTrue )
171
- )
172
- }
173
-
174
- /** Rearrange various simple comparisons into `left == right + k` form. */
175
- private predicate simple_comparison_eq (
176
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean areEqual
177
- ) {
178
- left = cmp .getLeftOperand ( ) and
179
- cmp .getOperator ( ) = "==" and
180
- right = cmp .getRightOperand ( ) and
181
- k = 0 and
182
- areEqual = true
183
- or
184
- left = cmp .getLeftOperand ( ) and
185
- cmp .getOperator ( ) = "!=" and
186
- right = cmp .getRightOperand ( ) and
187
- k = 0 and
188
- areEqual = false
189
- }
190
-
191
- private predicate complex_eq (
192
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean areEqual , boolean testIsTrue
193
- ) {
194
- sub_eq ( cmp , left , right , k , areEqual , testIsTrue )
195
- or
196
- add_eq ( cmp , left , right , k , areEqual , testIsTrue )
197
- }
198
-
199
- // left - x == right + c => left == right + (c+x)
200
- // left == (right - x) + c => left == right + (c-x)
201
- private predicate sub_eq (
202
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean areEqual , boolean testIsTrue
203
- ) {
204
- exists ( SubExpr lhs , int c , int x |
205
- compares_eq ( cmp , lhs , right , c , areEqual , testIsTrue ) and
206
- left = lhs .getLeftOperand ( ) and
207
- x = int_value ( lhs .getRightOperand ( ) ) and
208
- k = c + x
209
- )
210
- or
211
- exists ( SubExpr rhs , int c , int x |
212
- compares_eq ( cmp , left , rhs , c , areEqual , testIsTrue ) and
213
- right = rhs .getLeftOperand ( ) and
214
- x = int_value ( rhs .getRightOperand ( ) ) and
215
- k = c - x
216
- )
217
- }
218
-
219
- // left + x == right + c => left == right + (c-x)
220
- // left == (right + x) + c => left == right + (c+x)
221
- private predicate add_eq (
222
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean areEqual , boolean testIsTrue
223
- ) {
224
- exists ( AddExpr lhs , int c , int x |
225
- compares_eq ( cmp , lhs , right , c , areEqual , testIsTrue ) and
226
- (
227
- left = lhs .getLeftOperand ( ) and x = int_value ( lhs .getRightOperand ( ) )
228
- or
229
- left = lhs .getRightOperand ( ) and x = int_value ( lhs .getLeftOperand ( ) )
230
- ) and
231
- k = c - x
232
- )
233
- or
234
- exists ( AddExpr rhs , int c , int x |
235
- compares_eq ( cmp , left , rhs , c , areEqual , testIsTrue ) and
236
- (
237
- right = rhs .getLeftOperand ( ) and x = int_value ( rhs .getRightOperand ( ) )
238
- or
239
- right = rhs .getRightOperand ( ) and x = int_value ( rhs .getLeftOperand ( ) )
240
- ) and
241
- k = c + x
242
- )
243
- }
244
-
245
- /*
246
- * Simplification of inequality expressions:
247
- * Simplify conditions in the source to the canonical form l < r + k.
248
- */
249
-
250
- /** Holds if `left < right + k` evaluates to `isLt` given that test is `testIsTrue`. */
251
- private predicate compares_lt (
252
- Expr test , Expr left , Expr right , int k , boolean isLt , boolean testIsTrue
253
- ) {
254
- /* In the simple case, the test is the comparison, so isLt = testIsTrue */
255
- simple_comparison_lt ( test , left , right , k ) and isLt = true and testIsTrue = true
256
- or
257
- simple_comparison_lt ( test , left , right , k ) and isLt = false and testIsTrue = false
258
- or
259
- logical_comparison_lt ( test , left , right , k , isLt , testIsTrue )
260
- or
261
- complex_lt ( test , left , right , k , isLt , testIsTrue )
262
- or
263
- /* (not (left < right + k)) => (left >= right + k) */
264
- exists ( boolean isGe | isLt = isGe .booleanNot ( ) |
265
- compares_ge ( test , left , right , k , isGe , testIsTrue )
266
- )
267
- or
268
- /* (x is true => (left < right + k)) => (!x is false => (left < right + k)) */
269
- exists ( boolean isFalse | testIsTrue = isFalse .booleanNot ( ) |
270
- compares_lt ( test .( NotExpr ) .getOperand ( ) , left , right , k , isLt , isFalse )
271
- )
272
- }
273
-
274
- /** `(a < b + k) => (b > a - k) => (b >= a + (1-k))` */
275
- private predicate compares_ge (
276
- Expr test , Expr left , Expr right , int k , boolean isGe , boolean testIsTrue
277
- ) {
278
- exists ( int onemk | k = 1 - onemk | compares_lt ( test , right , left , onemk , isGe , testIsTrue ) )
279
- }
280
-
281
- /**
282
- * If `test => part` and `part => left < right + k` then `test => left < right + k`.
283
- * Similarly for the case where `test` evaluates false.
284
- */
285
- private predicate logical_comparison_lt (
286
- BinaryLogicalOperation test , Expr left , Expr right , int k , boolean isLt , boolean testIsTrue
287
- ) {
288
- exists ( boolean partIsTrue , Expr part | test .impliesValue ( part , partIsTrue , testIsTrue ) |
289
- compares_lt ( part , left , right , k , isLt , partIsTrue )
290
- )
291
- }
292
-
293
- /** Rearrange various simple comparisons into `left < right + k` form. */
294
- private predicate simple_comparison_lt ( ComparisonOperation cmp , Expr left , Expr right , int k ) {
295
- left = cmp .getLeftOperand ( ) and
296
- cmp .getOperator ( ) = "<" and
297
- right = cmp .getRightOperand ( ) and
298
- k = 0
299
- or
300
- left = cmp .getLeftOperand ( ) and
301
- cmp .getOperator ( ) = "<=" and
302
- right = cmp .getRightOperand ( ) and
303
- k = 1
304
- or
305
- right = cmp .getLeftOperand ( ) and
306
- cmp .getOperator ( ) = ">" and
307
- left = cmp .getRightOperand ( ) and
308
- k = 0
309
- or
310
- right = cmp .getLeftOperand ( ) and
311
- cmp .getOperator ( ) = ">=" and
312
- left = cmp .getRightOperand ( ) and
313
- k = 1
314
- }
315
-
316
- private predicate complex_lt (
317
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean isLt , boolean testIsTrue
318
- ) {
319
- sub_lt ( cmp , left , right , k , isLt , testIsTrue )
320
- or
321
- add_lt ( cmp , left , right , k , isLt , testIsTrue )
322
- }
323
-
324
- // left - x < right + c => left < right + (c+x)
325
- // left < (right - x) + c => left < right + (c-x)
326
- private predicate sub_lt (
327
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean isLt , boolean testIsTrue
328
- ) {
329
- exists ( SubExpr lhs , int c , int x |
330
- compares_lt ( cmp , lhs , right , c , isLt , testIsTrue ) and
331
- left = lhs .getLeftOperand ( ) and
332
- x = int_value ( lhs .getRightOperand ( ) ) and
333
- k = c + x
334
- )
335
- or
336
- exists ( SubExpr rhs , int c , int x |
337
- compares_lt ( cmp , left , rhs , c , isLt , testIsTrue ) and
338
- right = rhs .getLeftOperand ( ) and
339
- x = int_value ( rhs .getRightOperand ( ) ) and
340
- k = c - x
341
- )
342
- }
343
-
344
- // left + x < right + c => left < right + (c-x)
345
- // left < (right + x) + c => left < right + (c+x)
346
- private predicate add_lt (
347
- ComparisonOperation cmp , Expr left , Expr right , int k , boolean isLt , boolean testIsTrue
348
- ) {
349
- exists ( AddExpr lhs , int c , int x |
350
- compares_lt ( cmp , lhs , right , c , isLt , testIsTrue ) and
351
- (
352
- left = lhs .getLeftOperand ( ) and x = int_value ( lhs .getRightOperand ( ) )
353
- or
354
- left = lhs .getRightOperand ( ) and x = int_value ( lhs .getLeftOperand ( ) )
355
- ) and
356
- k = c - x
357
- )
358
- or
359
- exists ( AddExpr rhs , int c , int x |
360
- compares_lt ( cmp , left , rhs , c , isLt , testIsTrue ) and
361
- (
362
- right = rhs .getLeftOperand ( ) and x = int_value ( rhs .getRightOperand ( ) )
363
- or
364
- right = rhs .getRightOperand ( ) and x = int_value ( rhs .getLeftOperand ( ) )
365
- ) and
366
- k = c + x
367
- )
368
- }
369
-
370
- /** The `int` value of integer constant expression. */
371
- private int int_value ( Expr e ) {
372
- e .getUnderlyingType ( ) instanceof IntegralType and
373
- result = e .getValue ( ) .toInt ( )
374
- }
10
+ import IRGuards
375
11
376
12
/** An `SsaDefinition` with an additional predicate `isLt`. */
377
13
class GuardedSsa extends SsaDefinition {
0 commit comments