JavaScript: Teach API graphs to recognise arguments supplied in partial function applications.

This commit is contained in:
Max Schaefer
2020-09-28 15:34:47 +01:00
parent 18bdc054cd
commit dfc4436012
5 changed files with 45 additions and 12 deletions

View File

@@ -412,16 +412,9 @@ module API {
rhs = f.getAReturn()
)
or
exists(DataFlow::SourceNode src, DataFlow::InvokeNode invk |
use(base, src) and invk = trackUseNode(src).getAnInvocation()
|
exists(int i |
lbl = Label::parameter(i) and
rhs = invk.getArgument(i)
)
or
lbl = Label::receiver() and
rhs = invk.(DataFlow::CallNode).getReceiver()
exists(int i |
lbl = Label::parameter(i) and
argumentPassing(base, i, rhs)
)
or
exists(DataFlow::SourceNode src, DataFlow::PropWrite pw |
@@ -432,6 +425,30 @@ module API {
)
}
/**
* Holds if `arg` is passed as the `i`th argument to a use of `base`, either by means of a
* full invocation, or in a partial function application.
*
* The receiver is considered to be argument -1.
*/
private predicate argumentPassing(TApiNode base, int i, DataFlow::Node arg) {
exists(DataFlow::SourceNode use, DataFlow::SourceNode pred |
use(base, use) and pred = trackUseNode(use)
|
arg = pred.getAnInvocation().getArgument(i)
or
arg = pred.getACall().getReceiver() and
i = -1
or
exists(DataFlow::PartialInvokeNode pin, DataFlow::Node callback | pred.flowsTo(callback) |
pin.isPartialArgument(callback, arg, i)
or
arg = pin.getBoundReceiver(callback) and
i = -1
)
)
}
/**
* Holds if `rhs` is the right-hand side of a definition of node `nd`.
*/
@@ -719,10 +736,14 @@ private module Label {
bindingset[s]
string parameterByStringIndex(string s) {
result = "parameter " + s and
s.toInt() >= 0
s.toInt() >= -1
}
/** Gets the `parameter` edge label for the `i`th parameter. */
/**
* Gets the `parameter` edge label for the `i`th parameter.
*
* The receiver is considered to be parameter -1.
*/
bindingset[i]
string parameter(int i) { result = parameterByStringIndex(i.toString()) }

View File

@@ -0,0 +1 @@
import ApiGraphs.VerifyAssertions

View File

@@ -0,0 +1,8 @@
const cp = require('child_process');
module.exports = function () {
return cp.spawn.bind(
cp, // def (parameter -1 (member spawn (member exports (module child_process))))
"cat" // def (parameter 0 (member spawn (member exports (module child_process))))
);
};

View File

@@ -0,0 +1,3 @@
{
"name": "partial-invoke"
}