@@ -1142,7 +1142,8 @@ private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase, RawI
11421142}
11431143
11441144private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase ,
1145- RawIndirectInstruction {
1145+ RawIndirectInstruction
1146+ {
11461147 IndirectInstructionIndirectExprNode ( ) { indirectExprNodeShouldBeIndirectInstruction ( this , _) }
11471148
11481149 final override Expr getConvertedExpr ( int index ) {
@@ -1612,11 +1613,64 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
16121613cached
16131614private module ExprFlowCached {
16141615 /**
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` .
16171618 */
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+
16181672 private predicate localStepFromNonExpr ( Node n1 , Node n2 ) {
1619- not exists ( n1 . asExpr ( ) ) and
1673+ not exists ( asExpr ( n1 ) ) and
16201674 localFlowStep ( n1 , n2 )
16211675 }
16221676
@@ -1627,7 +1681,7 @@ private module ExprFlowCached {
16271681 pragma [ nomagic]
16281682 private predicate localStepsToExpr ( Node n1 , Node n2 , Expr e2 ) {
16291683 localStepFromNonExpr * ( n1 , n2 ) and
1630- e2 = n2 . asExpr ( )
1684+ e2 = asExpr ( n2 )
16311685 }
16321686
16331687 /**
@@ -1638,7 +1692,7 @@ private module ExprFlowCached {
16381692 exists ( Node mid |
16391693 localFlowStep ( n1 , mid ) and
16401694 localStepsToExpr ( mid , n2 , e2 ) and
1641- e1 = n1 . asExpr ( )
1695+ e1 = asExpr ( n1 )
16421696 )
16431697 }
16441698
0 commit comments