Skip to content

Commit 8eb84b2

Browse files
authored
Merge pull request #4391 from max-schaefer/js/api-graph-reexport
Approved by asgerf
2 parents 6d1634e + 98ab38a commit 8eb84b2

File tree

5 files changed

+60
-16
lines changed

5 files changed

+60
-16
lines changed

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

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -419,11 +419,20 @@ module API {
419419
exists(DataFlow::Node def, DataFlow::SourceNode pred |
420420
rhs(base, def) and pred = trackDefNode(def)
421421
|
422+
// from `x` to a definition of `x.prop`
422423
exists(DataFlow::PropWrite pw | pw = pred.getAPropertyWrite() |
423424
lbl = Label::memberFromRef(pw) and
424425
rhs = pw.getRhs()
425426
)
426427
or
428+
// special case: from `require('m')` to an export of `prop` in `m`
429+
exists(Import imp, Module m, string prop |
430+
pred = imp.getImportedModuleNode() and
431+
m = imp.getImportedModule() and
432+
lbl = Label::member(prop) and
433+
rhs = m.getAnExportedValue(prop)
434+
)
435+
or
427436
exists(DataFlow::FunctionNode fn | fn = pred |
428437
not fn.getFunction().isAsync() and
429438
lbl = Label::return() and
@@ -561,15 +570,11 @@ module API {
561570
cached
562571
predicate use(TApiNode nd, DataFlow::Node ref) {
563572
exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) |
564-
ref = DataFlow::ssaDefinitionNode(SSA::implicitInit(mod.(NodeModule).getModuleVariable()))
565-
or
566-
ref = DataFlow::parameterNode(mod.(AmdModule).getDefine().getModuleParameter())
573+
ref.(ModuleAsSourceNode).getModule() = mod
567574
)
568575
or
569576
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
570-
ref = DataFlow::ssaDefinitionNode(SSA::implicitInit(mod.(NodeModule).getExportsVariable()))
571-
or
572-
ref = DataFlow::parameterNode(mod.(AmdModule).getDefine().getExportsParameter())
577+
ref.(ExportsAsSourceNode).getModule() = mod
573578
or
574579
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
575580
ref = trackUseNode(base).getAPropertyRead("exports")
@@ -640,6 +645,16 @@ module API {
640645
rhs(_, nd) and
641646
result = nd.getALocalSource()
642647
or
648+
// additional backwards step from `require('m')` to `exports` or `module.exports` in m
649+
exists(Import imp | imp.getImportedModuleNode() = trackDefNode(nd, t.continue()) |
650+
result.(ExportsAsSourceNode).getModule() = imp.getImportedModule()
651+
or
652+
exists(ModuleAsSourceNode mod |
653+
mod.getModule() = imp.getImportedModule() and
654+
result = mod.(DataFlow::SourceNode).getAPropertyRead("exports")
655+
)
656+
)
657+
or
643658
exists(DataFlow::TypeBackTracker t2 | result = trackDefNode(nd, t2).backtrack(t2, t))
644659
}
645660

@@ -796,13 +811,31 @@ private module Label {
796811
}
797812

798813
/**
799-
* A CommonJS `module` or `exports` variable, considered as a source node.
814+
* A CommonJS/AMD `module` variable, considered as a source node.
800815
*/
801-
private class AdditionalSourceNode extends DataFlow::SourceNode::Range {
802-
AdditionalSourceNode() {
803-
exists(NodeModule m, Variable v |
804-
v in [m.getModuleVariable(), m.getExportsVariable()] and
805-
this = DataFlow::ssaDefinitionNode(SSA::implicitInit(v))
806-
)
816+
private class ModuleAsSourceNode extends DataFlow::SourceNode::Range {
817+
Module m;
818+
819+
ModuleAsSourceNode() {
820+
this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getModuleVariable()))
821+
or
822+
this = DataFlow::parameterNode(m.(AmdModule).getDefine().getModuleParameter())
823+
}
824+
825+
Module getModule() { result = m }
826+
}
827+
828+
/**
829+
* A CommonJS/AMD `exports` variable, considered as a source node.
830+
*/
831+
private class ExportsAsSourceNode extends DataFlow::SourceNode::Range {
832+
Module m;
833+
834+
ExportsAsSourceNode() {
835+
this = DataFlow::ssaDefinitionNode(SSA::implicitInit(m.(NodeModule).getExportsVariable()))
836+
or
837+
this = DataFlow::parameterNode(m.(AmdModule).getDefine().getExportsParameter())
807838
}
839+
840+
Module getModule() { result = m }
808841
}
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
| lib/utils.js:1:38:1:120 | /* use ... )))) */ | def (member util (member exports (module reexport))) has no outgoing edge labelled member id; it has no outgoing edges at all. |

javascript/ql/test/ApiGraphs/reexport/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ const impl = require("./lib/impl.js");
22

33
module.exports = {
44
impl,
5-
util: require("./lib/utils")
6-
};
5+
util: require("./lib/utils"),
6+
other: require("./lib/stuff"),
7+
util2: require("./lib/utils2")
8+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function foo(x) { /* use (parameter 0 (member bar (member other (member exports (module reexport)))) */
2+
return x + 1;
3+
}
4+
5+
export const bar = foo;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
id: function id(x) { /* use (parameter 0 (member id (member util2 (member exports (module reexport)))) */
3+
return x;
4+
}
5+
};

0 commit comments

Comments
 (0)