JS: Also track into callbacks

This commit is contained in:
Asger Feldthaus
2020-02-07 12:55:52 +00:00
parent e8e649102f
commit b780bc4d59
5 changed files with 28 additions and 3 deletions

View File

@@ -71,6 +71,7 @@
private import javascript
private import internal.FlowSteps
private import internal.AccessPaths
private import internal.CallGraphs
/**
* A data flow tracking configuration for finding inter-procedural paths from
@@ -620,10 +621,11 @@ private predicate exploratoryFlowStep(
isAdditionalStoreStep(pred, succ, _, cfg) or
isAdditionalLoadStep(pred, succ, _, cfg) or
isAdditionalLoadStoreStep(pred, succ, _, cfg) or
// the following two disjuncts taken together over-approximate flow through
// the following three disjuncts taken together over-approximate flow through
// higher-order calls
callback(pred, succ) or
succ = pred.(DataFlow::FunctionNode).getAParameter()
succ = pred.(DataFlow::FunctionNode).getAParameter() or
exploratoryBoundInvokeStep(pred, succ)
}
/**
@@ -1032,6 +1034,13 @@ private predicate flowIntoHigherOrderCall(
succ = cb.getParameter(i) and
summary = oldSummary.append(PathSummary::call())
)
or
exists(DataFlow::SourceNode cb, DataFlow::FunctionNode f, int i, int boundArgs, PathSummary oldSummary |
higherOrderCall(pred, cb, i, cfg, oldSummary) and
cb = CallGraph::getABoundFunctionReference(f, boundArgs, false) and
succ = f.getParameter(boundArgs + i) and
summary = oldSummary.append(PathSummary::call())
)
}
/**

View File

@@ -104,6 +104,20 @@ private module CachedSteps {
CallGraph::getABoundFunctionReference(f.flow(), boundArgs, false).flowsTo(invk.getCalleeNode())
}
/**
* Holds if `pred` may flow to `succ` through an invocation of a bound function.
*
* Should only be used for graph pruning, as the edge may lead to spurious flow.
*/
cached
predicate exploratoryBoundInvokeStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::InvokeNode invk, DataFlow::FunctionNode f, int i, int boundArgs |
CallGraph::getABoundFunctionReference(f, boundArgs, _).flowsTo(invk.getCalleeNode()) and
pred = invk.getArgument(i) and
succ = f.getParameter(i + boundArgs)
)
}
/**
* Holds if `invk` may invoke `f` indirectly through the given `callback` argument.
*

View File

@@ -17,6 +17,7 @@ typeInferenceMismatch
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:22:10:22:10 | x |
| bound-function.js:12:12:12:19 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:14:6:14:13 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:22:8:22:15 | source() | bound-function.js:25:10:25:10 | y |
| bound-function.js:45:10:45:17 | source() | bound-function.js:45:6:45:18 | id3(source()) |
| bound-function.js:49:12:49:19 | source() | bound-function.js:54:6:54:14 | source0() |
| bound-function.js:49:12:49:19 | source() | bound-function.js:55:6:55:14 | source1() |

View File

@@ -8,6 +8,7 @@
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:22:10:22:10 | x |
| bound-function.js:12:12:12:19 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:14:6:14:13 | source() | bound-function.js:4:10:4:10 | y |
| bound-function.js:22:8:22:15 | source() | bound-function.js:25:10:25:10 | y |
| bound-function.js:45:10:45:17 | source() | bound-function.js:45:6:45:18 | id3(source()) |
| bound-function.js:49:12:49:19 | source() | bound-function.js:54:6:54:14 | source0() |
| bound-function.js:49:12:49:19 | source() | bound-function.js:55:6:55:14 | source1() |

View File

@@ -19,7 +19,7 @@ foo2(null, source()); // OK
function takesCallback(cb) {
cb(source()); // NOT OK - but not found
cb(source()); // NOT OK
}
function callback(x, y) {
sink(y);