@@ -192,6 +192,77 @@ private predicate revBbSuccessorEntryReaches0(
192192 )
193193}
194194
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+
195266/**
196267 * A reachability analysis for control-flow nodes involving stack variables.
197268 * This defines sources, sinks, and any other configurable aspect of the
@@ -296,19 +367,6 @@ abstract class StackVariableReachability extends string {
296367 )
297368 }
298369
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-
312370 /** Holds if `cond` is a condition with a known truth value in `bb`. */
313371 private Condition getACondition ( ControlFlowNode source , SemanticStackVariable v , BasicBlock bb ) {
314372 revBbSuccessorEntryReaches0 ( source , pragma [ only_bind_into ] ( bb ) , v , _, this ) and
@@ -325,37 +383,9 @@ abstract class StackVariableReachability extends string {
325383 result = cond and
326384 revBbSuccessorEntryReaches0 ( source , pragma [ only_bind_into ] ( pred ) , v , _, this ) and
327385 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 )
359389 )
360390 )
361391 }
0 commit comments