Skip to content

Commit 9c37e07

Browse files
committed
JS: Add overlay-specific Stage2
1 parent 1001e86 commit 9c37e07

1 file changed

Lines changed: 100 additions & 6 deletions

File tree

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

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,10 @@ module API {
792792

793793
private predicate hasSemantics(DataFlow::Node nd) { not nd.getTopLevel().isExterns() }
794794

795+
bindingset[nd]
796+
pragma[inline_late]
797+
private predicate hasSemanticsLate(DataFlow::Node nd) { hasSemantics(nd) }
798+
795799
private signature module StageInputSig {
796800
/** Holds if `node` should be seen as a use-node root, in addition to module imports (which are the usual roots). */
797801
predicate isAdditionalUseRoot(Node node);
@@ -1583,30 +1587,120 @@ module API {
15831587
forceLocal(Stage1::getAPromisifiedInvocation/3)(callee, bound, succ, result)
15841588
}
15851589

1590+
private module Stage2Input implements StageInputSig {
1591+
overlay[global]
1592+
pragma[nomagic]
1593+
private predicate isInOverlayChangedFile(DataFlow::Node node) {
1594+
overlayChangedFiles(node.getFile().getAbsolutePath())
1595+
}
1596+
1597+
bindingset[node]
1598+
overlay[global]
1599+
pragma[inline_late]
1600+
private predicate isInOverlayChangedFileLate(DataFlow::Node node) {
1601+
isInOverlayChangedFile(node)
1602+
}
1603+
1604+
/** Holds if there is a step `node1 -> node2` from an unchanged file into a changed file. */
1605+
pragma[nomagic]
1606+
private predicate stepIntoOverlay(DataFlow::Node node1, DataFlow::Node node2) {
1607+
StepSummary::step(node1, node2, _) and
1608+
isInOverlayChangedFile(node2) and
1609+
not isInOverlayChangedFileLate(node1) and
1610+
hasSemanticsLate(node1)
1611+
}
1612+
1613+
/** Holds if use-node tracking starting at `nd` can reach a node in the overlay. */
1614+
pragma[nomagic]
1615+
private predicate shouldTrackIntoOverlay(DataFlow::SourceNode nd) {
1616+
exists(DataFlow::Node overlayNode |
1617+
stepIntoOverlay(Stage1Local::trackUseNodeAnyState(nd), overlayNode)
1618+
)
1619+
}
1620+
1621+
/** Holds if `node` should be tracked as a use-node in stage 2. */
1622+
pragma[nomagic]
1623+
predicate isAdditionalUseRoot(Node node) {
1624+
exists(DataFlow::Node ref |
1625+
shouldTrackIntoOverlay(ref) and
1626+
Stage1Local::use(node, ref)
1627+
)
1628+
}
1629+
1630+
/** Holds if there is a step `node1 -> node2` from a changed file into an unchanged file. */
1631+
pragma[nomagic]
1632+
private predicate stepOutOfOverlay(DataFlow::Node node1, DataFlow::Node node2) {
1633+
StepSummary::step(node1, node2, _) and
1634+
isInOverlayChangedFile(node1) and
1635+
not isInOverlayChangedFileLate(node2) and
1636+
hasSemanticsLate(node2)
1637+
}
1638+
1639+
/** Holds if def-node tracking starting at `nd` can reach a node in the overlay. */
1640+
pragma[nomagic]
1641+
private predicate shouldBacktrackIntoOverlay(DataFlow::Node nd) {
1642+
exists(DataFlow::Node overlayNode |
1643+
stepOutOfOverlay(overlayNode, Stage1Local::trackDefNodeAnyState(nd))
1644+
)
1645+
}
1646+
1647+
/** Holds if `node` should be tracked as a def-node in stage 2. */
1648+
pragma[nomagic]
1649+
predicate isAdditionalDefRoot(Node node) {
1650+
exists(DataFlow::Node def |
1651+
shouldBacktrackIntoOverlay(def) and
1652+
Stage1Local::rhs(node, def)
1653+
)
1654+
}
1655+
1656+
bindingset[node]
1657+
predicate inScope(DataFlow::Node node) { isInOverlayChangedFile(node) }
1658+
}
1659+
1660+
private module Stage2 = Stage<Stage2Input>;
1661+
15861662
cached
15871663
private module Cached {
15881664
cached
1589-
predicate rhs(TApiNode nd, DataFlow::Node rhs) { Stage1::rhs(nd, rhs) }
1665+
predicate rhs(TApiNode nd, DataFlow::Node rhs) {
1666+
Stage1Local::rhs(nd, rhs)
1667+
or
1668+
Stage2::rhs(nd, rhs)
1669+
}
15901670

15911671
cached
1592-
predicate use(TApiNode nd, DataFlow::Node ref) { Stage1::use(nd, ref) }
1672+
predicate use(TApiNode nd, DataFlow::Node ref) {
1673+
Stage1Local::use(nd, ref)
1674+
or
1675+
Stage2::use(nd, ref)
1676+
}
15931677

15941678
cached
15951679
DataFlow::SourceNode trackUseNode(DataFlow::SourceNode nd) {
1596-
result = Stage1::trackUseNode(nd)
1680+
result = Stage1Local::trackUseNode(nd)
1681+
or
1682+
result = Stage2::trackUseNode(nd)
15971683
}
15981684

15991685
cached
1600-
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) { result = Stage1::trackDefNode(nd) }
1686+
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) {
1687+
result = Stage1Local::trackDefNode(nd)
1688+
or
1689+
result = Stage2::trackDefNode(nd)
1690+
}
16011691

16021692
cached
16031693
predicate edge(TApiNode pred, Label::ApiLabel lbl, TApiNode succ) {
1604-
Stage1::edge(pred, lbl, succ)
1694+
Stage1Local::edge(pred, lbl, succ)
1695+
or
1696+
Stage2::edge(pred, lbl, succ)
16051697
}
16061698

16071699
cached
16081700
DataFlow::InvokeNode getAPromisifiedInvocation(TApiNode callee, int bound, TApiNode succ) {
1609-
result = Stage1::getAPromisifiedInvocation(callee, bound, succ)
1701+
result = Stage1Local::getAPromisifiedInvocation(callee, bound, succ)
1702+
or
1703+
result = Stage2::getAPromisifiedInvocation(callee, bound, succ)
16101704
}
16111705
}
16121706

0 commit comments

Comments
 (0)