@@ -1142,7 +1142,8 @@ private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase, RawI
1142
1142
}
1143
1143
1144
1144
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase ,
1145
- RawIndirectInstruction {
1145
+ RawIndirectInstruction
1146
+ {
1146
1147
IndirectInstructionIndirectExprNode ( ) { indirectExprNodeShouldBeIndirectInstruction ( this , _) }
1147
1148
1148
1149
final override Expr getConvertedExpr ( int index ) {
@@ -1612,11 +1613,64 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
1612
1613
cached
1613
1614
private module ExprFlowCached {
1614
1615
/**
1615
- * Holds if `n1.asExpr()` doesn't have a result and `n1` flows to `n2` in a single
1616
- * dataflow step .
1616
+ * Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
1617
+ * `e` is the result of loading from the `PointerArithmeticInstruction` .
1617
1618
*/
1619
+ private predicate isIndirectBaseOfArrayAccess ( IndirectOperand n , Expr e ) {
1620
+ exists ( LoadInstruction load , PointerArithmeticInstruction pai |
1621
+ pai = load .getSourceAddress ( ) and
1622
+ pai .getLeftOperand ( ) = n .getOperand ( ) and
1623
+ n .getIndirectionIndex ( ) = 1 and
1624
+ e = load .getConvertedResultExpression ( )
1625
+ )
1626
+ }
1627
+
1628
+ /**
1629
+ * Gets the expression associated with node `n`, if any.
1630
+ *
1631
+ * Unlike `n.asExpr()`, this predicate will also get the
1632
+ * expression `*(x + i)` when `n` is the indirect node
1633
+ * for `x`. This ensures that an assignment in a long chain
1634
+ * of assignments in a macro expansion is properly mapped
1635
+ * to the previous assignment. For example, in:
1636
+ * ```cpp
1637
+ * *x = source();
1638
+ * use(x[0]);
1639
+ * use(x[1]);
1640
+ * ...
1641
+ * use(x[i]);
1642
+ * use(x[i+1]);
1643
+ * ...
1644
+ * use(x[N]);
1645
+ * ```
1646
+ * To see what the problem would be if `asExpr(n)` was replaced
1647
+ * with `n.asExpr()`, consider the transitive closure over
1648
+ * `localStepFromNonExpr` in `localStepsToExpr`. We start at `n2`
1649
+ * for which `n.asExpr()` exists. For example, `n2` in the above
1650
+ * example could be a `x[i]` in any of the `use(x[i])` above.
1651
+ *
1652
+ * We then step to a dataflow predecessor of `n2`. In the above
1653
+ * code fragment, thats the indirect node corresponding to `x` in
1654
+ * `x[i-1]`. Since this doesn't have a result for `Node::asExpr()`
1655
+ * we continue with the recursion until we reach `*x = source()`
1656
+ * which does have a result for `Node::asExpr()`.
1657
+ *
1658
+ * If `N` is very large this blows up.
1659
+ *
1660
+ * To fix this, we map the indirect node corresponding to `x` to
1661
+ * in `x[i - 1]` to the `x[i - 1]` expression. This ensures that
1662
+ * `x[i]` steps to the expression `x[i - 1]` without traversing the
1663
+ * entire chain.
1664
+ */
1665
+ private Expr asExpr ( Node n ) {
1666
+ isIndirectBaseOfArrayAccess ( n , result )
1667
+ or
1668
+ not isIndirectBaseOfArrayAccess ( n , _) and
1669
+ result = n .asExpr ( )
1670
+ }
1671
+
1618
1672
private predicate localStepFromNonExpr ( Node n1 , Node n2 ) {
1619
- not exists ( n1 . asExpr ( ) ) and
1673
+ not exists ( asExpr ( n1 ) ) and
1620
1674
localFlowStep ( n1 , n2 )
1621
1675
}
1622
1676
@@ -1627,7 +1681,7 @@ private module ExprFlowCached {
1627
1681
pragma [ nomagic]
1628
1682
private predicate localStepsToExpr ( Node n1 , Node n2 , Expr e2 ) {
1629
1683
localStepFromNonExpr * ( n1 , n2 ) and
1630
- e2 = n2 . asExpr ( )
1684
+ e2 = asExpr ( n2 )
1631
1685
}
1632
1686
1633
1687
/**
@@ -1638,7 +1692,7 @@ private module ExprFlowCached {
1638
1692
exists ( Node mid |
1639
1693
localFlowStep ( n1 , mid ) and
1640
1694
localStepsToExpr ( mid , n2 , e2 ) and
1641
- e1 = n1 . asExpr ( )
1695
+ e1 = asExpr ( n1 )
1642
1696
)
1643
1697
}
1644
1698
0 commit comments