mirror of
https://github.com/github/codeql.git
synced 2025-12-23 20:26:32 +01:00
Merge pull request #12507 from MathiasVP/fix-as-expr-performance-2
C++: Map some indirect nodes to expressions in `localExprFlowStep`
This commit is contained in:
@@ -1142,7 +1142,8 @@ private class IndirectOperandIndirectExprNode extends IndirectExprNodeBase, RawI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase,
|
private class IndirectInstructionIndirectExprNode extends IndirectExprNodeBase,
|
||||||
RawIndirectInstruction {
|
RawIndirectInstruction
|
||||||
|
{
|
||||||
IndirectInstructionIndirectExprNode() { indirectExprNodeShouldBeIndirectInstruction(this, _) }
|
IndirectInstructionIndirectExprNode() { indirectExprNodeShouldBeIndirectInstruction(this, _) }
|
||||||
|
|
||||||
final override Expr getConvertedExpr(int index) {
|
final override Expr getConvertedExpr(int index) {
|
||||||
@@ -1612,39 +1613,96 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
|
|||||||
cached
|
cached
|
||||||
private module ExprFlowCached {
|
private module ExprFlowCached {
|
||||||
/**
|
/**
|
||||||
* Holds if `n1.asExpr()` doesn't have a result and `n1` flows to `n2` in a single
|
* Holds if `n` is an indirect operand of a `PointerArithmeticInstruction`, and
|
||||||
|
* `e` is the result of loading from the `PointerArithmeticInstruction`.
|
||||||
|
*/
|
||||||
|
private predicate isIndirectBaseOfArrayAccess(IndirectOperand n, Expr e) {
|
||||||
|
exists(LoadInstruction load, PointerArithmeticInstruction pai |
|
||||||
|
pai = load.getSourceAddress() and
|
||||||
|
pai.getLeftOperand() = n.getOperand() and
|
||||||
|
n.getIndirectionIndex() = 1 and
|
||||||
|
e = load.getConvertedResultExpression()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the expression associated with node `n`, if any.
|
||||||
|
*
|
||||||
|
* Unlike `n.asExpr()`, this predicate will also get the
|
||||||
|
* expression `*(x + i)` when `n` is the indirect node
|
||||||
|
* for `x`. This ensures that an assignment in a long chain
|
||||||
|
* of assignments in a macro expansion is properly mapped
|
||||||
|
* to the previous assignment. For example, in:
|
||||||
|
* ```cpp
|
||||||
|
* *x = source();
|
||||||
|
* use(x[0]);
|
||||||
|
* use(x[1]);
|
||||||
|
* ...
|
||||||
|
* use(x[i]);
|
||||||
|
* use(x[i+1]);
|
||||||
|
* ...
|
||||||
|
* use(x[N]);
|
||||||
|
* ```
|
||||||
|
* To see what the problem would be if `asExpr(n)` was replaced
|
||||||
|
* with `n.asExpr()`, consider the transitive closure over
|
||||||
|
* `localStepFromNonExpr` in `localStepsToExpr`. We start at `n2`
|
||||||
|
* for which `n.asExpr()` exists. For example, `n2` in the above
|
||||||
|
* example could be a `x[i]` in any of the `use(x[i])` above.
|
||||||
|
*
|
||||||
|
* We then step to a dataflow predecessor of `n2`. In the above
|
||||||
|
* code fragment, thats the indirect node corresponding to `x` in
|
||||||
|
* `x[i-1]`. Since this doesn't have a result for `Node::asExpr()`
|
||||||
|
* we continue with the recursion until we reach `*x = source()`
|
||||||
|
* which does have a result for `Node::asExpr()`.
|
||||||
|
*
|
||||||
|
* If `N` is very large this blows up.
|
||||||
|
*
|
||||||
|
* To fix this, we map the indirect node corresponding to `x` to
|
||||||
|
* in `x[i - 1]` to the `x[i - 1]` expression. This ensures that
|
||||||
|
* `x[i]` steps to the expression `x[i - 1]` without traversing the
|
||||||
|
* entire chain.
|
||||||
|
*/
|
||||||
|
private Expr asExpr(Node n) {
|
||||||
|
isIndirectBaseOfArrayAccess(n, result)
|
||||||
|
or
|
||||||
|
not isIndirectBaseOfArrayAccess(n, _) and
|
||||||
|
result = n.asExpr()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `asExpr(n1)` doesn't have a result and `n1` flows to `n2` in a single
|
||||||
* dataflow step.
|
* dataflow step.
|
||||||
*/
|
*/
|
||||||
private predicate localStepFromNonExpr(Node n1, Node n2) {
|
private predicate localStepFromNonExpr(Node n1, Node n2) {
|
||||||
not exists(n1.asExpr()) and
|
not exists(asExpr(n1)) and
|
||||||
localFlowStep(n1, n2)
|
localFlowStep(n1, n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n1.asExpr()` doesn't have a result, `n2.asExpr() = e2` and
|
* Holds if `asExpr(n1)` doesn't have a result, `asExpr(n2) = e2` and
|
||||||
* `n2` is the first node reachable from `n1` such that `n2.asExpr()` exists.
|
* `n2` is the first node reachable from `n1` such that `asExpr(n2)` exists.
|
||||||
*/
|
*/
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
|
private predicate localStepsToExpr(Node n1, Node n2, Expr e2) {
|
||||||
localStepFromNonExpr*(n1, n2) and
|
localStepFromNonExpr*(n1, n2) and
|
||||||
e2 = n2.asExpr()
|
e2 = asExpr(n2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n1.asExpr() = e1` and `n2.asExpr() = e2` and `n2` is the first node
|
* Holds if `asExpr(n1) = e1` and `asExpr(n2) = e2` and `n2` is the first node
|
||||||
* reachable from `n1` such that `n2.asExpr()` exists.
|
* reachable from `n1` such that `asExpr(n2)` exists.
|
||||||
*/
|
*/
|
||||||
private predicate localExprFlowSingleExprStep(Node n1, Expr e1, Node n2, Expr e2) {
|
private predicate localExprFlowSingleExprStep(Node n1, Expr e1, Node n2, Expr e2) {
|
||||||
exists(Node mid |
|
exists(Node mid |
|
||||||
localFlowStep(n1, mid) and
|
localFlowStep(n1, mid) and
|
||||||
localStepsToExpr(mid, n2, e2) and
|
localStepsToExpr(mid, n2, e2) and
|
||||||
e1 = n1.asExpr()
|
e1 = asExpr(n1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `n1.asExpr() = e1` and `e1 != e2` and `n2` is the first reachable node from
|
* Holds if `asExpr(n1) = e1` and `e1 != e2` and `n2` is the first reachable node from
|
||||||
* `n1` such that `n2.asExpr() = e2`.
|
* `n1` such that `asExpr(n2) = e2`.
|
||||||
*/
|
*/
|
||||||
private predicate localExprFlowStepImpl(Node n1, Expr e1, Node n2, Expr e2) {
|
private predicate localExprFlowStepImpl(Node n1, Expr e1, Node n2, Expr e2) {
|
||||||
exists(Node n, Expr e | localExprFlowSingleExprStep(n1, e1, n, e) |
|
exists(Node n, Expr e | localExprFlowSingleExprStep(n1, e1, n, e) |
|
||||||
|
|||||||
Reference in New Issue
Block a user