Skip to content

Commit 440ef34

Browse files
committed
JS: Parameterise the module (still only one instantiation)
1 parent 785e2ec commit 440ef34

1 file changed

Lines changed: 71 additions & 28 deletions

File tree

javascript/ql/lib/semmle/javascript/ApiGraphs.qll

Lines changed: 71 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -784,17 +784,6 @@ module API {
784784
} or
785785
MkSyntheticCallbackArg(DataFlow::InvokeNode nd)
786786

787-
private predicate needsDefNode(DataFlow::ClassNode cls) {
788-
hasSemantics(cls) and
789-
(
790-
cls = trackDefNode(_)
791-
or
792-
cls.getAnInstanceReference() = trackDefNode(_)
793-
or
794-
needsDefNode(cls.getADirectSubClass())
795-
)
796-
}
797-
798787
class TDef = MkModuleDef or TNonModuleDef;
799788

800789
class TNonModuleDef = MkModuleExport or MkClassInstance or MkDef or MkSyntheticCallbackArg;
@@ -811,8 +800,26 @@ module API {
811800
hasSemantics(imp)
812801
}
813802

803+
private signature module StageInputSig {
804+
/** Holds if `node` should be seen as a use-node root, in addition to module imports (which are the usual roots). */
805+
predicate isAdditionalUseRoot(Node node);
806+
807+
/** Holds if `node` should be seen as a def-node root, in addition to module exports (which are the usual roots). */
808+
predicate isAdditionalDefRoot(Node node);
809+
810+
/**
811+
* Holds if `node` is considered "in scope" for this stage, meaning that we allow outgoing labelled edges
812+
* to be materialised from here, and continue API graph construction from the successors edges.
813+
*
814+
* Note that the "additional roots" contributed by the stage inputs may be out of scope but can be tracked to a node in scope.
815+
* This predicate should thus not be used to block the tracking of use/def nodes, but only block the creation of new labelled edges.
816+
*/
817+
bindingset[node]
818+
predicate inScope(DataFlow::Node node);
819+
}
820+
814821
cached
815-
private module Stage {
822+
private module Stage<StageInputSig S> {
816823
/**
817824
* Holds if `rhs` is the right-hand side of a definition of a node that should have an
818825
* incoming edge from `base` labeled `lbl` in the API graph.
@@ -1005,9 +1012,11 @@ module API {
10051012
*/
10061013
cached
10071014
predicate rhs(TApiNode nd, DataFlow::Node rhs) {
1015+
(S::inScope(rhs) or S::isAdditionalDefRoot(nd)) and
10081016
exists(string m | nd = MkModuleExport(m) | exports(m, rhs))
10091017
or
10101018
rhs(_, _, rhs) and
1019+
S::inScope(rhs) and
10111020
nd = MkDef(rhs)
10121021
}
10131022

@@ -1058,7 +1067,8 @@ module API {
10581067
base = MkRoot() and
10591068
exists(EntryPoint e |
10601069
lbl = Label::entryPoint(e) and
1061-
ref = e.getASource()
1070+
ref = e.getASource() and
1071+
S::inScope(ref)
10621072
)
10631073
or
10641074
// property reads
@@ -1230,35 +1240,57 @@ module API {
12301240
)
12311241
}
12321242

1243+
private predicate needsDefNode(DataFlow::ClassNode cls) {
1244+
hasSemantics(cls) and
1245+
(
1246+
cls = trackDefNode(_)
1247+
or
1248+
cls.getAnInstanceReference() = trackDefNode(_)
1249+
or
1250+
needsDefNode(cls.getADirectSubClass())
1251+
or
1252+
S::isAdditionalDefRoot(MkClassInstance(cls))
1253+
or
1254+
S::isAdditionalUseRoot(MkClassInstance(cls)) // These are also tracked as use-nodes
1255+
)
1256+
}
1257+
12331258
/**
12341259
* Holds if `ref` is a use of node `nd`.
12351260
*/
12361261
cached
12371262
predicate use(TApiNode nd, DataFlow::Node ref) {
1238-
exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) |
1239-
ref = DataFlow::moduleVarNode(mod)
1240-
)
1241-
or
1242-
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
1243-
ref = DataFlow::exportsVarNode(mod)
1263+
(S::inScope(ref) or S::isAdditionalUseRoot(nd)) and
1264+
(
1265+
exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) |
1266+
ref = DataFlow::moduleVarNode(mod)
1267+
)
12441268
or
1245-
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
1246-
ref = trackUseNode(base).getAPropertyRead("exports")
1269+
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
1270+
ref = DataFlow::exportsVarNode(mod)
1271+
or
1272+
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
1273+
ref = trackUseNode(base).getAPropertyRead("exports")
1274+
)
1275+
)
1276+
or
1277+
exists(string m |
1278+
nd = MkModuleImport(m) and
1279+
ref = DataFlow::moduleImport(m)
12471280
)
12481281
)
12491282
or
1250-
exists(string m |
1251-
nd = MkModuleImport(m) and
1252-
ref = DataFlow::moduleImport(m)
1253-
)
1254-
or
1255-
exists(DataFlow::ClassNode cls | nd = MkClassInstance(cls) |
1283+
exists(DataFlow::ClassNode cls | nd = MkClassInstance(cls) and needsDefNode(cls) |
12561284
ref = cls.getAReceiverNode()
12571285
or
12581286
ref = cls.(DataFlow::ClassNode).getAPrototypeReference()
12591287
)
12601288
or
12611289
use(_, _, ref) and
1290+
S::inScope(ref) and
1291+
nd = MkUse(ref)
1292+
or
1293+
S::isAdditionalUseRoot(nd) and
12621294
nd = MkUse(ref)
12631295
}
12641296

@@ -1498,7 +1530,18 @@ module API {
14981530
}
14991531
}
15001532

1501-
import Stage
1533+
private module Stage1Input implements StageInputSig {
1534+
pragma[inline]
1535+
predicate isAdditionalUseRoot(Node node) { none() }
1536+
1537+
pragma[inline]
1538+
predicate isAdditionalDefRoot(Node node) { none() }
1539+
1540+
bindingset[node]
1541+
predicate inScope(DataFlow::Node node) { any() }
1542+
}
1543+
1544+
import Stage<Stage1Input>
15021545

15031546
/**
15041547
* Holds if there is an edge from `pred` to `succ` in the API graph.

0 commit comments

Comments
 (0)