Skip to content

Commit cf0b770

Browse files
committed
JS: Workaround forceLocal not supporting 'result' column
A bug made it into the release which causes compilation errors when forceLocal is used on a predicate with a result column. This commit works around the issue by converting the result column to a positional parameter, for the predicates that we use forceLocal on. It should be safe to revert this commit once the compiler fix has made it into a stable release.
1 parent e16cacd commit cf0b770

File tree

1 file changed

+78
-63
lines changed

1 file changed

+78
-63
lines changed

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

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ module API {
132132
*/
133133
pragma[inline]
134134
DataFlow::Node getAValueReachableFromSource() {
135-
Impl::trackUseNode(this.asSource()).flowsTo(result)
135+
Impl::trackUseNode(this.asSource(), result.getALocalSource())
136136
}
137137

138138
/**
@@ -171,7 +171,7 @@ module API {
171171
CallNode getMaybePromisifiedCall() {
172172
result = this.getACall()
173173
or
174-
result = Impl::getAPromisifiedInvocation(this, _, _)
174+
Impl::getAPromisifiedInvocation(this, _, _, result)
175175
}
176176

177177
/**
@@ -210,7 +210,7 @@ module API {
210210
* This is similar to `asSink()` but additionally includes nodes that transitively reach a sink by data flow.
211211
* See `asSink()` for examples.
212212
*/
213-
DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) }
213+
DataFlow::Node getAValueReachingSink() { Impl::trackDefNode(this.asSink(), result) }
214214

