@@ -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