@@ -192,6 +192,77 @@ private predicate revBbSuccessorEntryReaches0(
192
192
)
193
193
}
194
194
195
+ private predicate successorExitsLoop ( BasicBlock pred , BasicBlock succ , Loop loop ) {
196
+ pred .getASuccessor ( ) = succ and
197
+ bbDominates ( loop .getStmt ( ) , pred ) and
198
+ not bbDominates ( loop .getStmt ( ) , succ )
199
+ }
200
+
201
+ private predicate successorExitsFirstDisjunct ( BasicBlock pred , BasicBlock succ ) {
202
+ exists ( LogicalOrExpr orExpr | orExpr instanceof GuardCondition |
203
+ pred .getAFalseSuccessor ( ) = succ and
204
+ pred .contains ( orExpr .getLeftOperand ( ) )
205
+ )
206
+ }
207
+
208
+ /**
209
+ * When we exit a loop, we filter out the conditions that arise from the loop's guard.
210
+ * To see why this is necessary, consider this example:
211
+ * ```
212
+ * (1) source();
213
+ * while (b) { (2) ... }
214
+ * (3) sink();
215
+ * ```
216
+ * If we keep all the conditions when we transition from (2) to (3) we learn that `b` is true at
217
+ * (3), but since we exited the loop we also learn that `b` is false at 3.
218
+ * Thus, when we transition from (2) to (3) we discard all those conditions that are true at (2),
219
+ * but NOT true at (3).
220
+ */
221
+ private predicate isLoopCondition ( LogicalGuardCondition cond , BasicBlock pred , BasicBlock bb ) {
222
+ exists ( Loop loop , boolean testIsTrue | successorExitsLoop ( pred , bb , loop ) |
223
+ // the resulting `Condition` holds inside the loop
224
+ cond .controls ( pred , testIsTrue ) and
225
+ // but not prior to the loop.
226
+ not cond .controls ( loop .getBasicBlock ( ) , testIsTrue )
227
+ )
228
+ }
229
+
230
+ /**
231
+ * When we leave the first disjunct we throw away the condition that says the the first disjunct is
232
+ * false. To see why this is necessary, consider this example:
233
+ * ```
234
+ * if((1) b1 || (2) b2) { (3) ... }
235
+ * ```
236
+ * it holds that `b1 == false` controls (2), and since (2) steps to (3) we learn that `b1 == false `
237
+ * holds at (3). So we filter out the conditions that we learn from leaving taking the false
238
+ * branch in a disjunction.
239
+ */
240
+ private predicate isDisjunctionCondition ( LogicalGuardCondition cond , BasicBlock pred , BasicBlock bb ) {
241
+ exists ( boolean testIsTrue | successorExitsFirstDisjunct ( pred , bb ) |
242
+ // the resulting `Condition` holds after evaluating the left-hand side
243
+ cond .controls ( bb , testIsTrue ) and
244
+ // but not before evaluating the left-hand side.
245
+ not cond .controls ( pred , testIsTrue )
246
+ )
247
+ }
248
+
249
+ private predicate isLoopVariantCondition ( LogicalGuardCondition cond , BasicBlock pred , BasicBlock bb ) {
250
+ exists ( Loop loop |
251
+ bb .getEnd ( ) = loop .getCondition ( ) and
252
+ pred .getASuccessor ( ) = bb and
253
+ bbDominates ( bb , pred ) and
254
+ loopVariant ( cond .getAChild * ( ) , loop )
255
+ )
256
+ }
257
+
258
+ private predicate loopVariant ( VariableAccess e , Loop loop ) {
259
+ exists ( SsaDefinition d | d .getAUse ( e .getTarget ( ) ) = e |
260
+ d .getAnUltimateDefiningValue ( e .getTarget ( ) ) = loop .getCondition ( ) .getAChild * ( ) or
261
+ d .getAnUltimateDefiningValue ( e .getTarget ( ) ) .getEnclosingStmt ( ) .getParent * ( ) = loop .getStmt ( ) or
262
+ d .getAnUltimateDefiningValue ( e .getTarget ( ) ) = loop .( ForStmt ) .getUpdate ( ) .getAChild * ( )
263
+ )
264
+ }
265
+
195
266
/**
196
267
* A reachability analysis for control-flow nodes involving stack variables.
197
268
* This defines sources, sinks, and any other configurable aspect of the
@@ -296,19 +367,6 @@ abstract class StackVariableReachability extends string {
296
367
)
297
368
}
298
369
299
- private predicate successorExitsLoop ( BasicBlock pred , BasicBlock succ , Loop loop ) {
300
- pred .getASuccessor ( ) = succ and
301
- bbDominates ( loop .getStmt ( ) , pred ) and
302
- not bbDominates ( loop .getStmt ( ) , succ )
303
- }
304
-
305
- private predicate successorExitsFirstDisjunct ( BasicBlock pred , BasicBlock succ ) {
306
- exists ( LogicalOrExpr orExpr | orExpr instanceof GuardCondition |
307
- pred .getAFalseSuccessor ( ) = succ and
308
- pred .contains ( orExpr .getLeftOperand ( ) )
309
- )
310
- }
311
-
312
370
/** Holds if `cond` is a condition with a known truth value in `bb`. */
313
371
private Condition getACondition ( ControlFlowNode source , SemanticStackVariable v , BasicBlock bb ) {
314
372
revBbSuccessorEntryReaches0 ( source , pragma [ only_bind_into ] ( bb ) , v , _, this ) and
@@ -325,37 +383,9 @@ abstract class StackVariableReachability extends string {
325
383
result = cond and
326
384
revBbSuccessorEntryReaches0 ( source , pragma [ only_bind_into ] ( pred ) , v , _, this ) and
327
385
pred .getASuccessor ( ) = bb and
328
- // When we exit a loop, we filter out the conditions that arise from the loop's guard.
329
- // To see why this is necessary, consider this example:
330
- // ```
331
- // (1) source();
332
- // while (b) { (2) /* ... */ }
333
- // (3) sink();
334
- // ```
335
- // If we keep all the conditions when we transition from (2) to (3) we learn that `b` is true at
336
- // (3), but since we exited the loop we also learn that `b` is false at 3.
337
- // Thus, when we transition from (2) to (3) we discard all those conditions that are true at (2),
338
- // but NOT true at (3).
339
- not exists ( Loop loop , boolean testIsTrue | successorExitsLoop ( pred , bb , loop ) |
340
- // the resulting `Condition` holds inside the loop
341
- cond .getCondition ( ) .controls ( pred , testIsTrue ) and
342
- // but not prior to the loop.
343
- not cond .getCondition ( ) .controls ( loop .getBasicBlock ( ) , testIsTrue )
344
- ) and
345
- // Similarly, in this example:
346
- // ```
347
- // if((1) b1 || (2) b2) { (3) /* ... */ }
348
- // ```
349
- // it holds that `b1 == false` controls (2), and since (2) steps to (3) we learn that `b1 == false `
350
- // holds at (3). So we filter out the conditions that we learn from leaving taking the false
351
- // branch in a disjunction.
352
- not exists ( boolean testIsTrue |
353
- successorExitsFirstDisjunct ( pred , bb ) and
354
- // the resulting `Condition` holds after evaluating the left-hand side
355
- cond .getCondition ( ) .controls ( bb , testIsTrue ) and
356
- // but not before evaluating the left-hand side.
357
- not cond .getCondition ( ) .controls ( pred , testIsTrue )
358
- )
386
+ not isLoopCondition ( cond .getCondition ( ) , pred , bb ) and
387
+ not isDisjunctionCondition ( cond .getCondition ( ) , pred , bb ) and
388
+ not isLoopVariantCondition ( cond .getCondition ( ) , pred , bb )
359
389
)
360
390
)
361
391
}
0 commit comments