215215
/**
216216
* Gets a node representing member `m` of this API component.
@@ -855,7 +855,7 @@ module API {
855855
)
856856
or
857857
exists(DataFlow::Node def, DataFlow::SourceNode pred |
858-
rhs(base, def) and pred = trackDefNode(def)
858+
rhs(base, def) and trackDefNode(def, pred)
859859
|
860860
// from `x` to a definition of `x.prop`
861861
exists(DataFlow::PropWrite pw | pw = pred.getAPropertyWrite() |
@@ -956,8 +956,11 @@ module API {
956956
lbl = Label::spreadArgument(i)
957957
)
958958
or
959-
exists(DataFlow::SourceNode src, DataFlow::PropWrite pw |
960-
use(base, src) and pw = trackUseNode(src).getAPropertyWrite() and rhs = pw.getRhs()
959+
exists(DataFlow::SourceNode src, DataFlow::SourceNode mid, DataFlow::PropWrite pw |
960+
use(base, src) and
961+
trackUseNode(src, mid) and
962+
pw = mid.getAPropertyWrite() and
963+
rhs = pw.getRhs()
961964
|
962965
lbl = Label::memberFromRef(pw)
963966
)
@@ -1099,7 +1102,7 @@ module API {
10991102
)
11001103
or
11011104
exists(DataFlow::SourceNode src, DataFlow::SourceNode pred |
1102-
use(base, src) and pred = trackUseNode(src)
1105+
use(base, src) and trackUseNode(src, pred)
11031106
|
11041107
lbl = Label::instance() and
11051108
ref = pred.getAnInstantiation()
@@ -1133,7 +1136,7 @@ module API {
11331136
)
11341137
or
11351138
exists(DataFlow::Node def, DataFlow::FunctionNode fn |
1136-
rhs(base, def) and fn = trackDefNode(def)
1139+
rhs(base, def) and trackDefNode(def, fn)
11371140
|
11381141
exists(int i |
11391142
lbl = Label::parameter(i) and
@@ -1145,7 +1148,7 @@ module API {
11451148
)
11461149
or
11471150
exists(DataFlow::Node def, DataFlow::ClassNode cls, int i |
1148-
rhs(base, def) and cls = trackDefNode(def)
1151+
rhs(base, def) and trackDefNode(def, cls)
11491152
|
11501153
lbl = Label::parameter(i) and
11511154
ref = cls.getConstructor().getParameter(i)
@@ -1188,7 +1191,7 @@ module API {
11881191
private predicate useNodeFlowsToDecorator(TApiNode base, Decorator decorator) {
11891192
exists(DataFlow::SourceNode decoratorSrc |
11901193
use(base, decoratorSrc) and
1191-
trackUseNode(decoratorSrc).flowsToExpr(decorator.getExpression())
1194+
trackUseNode(decoratorSrc, decorator.getExpression().flow().getALocalSource())
11921195
)
11931196
}
11941197

@@ -1271,9 +1274,9 @@ module API {
12711274
private predicate needsDefNode(DataFlow::ClassNode cls) {
12721275
hasSemantics(cls) and
12731276
(
1274-
cls = trackDefNode(_)
1277+
trackDefNode(_, cls)
12751278
or
1276-
cls.getAnInstanceReference() = trackDefNode(_)
1279+
trackDefNode(_, cls.getAnInstanceReference())
12771280
or
12781281
needsDefNode(cls.getADirectSubClass())
12791282
or
@@ -1296,8 +1299,8 @@ module API {
12961299
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
12971300
ref = DataFlow::exportsVarNode(mod)
12981301
or
1299-
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
1300-
ref = trackUseNode(base).getAPropertyRead("exports")
1302+
exists(DataFlow::Node base, DataFlow::SourceNode mid | use(MkModuleDef(m), base) |
1303+
trackUseNode(base, mid) and ref = mid.getAPropertyRead("exports")
13011304
)
13021305
)
13031306
or
@@ -1415,34 +1418,36 @@ module API {
14151418
}
14161419

14171420
/**
1418-
* Gets a node that is inter-procedurally reachable from `nd`, which is a use of some node.
1421+
* Holds if `target` is inter-procedurally reachable from `nd`, which is a use of some node.
14191422
*/
1420-
DataFlow::SourceNode trackUseNode(DataFlow::SourceNode nd) {
1421-
result = trackUseNode(nd, false, 0, "")
1423+
predicate trackUseNode(DataFlow::SourceNode nd, DataFlow::SourceNode target) {
1424+
target = trackUseNode(nd, false, 0, "")
14221425
}
14231426

14241427
/**
14251428
* Gets a node whose forward tracking reaches `nd` in some state (e.g. possibly inside a content at this point).
14261429
*/
1427-
DataFlow::SourceNode trackUseNodeAnyState(DataFlow::SourceNode nd) {
1428-
result = trackUseNode(nd, _, _, _, _)
1430+
predicate trackUseNodeAnyState(DataFlow::SourceNode nd, DataFlow::SourceNode target) {
1431+
target = trackUseNode(nd, _, _, _, _)
14291432
}
14301433

1431-
private DataFlow::SourceNode trackDefNode(DataFlow::Node nd, DataFlow::TypeBackTracker t) {
1434+
private predicate trackDefNode(
1435+
DataFlow::Node nd, DataFlow::TypeBackTracker t, DataFlow::SourceNode target
1436+
) {
14321437
t.start() and
14331438
rhs(_, nd) and
1434-
result = nd.getALocalSource()
1439+
target = nd.getALocalSource()
14351440
or
14361441
// additional backwards step from `require('m')` to `exports` or `module.exports` in m
1437-
exists(Import imp | imp.getImportedModuleNodeStrict() = trackDefNode(nd, t.continue()) |
1438-
result = DataFlow::exportsVarNode(imp.getImportedModule())
1442+
exists(Import imp | trackDefNode(nd, t.continue(), imp.getImportedModuleNodeStrict()) |
1443+
target = DataFlow::exportsVarNode(imp.getImportedModule())
14391444
or
1440-
result = DataFlow::moduleVarNode(imp.getImportedModule()).getAPropertyRead("exports")
1445+
target = DataFlow::moduleVarNode(imp.getImportedModule()).getAPropertyRead("exports")
14411446
)
14421447
or
14431448
exists(ObjectExpr obj |
1444-
obj = trackDefNode(nd, t.continue()).asExpr() and
1445-
result =
1449+
trackDefNode(nd, t.continue(), obj.flow()) and
1450+
target =
14461451
obj.getAProperty()
14471452
.(SpreadProperty)
14481453
.getInit()
@@ -1452,7 +1457,7 @@ module API {
14521457
.getALocalSource()
14531458
)
14541459
or
1455-
t = defStep(nd, result)
1460+
t = defStep(nd, target)
14561461
}
14571462

14581463
/**
@@ -1465,7 +1470,7 @@ module API {
14651470
pragma[noopt]
14661471
private DataFlow::TypeBackTracker defStep(DataFlow::Node nd, DataFlow::SourceNode prev) {
14671472
exists(DataFlow::TypeBackTracker t, StepSummary summary, DataFlow::Node next |
1468-
next = trackDefNode(nd, t) and
1473+
trackDefNode(nd, t, next) and
14691474
StepSummary::step(prev, next, summary) and
14701475
result = t.prepend(summary) and
14711476
// Block argument-passing into 'this' when it determines the call target
@@ -1474,16 +1479,18 @@ module API {
14741479
}
14751480

14761481
/**
1477-
* Gets a node that inter-procedurally flows into `nd`, which is a definition of some node.
1482+
* Holds if `target` inter-procedurally flows into `nd`, which is a definition of some node.
14781483
*/
1479-
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) {
1480-
result = trackDefNode(nd, DataFlow::TypeBackTracker::end())
1484+
predicate trackDefNode(DataFlow::Node nd, DataFlow::SourceNode target) {
1485+
trackDefNode(nd, DataFlow::TypeBackTracker::end(), target)
14811486
}
14821487

14831488
/**
14841489
* Gets a node reached by the backwards tracking of `nd` in some state (e.g. possibly inside a content at this point).
14851490
*/
1486-
DataFlow::SourceNode trackDefNodeAnyState(DataFlow::Node nd) { result = trackDefNode(nd, _) }
1491+
predicate trackDefNodeAnyState(DataFlow::Node nd, DataFlow::SourceNode target) {
1492+
trackDefNode(nd, _, target)
1493+
}
14871494

14881495
private DataFlow::SourceNode awaited(DataFlow::InvokeNode call, DataFlow::TypeTracker t) {
14891496
t.startInPromise() and
@@ -1539,10 +1546,11 @@ module API {
15391546
)
15401547
)
15411548
or
1542-
exists(DataFlow::Node def |
1549+
exists(DataFlow::Node def, DataFlow::Node mid |
15431550
rhs(pred, def) and
15441551
lbl = Label::instance() and
1545-
succ = MkClassInstance(trackDefNode(def))
1552+
trackDefNode(def, mid) and
1553+
succ = MkClassInstance(mid)
15461554
)
15471555
or
15481556
exists(string moduleName, string exportName |
@@ -1554,26 +1562,28 @@ module API {
15541562
exists(DataFlow::Node nd, DataFlow::FunctionNode f |
15551563
f.getFunction().isAsync() and
15561564
pred = MkDef(nd) and
1557-
f = trackDefNode(nd) and
1565+
trackDefNode(nd, f) and
15581566
lbl = Label::return() and
15591567
succ = MkDef(f.getReturnNode())
15601568
)
15611569
or
15621570
exists(int bound, DataFlow::InvokeNode call |
15631571
lbl = Label::parameter(bound + call.getNumArgument()) and
1564-
call = getAPromisifiedInvocation(pred, bound, succ)
1572+
getAPromisifiedInvocation(pred, bound, succ, call)
15651573
)
15661574
}
15671575

15681576
/**
15691577
* Gets a call to a promisified function represented by `callee` where
15701578
* `bound` arguments have been bound.
15711579
*/
1572-
DataFlow::InvokeNode getAPromisifiedInvocation(TApiNode callee, int bound, TApiNode succ) {
1580+
predicate getAPromisifiedInvocation(
1581+
TApiNode callee, int bound, TApiNode succ, DataFlow::InvokeNode invoke
1582+
) {
15731583
exists(DataFlow::SourceNode src |
15741584
use(callee, src) and
1575-
trackUseNode(src, true, bound, "").flowsTo(result.getCalleeNode()) and
1576-
succ = Impl::MkSyntheticCallbackArg(result)
1585+
trackUseNode(src, true, bound, "").flowsTo(invoke.getCalleeNode()) and
1586+
succ = Impl::MkSyntheticCallbackArg(invoke)
15771587
)
15781588
}
15791589
}
@@ -1606,23 +1616,24 @@ module API {
16061616

16071617
predicate rhs(TApiNode node, DataFlow::Node def) = forceLocal(Stage1::rhs/2)(node, def)
16081618

1609-
DataFlow::SourceNode trackUseNode(DataFlow::SourceNode nd) =
1610-
forceLocal(Stage1::trackUseNode/1)(nd, result)
1619+
predicate trackUseNode(DataFlow::SourceNode nd, DataFlow::SourceNode target) =
1620+
forceLocal(Stage1::trackUseNode/2)(nd, target)
16111621

1612-
DataFlow::SourceNode trackUseNodeAnyState(DataFlow::SourceNode nd) =
1613-
forceLocal(Stage1::trackUseNodeAnyState/1)(nd, result)
1622+
predicate trackUseNodeAnyState(DataFlow::SourceNode nd, DataFlow::SourceNode target) =
1623+
forceLocal(Stage1::trackUseNodeAnyState/2)(nd, target)
16141624

1615-
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) =
1616-
forceLocal(Stage1::trackDefNode/1)(nd, result)
1625+
predicate trackDefNode(DataFlow::Node nd, DataFlow::SourceNode target) =
1626+
forceLocal(Stage1::trackDefNode/2)(nd, target)
16171627

1618-
DataFlow::SourceNode trackDefNodeAnyState(DataFlow::Node nd) =
1619-
forceLocal(Stage1::trackDefNodeAnyState/1)(nd, result)
1628+
predicate trackDefNodeAnyState(DataFlow::Node nd, DataFlow::SourceNode target) =
1629+
forceLocal(Stage1::trackDefNodeAnyState/2)(nd, target)
16201630

16211631
predicate edge(TApiNode pred, Label::ApiLabel lbl, TApiNode succ) =
16221632
forceLocal(Stage1::edge/3)(pred, lbl, succ)
16231633

1624-
DataFlow::InvokeNode getAPromisifiedInvocation(TApiNode callee, int bound, TApiNode succ) =
1625-
forceLocal(Stage1::getAPromisifiedInvocation/3)(callee, bound, succ, result)
1634+
predicate getAPromisifiedInvocation(
1635+
TApiNode callee, int bound, TApiNode succ, DataFlow::InvokeNode invoke
1636+
) = forceLocal(Stage1::getAPromisifiedInvocation/4)(callee, bound, succ, invoke)
16261637
}
16271638

16281639
private module Stage2Input implements StageInputSig {
@@ -1651,8 +1662,9 @@ module API {
16511662
/** Holds if use-node tracking starting at `nd` can reach a node in the overlay. */
16521663
pragma[nomagic]
16531664
private predicate shouldTrackIntoOverlay(DataFlow::SourceNode nd) {
1654-
exists(DataFlow::Node overlayNode |
1655-
stepIntoOverlay(Stage1Local::trackUseNodeAnyState(nd), overlayNode)
1665+
exists(DataFlow::Node mid |
1666+
Stage1Local::trackUseNodeAnyState(nd, mid) and
1667+
stepIntoOverlay(mid, _)
16561668
)
16571669
}
16581670

@@ -1677,8 +1689,9 @@ module API {
16771689
/** Holds if def-node tracking starting at `nd` can reach a node in the overlay. */
16781690
pragma[nomagic]
16791691
private predicate shouldBacktrackIntoOverlay(DataFlow::Node nd) {
1680-
exists(DataFlow::Node overlayNode |
1681-
stepOutOfOverlay(overlayNode, Stage1Local::trackDefNodeAnyState(nd))
1692+
exists(DataFlow::Node mid |
1693+
Stage1Local::trackDefNodeAnyState(nd, mid) and
1694+
stepOutOfOverlay(_, mid)
16821695
)
16831696
}
16841697

@@ -1714,17 +1727,17 @@ module API {
17141727
}
17151728

17161729
cached
1717-
DataFlow::SourceNode trackUseNode(DataFlow::SourceNode nd) {
1718-
result = Stage1Local::trackUseNode(nd)
1730+
predicate trackUseNode(DataFlow::SourceNode nd, DataFlow::SourceNode target) {
1731+
Stage1Local::trackUseNode(nd, target)
17191732
or
1720-
result = Stage2::trackUseNode(nd)
1733+
Stage2::trackUseNode(nd, target)
17211734
}
17221735

17231736
cached
1724-
DataFlow::SourceNode trackDefNode(DataFlow::Node nd) {
1725-
result = Stage1Local::trackDefNode(nd)
1737+
predicate trackDefNode(DataFlow::Node nd, DataFlow::SourceNode target) {
1738+
Stage1Local::trackDefNode(nd, target)
17261739
or
1727-
result = Stage2::trackDefNode(nd)
1740+
Stage2::trackDefNode(nd, target)
17281741
}
17291742

17301743
cached
@@ -1735,10 +1748,12 @@ module API {
17351748
}
17361749

17371750
cached
1738-
DataFlow::InvokeNode getAPromisifiedInvocation(TApiNode callee, int bound, TApiNode succ) {
1739-
result = Stage1Local::getAPromisifiedInvocation(callee, bound, succ)
1751+
predicate getAPromisifiedInvocation(
1752+
TApiNode callee, int bound, TApiNode succ, DataFlow::InvokeNode invoke
1753+
) {
1754+
Stage1Local::getAPromisifiedInvocation(callee, bound, succ, invoke)
17401755
or
1741-
result = Stage2::getAPromisifiedInvocation(callee, bound, succ)
1756+
Stage2::getAPromisifiedInvocation(callee, bound, succ, invoke)
17421757
}
17431758
}
17441759

@@ -1808,7 +1823,7 @@ module API {
18081823
InvokeNode() {
18091824
this = callee.getReturn().asSource() or
18101825
this = callee.getInstance().asSource() or
1811-
this = Impl::getAPromisifiedInvocation(callee, _, _)
1826+
Impl::getAPromisifiedInvocation(callee, _, _, this)
18121827
}
18131828

18141829
/** Gets the API node for the `i`th parameter of this invocation. */

0 commit comments

Comments
 (0)