Skip to content

Commit 0158e2f

Browse files
authored
Merge pull request #4374 from max-schaefer/js/api-graph
Approved by erik-krogh
2 parents 7f07520 + dfc4436 commit 0158e2f

File tree

5 files changed

+45
-12
lines changed

5 files changed

+45
-12
lines changed

javascript/ql/src/semmle/javascript/ApiGraphs.qll

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -443,16 +443,9 @@ module API {
443443
rhs = f.getAReturn()
444444
)
445445
or
446-
exists(DataFlow::SourceNode src, DataFlow::InvokeNode invk |
447-
use(base, src) and invk = trackUseNode(src).getAnInvocation()
448-
|
449-
exists(int i |
450-
lbl = Label::parameter(i) and
451-
rhs = invk.getArgument(i)
452-
)
453-
or
454-
lbl = Label::receiver() and
455-
rhs = invk.(DataFlow::CallNode).getReceiver()
446+
exists(int i |
447+
lbl = Label::parameter(i) and
448+
argumentPassing(base, i, rhs)
456449
)
457450
or
458451
exists(DataFlow::SourceNode src, DataFlow::PropWrite pw |
@@ -463,6 +456,30 @@ module API {
463456
)
464457
}
465458

459+
/**
460+
* Holds if `arg` is passed as the `i`th argument to a use of `base`, either by means of a
461+
* full invocation, or in a partial function application.
462+
*
463+
* The receiver is considered to be argument -1.
464+
*/
465+
private predicate argumentPassing(TApiNode base, int i, DataFlow::Node arg) {
466+
exists(DataFlow::SourceNode use, DataFlow::SourceNode pred |
467+
use(base, use) and pred = trackUseNode(use)
468+
|
469+
arg = pred.getAnInvocation().getArgument(i)
470+
or
471+
arg = pred.getACall().getReceiver() and
472+
i = -1
473+
or
474+
exists(DataFlow::PartialInvokeNode pin, DataFlow::Node callback | pred.flowsTo(callback) |
475+
pin.isPartialArgument(callback, arg, i)
476+
or
477+
arg = pin.getBoundReceiver(callback) and
478+
i = -1
479+
)
480+
)
481+
}
482+
466483
/**
467484
* Holds if `rhs` is the right-hand side of a definition of node `nd`.
468485
*/
@@ -750,10 +767,14 @@ private module Label {
750767
bindingset[s]
751768
string parameterByStringIndex(string s) {
752769
result = "parameter " + s and
753-
s.toInt() >= 0
770+
s.toInt() >= -1
754771
}
755772

756-
/** Gets the `parameter` edge label for the `i`th parameter. */
773+
/**
774+
* Gets the `parameter` edge label for the `i`th parameter.
775+
*
776+
* The receiver is considered to be parameter -1.
777+
*/
757778
bindingset[i]
758779
string parameter(int i) { result = parameterByStringIndex(i.toString()) }
759780

javascript/ql/test/ApiGraphs/partial-invoke/VerifyAssertions.expected

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import ApiGraphs.VerifyAssertions
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const cp = require('child_process');
2+
3+
module.exports = function () {
4+
return cp.spawn.bind(
5+
cp, // def (parameter -1 (member spawn (member exports (module child_process))))
6+
"cat" // def (parameter 0 (member spawn (member exports (module child_process))))
7+
);
8+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "partial-invoke"
3+
}

0 commit comments

Comments
 (0)