Skip to content

Commit 47e0cd3

Browse files
committed
JS: Apply forceLocal overlay trick to API graphs
1 parent 7a9b780 commit 47e0cd3

File tree

1 file changed

+146
-8
lines changed

1 file changed

+146
-8
lines changed

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

Lines changed: 146 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,10 @@ module API {
784784

785785
private predicate hasSemantics(DataFlow::Node nd) { not nd.getTopLevel().isExterns() }
786786

787+
bindingset[nd]
788+
pragma[inline_late]
789+
private predicate hasSemanticsLate(DataFlow::Node nd) { hasSemantics(nd) }
790+
787791
private signature module StageInputSig {
788792
/** Holds if `node` should be seen as a use-node root, in addition to module imports (which are the usual roots). */
789793
predicate isAdditionalUseRoot(Node node);
@@ -1272,9 +1276,13 @@ module API {
12721276
nd = MkUse(ref)
12731277
or
12741278
S::isAdditionalUseRoot(nd) and
1275-
nd = MkUse(ref)
1279+
nd = mkUseLate(ref)
12761280
}
12771281

1282+
bindingset[node]
1283+
pragma[inline_late]
1284+
private TApiNode mkUseLate(DataFlow::Node node) { result = MkUse(node) }
1285+
12781286
private import semmle.javascript.dataflow.TypeTracking
12791287

12801288
/**
@@ -1365,6 +1373,13 @@ module API {
13651373
result = trackUseNode(nd, false, 0, "")
13661374
}
13671375

1376+
/**
1377+
* Gets a node whose forward tracking reaches `nd` in some state (e.g. possibly inside a content at this point).
1378+
*/
1379+
DataFlow::SourceNode trackUseNodeAnyState(DataFlow::SourceNode nd) {
1380+
result = trackUseNode(nd, _, _, _, _)
1381+
}
1382+
13681383
private DataFlow::SourceNode trackDefNode(DataFlow::Node nd, DataFlow::TypeBackTracker t) {
13691384
t.start() and
13701385
rhs(_, nd) and
@@ -1415,6 +1430,11 @@ module API {
14151430
result = trackDefNode(nd, DataFlow::TypeBackTracker::end())
14161431
}
14171432

1433+
/**
1434+
* Gets a node reached by the backwards tracking of `nd` in some state (e.g. possibly inside a content at this point).
1435+
*/
1436+
DataFlow::SourceNode trackDefNodeAnyState(DataFlow::Node nd) { result = trackDefNode(nd, _) }
1437+
14181438
private DataFlow::SourceNode awaited(DataFlow::InvokeNode call, DataFlow::TypeTracker t) {
14191439
t.startInPromise() and
14201440
trackUseNode(_, true, _, "").flowsTo(call.getCalleeNode()) and
@@ -1514,36 +1534,154 @@ module API {
15141534
pragma[inline]
15151535
predicate isAdditionalDefRoot(Node node) { none() }
15161536

1537+
overlay[local]
1538+
private predicate isOverlay() { databaseMetadata("isOverlay", "true") }
1539+
15171540
bindingset[node]
1518-
predicate inScope(DataFlow::Node node) { any() }
1541+
predicate inScope(DataFlow::Node node) { not isOverlay() and exists(node) }
15191542
}
15201543

15211544
private module Stage1 = Stage<Stage1Input>;
15221545

1546+
overlay[local]
1547+
private module Stage1Local {
1548+
predicate use(TApiNode node, DataFlow::Node ref) = forceLocal(Stage1::use/2)(node, ref)
1549+
1550+
predicate rhs(TApiNode node, DataFlow::Node def) = forceLocal(Stage1::rhs/2)(node, def)
1551+
1552+
DataFlow::SourceNode trackUseNode(DataFlow::SourceNode nd) =
1553+
forceLocal(Stage1::trackUseNode/1)(nd, result)
1554+
1555+
DataFlow::SourceNode trackUseNodeAnyState(DataFlow::SourceNode nd) =
1556+
forceLocal(Stage1::trackUseNodeAnyState/1)(nd, result)
1557+
1558+
DataFlow::SourceNode trackDefNode(DataFlow::SourceNode nd) =
1559+
forceLocal(Stage1::trackDefNode/1)(nd, result)
1560+
1561+
DataFlow::SourceNode trackDefNodeAnyState(DataFlow::Node nd) =
1562+
forceLocal(Stage1::trackDefNodeAnyState/1)(nd, result)
1563+
1564+
predicate edge(TApiNode pred, Label::ApiLabel lbl, TApiNode succ) =
1565+
forceLocal(Stage1::edge/3)(pred, lbl, succ)
1566+
1567+
DataFlow::InvokeNode getAPromisifiedInvocation(TApiNode callee, int bound, TApiNode succ) =
1568+
forceLocal(Stage1::getAPromisifiedInvocation/3)(callee, bound, succ, result)
1569+
}
1570+
1571+
private module Stage2Input implements StageInputSig {
1572+
overlay[global]
1573+
pragma[nomagic]
1574+
private predicate isInOverlayChangedFile(DataFlow::Node node) {
1575+
overlayChangedFiles(node.getFile().getAbsolutePath())
1576+
}
1577+
1578+
bindingset[node]
1579+
overlay[global]
1580+
pragma[inline_late]
1581+
private predicate isInOverlayChangedFileLate(DataFlow::Node node) {
1582+
isInOverlayChangedFile(node)
1583+
}
1584+
1585+
/** Holds if there is a step `node1 -> node2` from an unchanged file into a changed file. */
1586+
pragma[nomagic]
1587+
private predicate stepIntoOverlay(DataFlow::Node node1, DataFlow::Node node2) {
1588+
StepSummary::step(node1, node2, _) and
1589+
isInOverlayChangedFile(node2) and
1590+
not isInOverlayChangedFileLate(node1) and
1591+
hasSemanticsLate(node1)
1592+
}
1593+
1594+
/** Holds if use-node tracking starting at `nd` can reach a node in the overlay. */
1595+
pragma[nomagic]
1596+
private predicate shouldTrackIntoOverlay(DataFlow::SourceNode nd) {
1597+
exists(DataFlow::Node overlayNode |
1598+
stepIntoOverlay(Stage1Local::trackUseNodeAnyState(nd), overlayNode)
1599+
)
1600+
}
1601+
1602+
/** Holds if `node` should be tracked as a use-node in stage 2. */
1603+
pragma[nomagic]
1604+
predicate isAdditionalUseRoot(Node node) {
1605+
exists(DataFlow::Node ref |
1606+
shouldTrackIntoOverlay(ref) and
1607+
Stage1Local::use(node, ref)
1608+
)
1609+
}
1610+
1611+
/** Holds if there is a step `node1 -> node2` from a changed file into an unchanged file. */
1612+
pragma[nomagic]
1613+
private predicate stepOutOfOverlay(DataFlow::Node node1, DataFlow::Node node2) {
1614+
StepSummary::step(node1, node2, _) and
1615+
isInOverlayChangedFile(node1) and
1616+
not isInOverlayChangedFileLate(node2) and
1617+
hasSemanticsLate(node2)
1618+
}
1619+
1620+
/** Holds if def-node tracking starting at `nd` can reach a node in the overlay. */
1621+
pragma[nomagic]
1622+
private predicate shouldBacktrackIntoOverlay(DataFlow::SourceNode nd) {
1623+
exists(DataFlow::Node overlayNode |
1624+
stepOutOfOverlay(overlayNode, Stage1Local::trackDefNodeAnyState(nd))
1625+
)
1626+
}
1627+
1628+
/** Holds if `node` should be tracked as a def-node in stage 2. */
1629+
pragma[nomagic]
1630+
predicate isAdditionalDefRoot(Node node) {
1631+
exists(DataFlow::Node def |
1632+
shouldBacktrackIntoOverlay(def) and
1633+
Stage1Local::rhs(node, def)
1634+
)
1635+
}
1636+
1637+
bindingset[node]
1638+
predicate inScope(DataFlow::Node node) { isInOverlayChangedFile(node) }
1639+
}
1640+
1641+
private module Stage2 = Stage<Stage2Input>;
1642+
15231643
cached
15241644
private module Cached {
15251645
cached
1526-
predicate rhs(TApiNode nd, DataFlow::Node rhs) { Stage1::rhs(nd, rhs) }
1646+
predicate rhs(TApiNode nd, DataFlow::Node rhs) {
1647+
Stage1Local::rhs(nd, rhs)
1648+
or
1649+
Stage2::rhs(nd, rhs)
1650+
}
15271651

15281652
cached
1529-
predicate use(TApiNode nd, DataFlow::Node ref) { Stage1::use(nd, ref) }
1653+
predicate use(TApiNode nd, DataFlow::Node ref) {
1654+
Stage1Local::use(nd, ref)
1655+
or
1656+
Stage2::use(nd, ref)
1657+
}
15301658

15311659
cached
15321660
DataFlow::SourceNode trackUseNode(DataFlow::SourceNode nd) {
1533-
result = Stage1::trackUseNode(nd)
1661+
result = Stage1Local::trackUseNode(nd)
1662+
or
1663+
result = Stage2::trackUseNode(nd)
15341664
}
15351665

15361666
cached
1537-
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) { result = Stage1::trackDefNode(nd) }
1667+
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) {
1668+
result = Stage1Local::trackDefNode(nd)
1669+
or
1670+
result = Stage2::trackDefNode(nd)
1671+
}
15381672

15391673
cached
15401674
predicate edge(TApiNode pred, Label::ApiLabel lbl, TApiNode succ) {
1541-
Stage1::edge(pred, lbl, succ)
1675+
Stage1Local::edge(pred, lbl, succ)
1676+
or
1677+
Stage2::edge(pred, lbl, succ)
15421678
}
15431679

15441680
cached
15451681
DataFlow::InvokeNode getAPromisifiedInvocation(TApiNode callee, int bound, TApiNode succ) {
1546-
result = Stage1::getAPromisifiedInvocation(callee, bound, succ)
1682+
result = Stage1Local::getAPromisifiedInvocation(callee, bound, succ)
1683+
or
1684+
result = Stage2::getAPromisifiedInvocation(callee, bound, succ)
15471685
}
15481686
}
15491687

0 commit comments

Comments
 (0)