@@ -1326,13 +1326,8 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
13261326 localFlow ( instructionNode ( e1 ) , instructionNode ( e2 ) )
13271327}
13281328
1329- /**
1330- * Holds if data can flow from `e1` to `e2` in zero or more
1331- * local (intra-procedural) steps.
1332- */
1333- pragma [ inline]
1334- predicate localExprFlow ( Expr e1 , Expr e2 ) { localExprFlowStep * ( e1 , e2 ) }
1335-
1329+ cached
1330+ private module ExprFlowCached {
13361331/**
13371332 * Holds if `n1.asExpr()` doesn't have a result and `n1` flows to `n2` in a single
13381333 * dataflow step.
@@ -1352,14 +1347,43 @@ private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
13521347 e2 = n2 .asExpr ( )
13531348}
13541349
1355- /** Holds if data can flow from `e1` to `e2` in one local (intra-procedural) step. */
1356- cached
1357- predicate localExprFlowStep ( Expr e1 , Expr e2 ) {
1358- exists ( Node mid , Node n1 , Node n2 |
1350+ /**
1351+ * Holds if `n1.asExpr() = e1` and `n2.asExpr() = e2` and `n2` is the first node
1352+ * reacahble from `n1` such that `n2.asExpr()` exists.
1353+ */
1354+ private predicate localExprFlowSingleExprStep ( Node n1 , Expr e1 , Node n2 , Expr e2 ) {
1355+ exists ( Node mid |
13591356 localFlowStep ( n1 , mid ) and
13601357 localStepsToExpr ( mid , n2 , e2 ) and
13611358 e1 = n1 .asExpr ( )
13621359 )
1360+ }
1361+
1362+ /**
1363+ * Holds if `n1.asExpr() = e1` and `e1 != e2` and `n2` is the first reachable node from
1364+ * `n1` such that `n2.asExpr() = e2`.
1365+ */
1366+ private predicate localExprFlowStepImpl ( Node n1 , Expr e1 , Node n2 , Expr e2 ) {
1367+ exists ( Node n , Expr e | localExprFlowSingleExprStep ( n1 , e1 , n , e ) |
1368+ // If `n.asExpr()` and `n1.asExpr()` both resolve to the same node (which can
1369+ // happen if `n2` is the node attached to a conversion of `e1`), then we recursively
1370+ // perform another expression step.
1371+ if e1 = e
1372+ then localExprFlowStepImpl ( n , e , n2 , e2 )
1373+ else (
1374+ // If we manage to step to a different expression we're done.
1375+ e2 = e and
1376+ n2 = n
1377+ )
1378+ )
1379+ }
1380+
1381+ /** Holds if data can flow from `e1` to `e2` in one local (intra-procedural) step. */
1382+ cached
1383+ predicate localExprFlowStep ( Expr e1 , Expr e2 ) { localExprFlowStepImpl ( _, e1 , _, e2 ) }
1384+ }
1385+
1386+ import ExprFlowCached
13631387}
13641388
13651389cached
0 commit comments