Python: Fix bad join order in TypeTracker::callStep

From a local evaluation against flask DB, after
https://github.com/github/codeql/pull/4649 was merged we would get:

```
Tuple counts for TypeTracker::callStep#ff/2@a21b71:
9876     ~0%     {3} r1 = SCAN DataFlowPrivate::DataFlowCall::getArg_dispred#fff AS I OUTPUT I.<2>, I.<0>, I.<1>
9876     ~2%     {3} r2 = JOIN r1 WITH project#DataFlowPrivate::DataFlowCall::getArg_dispred#fff AS R ON FIRST 1 OUTPUT r1.<2>, R.<0>, r1.<1>
72388997 ~0%     {4} r3 = JOIN r2 WITH DataFlowPublic::ParameterNode::isParameterOf_dispred#fff_201#join_rhs AS R ON FIRST 1 OUTPUT r2.<2>, R.<2>, r2.<1>, R.<1>
4952     ~0%     {2} r4 = JOIN r3 WITH DataFlowPrivate::DataFlowCall::getCallable_dispred#ff AS R ON FIRST 2 OUTPUT r3.<2>, r3.<3>
                     return r4
```
This commit is contained in:
Rasmus Wriedt Larsen
2020-11-17 16:38:15 +01:00
parent 09cfb24afa
commit 14136154d6

View File

@@ -87,11 +87,25 @@ private predicate typePreservingStep(Node nodeFrom, Node nodeTo) {
nodeFrom = nodeTo.(PostUpdateNode).getPreUpdateNode()
}
/**
* Helper predicate to avoid bad join order experienced in `callStep`.
*
* This happened when `isParameterOf` was joined _before_ `getCallable`.
*/
pragma[nomagic]
private DataFlowCallable callStepHelper(ArgumentNode nodeFrom, int i) {
exists(DataFlowCall call |
nodeFrom.argumentOf(call, i) and
result = call.getCallable()
)
}
/** Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. */
predicate callStep(ArgumentNode nodeFrom, ParameterNode nodeTo) {
// TODO: Support special methods?
exists(DataFlowCall call, int i |
nodeFrom.argumentOf(call, i) and nodeTo.isParameterOf(call.getCallable(), i)
exists(DataFlowCallable callable, int i |
callable = callStepHelper(nodeFrom, i) and
nodeTo.isParameterOf(callable, i)
)
}