@@ -7,371 +7,7 @@ import cpp
77import semmle.code.cpp.controlflow.BasicBlocks
88import semmle.code.cpp.controlflow.SSA
99import 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
37511
37612/** An `SsaDefinition` with an additional predicate `isLt`. */
37713class GuardedSsa extends SsaDefinition {
0 commit comments