Skip to content

Commit c23e501

Browse files
committed
JS: Parameterise the module (still only one instantiation)
1 parent 1964b38 commit c23e501

File tree

1 file changed

+71
-28
lines changed

1 file changed

+71
-28
lines changed

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

Lines changed: 71 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -778,17 +778,6 @@ module API {
778778
} or
779779
MkSyntheticCallbackArg(DataFlow::InvokeNode nd)
780780

781-
private predicate needsDefNode(DataFlow::ClassNode cls) {
782-
hasSemantics(cls) and
783-
(
784-
cls = trackDefNode(_)
785-
or
786-
cls.getAnInstanceReference() = trackDefNode(_)
787-
or
788-
needsDefNode(cls.getADirectSubClass())
789-
)
790-
}
791-
792781
class TDef = MkModuleDef or TNonModuleDef;
793782

794783
class TNonModuleDef = MkModuleExport or MkClassInstance or MkDef or MkSyntheticCallbackArg;
@@ -805,8 +794,26 @@ module API {
805794
hasSemantics(imp)
806795
}
807796

797+
private signature module StageInputSig {
798+
/** Holds if `node` should be seen as a use-node root, in addition to module imports (which are the usual roots). */
799+
predicate isAdditionalUseRoot(Node node);
800+
801+
/** Holds if `node` should be seen as a def-node root, in addition to module exports (which are the usual roots). */
802+
predicate isAdditionalDefRoot(Node node);
803+
804+
/**
805+
* Holds if `node` is considered "in scope" for this stage, meaning that we allow outgoing labelled edges
806+
* to be materialised from here, and continue API graph construction from the successors edges.
807+
*
808+
* Note that the "additional roots" contributed by the stage inputs may be out of scope but can be tracked to a node in scope.
809+
* This predicate should thus not be used to block the tracking of use/def nodes, but only block the creation of new labelled edges.
810+
*/
811+
bindingset[node]
812+
predicate inScope(DataFlow::Node node);
813+
}
814+
808815
cached
809-
private module Stage {
816+
private module Stage<StageInputSig S> {
810817
/**
811818
* Holds if `rhs` is the right-hand side of a definition of a node that should have an
812819
* incoming edge from `base` labeled `lbl` in the API graph.
@@ -999,9 +1006,11 @@ module API {
9991006
*/
10001007
cached
10011008
predicate rhs(TApiNode nd, DataFlow::Node rhs) {
1009+
(S::inScope(rhs) or S::isAdditionalDefRoot(nd)) and
10021010
exists(string m | nd = MkModuleExport(m) | exports(m, rhs))
10031011
or
10041012
rhs(_, _, rhs) and
1013+
S::inScope(rhs) and
10051014
nd = MkDef(rhs)
10061015
}
10071016

@@ -1052,7 +1061,8 @@ module API {
10521061
base = MkRoot() and
10531062
exists(EntryPoint e |
10541063
lbl = Label::entryPoint(e) and
1055-
ref = e.getASource()
1064+
ref = e.getASource() and
1065+
S::inScope(ref)
10561066
)
10571067
or
10581068
// property reads
@@ -1224,35 +1234,57 @@ module API {
12241234
)
12251235
}
12261236

1237+
private predicate needsDefNode(DataFlow::ClassNode cls) {
1238+
hasSemantics(cls) and
1239+
(
1240+
cls = trackDefNode(_)
1241+
or
1242+
cls.getAnInstanceReference() = trackDefNode(_)
1243+
or
1244+
needsDefNode(cls.getADirectSubClass())
1245+
or
1246+
S::isAdditionalDefRoot(MkClassInstance(cls))
1247+
or
1248+
S::isAdditionalUseRoot(MkClassInstance(cls)) // These are also tracked as use-nodes
1249+
)
1250+
}
1251+
12271252
/**
12281253
* Holds if `ref` is a use of node `nd`.
12291254
*/
12301255
cached
12311256
predicate use(TApiNode nd, DataFlow::Node ref) {
1232-
exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) |
1233-
ref = DataFlow::moduleVarNode(mod)
1234-
)
1235-
or
1236-
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
1237-
ref = DataFlow::exportsVarNode(mod)
1257+
(S::inScope(ref) or S::isAdditionalUseRoot(nd)) and
1258+
(
1259+
exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) |
1260+
ref = DataFlow::moduleVarNode(mod)
1261+
)
12381262
or
1239-
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
1240-
ref = trackUseNode(base).getAPropertyRead("exports")
1263+
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
1264+
ref = DataFlow::exportsVarNode(mod)
1265+
or
1266+
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
1267+
ref = trackUseNode(base).getAPropertyRead("exports")
1268+
)
1269+
)
1270+
or
1271+
exists(string m |
1272+
nd = MkModuleImport(m) and
1273+
ref = DataFlow::moduleImport(m)
12411274
)
12421275
)
12431276
or
1244-
exists(string m |
1245-
nd = MkModuleImport(m) and
1246-
ref = DataFlow::moduleImport(m)
1247-
)
1248-
or
1249-
exists(DataFlow::ClassNode cls | nd = MkClassInstance(cls) |
1277+
exists(DataFlow::ClassNode cls | nd = MkClassInstance(cls) and needsDefNode(cls) |
12501278
ref = cls.getAReceiverNode()
12511279
or
12521280
ref = cls.(DataFlow::ClassNode).getAPrototypeReference()
12531281
)
12541282
or
12551283
use(_, _, ref) and
1284+
S::inScope(ref) and
1285+
nd = MkUse(ref)
1286+
or
1287+
S::isAdditionalUseRoot(nd) and
12561288
nd = MkUse(ref)
12571289
}
12581290

@@ -1492,7 +1524,18 @@ module API {
14921524
}
14931525
}
14941526

1495-
import Stage
1527+
private module Stage1Input implements StageInputSig {
1528+
pragma[inline]
1529+
predicate isAdditionalUseRoot(Node node) { none() }
1530+
1531+
pragma[inline]
1532+
predicate isAdditionalDefRoot(Node node) { none() }
1533+
1534+
bindingset[node]
1535+
predicate inScope(DataFlow::Node node) { any() }
1536+
}
1537+
1538+
import Stage<Stage1Input>
14961539

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

0 commit comments

Comments
 (0)