Skip to content

Commit 25c3d8f

Browse files
committed
JS: Add more features to AdditionalFlowInternal
This lets us place some more logic outside of the giant DataFlowPrivate file
1 parent 93d0b41 commit 25c3d8f

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

Diff for: javascript/ql/lib/semmle/javascript/dataflow/internal/AdditionalFlowInternal.qll

+18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ DataFlow::Node getSynthesizedNode(AstNode node, string tag) {
99
result = TGenericSynthesizedNode(node, tag, _)
1010
}
1111

12+
DataFlowCallable getSynthesizedCallable(AstNode node, string tag) {
13+
result = MkGenericSynthesizedCallable(node, tag)
14+
}
15+
16+
DataFlowCall getSynthesizedCall(AstNode node, string tag) {
17+
result = MkGenericSynthesizedCall(node, tag, _)
18+
}
19+
1220
/**
1321
* An extension to `AdditionalFlowStep` with additional internal-only predicates.
1422
*/
@@ -22,6 +30,10 @@ class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
2230
*/
2331
predicate needsSynthesizedNode(AstNode node, string tag, DataFlowCallable container) { none() }
2432

33+
predicate needsSynthesizedCallable(AstNode node, string tag) { none() }
34+
35+
predicate needsSynthesizedCall(AstNode node, string tag, DataFlowCallable container) { none() }
36+
2537
/**
2638
* Holds if `node` should only permit flow of values stored in `contents`.
2739
*/
@@ -31,4 +43,10 @@ class AdditionalFlowInternal extends DataFlow::AdditionalFlowStep {
3143
* Holds if `node` should not permit flow of values stored in `contents`.
3244
*/
3345
predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) { none() }
46+
47+
predicate argument(DataFlowCall call, ArgumentPosition pos, DataFlow::Node value) { none() }
48+
49+
predicate postUpdate(DataFlow::Node pre, DataFlow::Node post) { none() }
50+
51+
predicate viableCallable(DataFlowCall call, DataFlowCallable target) { none() }
3452
}

Diff for: javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowPrivate.qll

+44-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private import sharedlib.FlowSummaryImpl as FlowSummaryImpl
1313
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
1414
private import semmle.javascript.dataflow.FlowSummary as FlowSummary
1515
private import semmle.javascript.dataflow.internal.BarrierGuards
16+
private import codeql.util.Boolean
1617

1718
class DataFlowSecondLevelScope = Unit;
1819

@@ -363,6 +364,8 @@ predicate postUpdatePair(Node pre, Node post) {
363364
pre.(FlowSummaryNode).getSummaryNode())
364365
or
365366
VariableCaptureOutput::capturePostUpdateNode(getClosureNode(post), getClosureNode(pre))
367+
or
368+
any(AdditionalFlowInternal f).postUpdate(pre, post)
366369
}
367370

368371
class CastNode extends DataFlow::Node {
@@ -381,10 +384,16 @@ newtype TDataFlowCallable =
381384
not f instanceof ArrowFunctionExpr and
382385
// We also don't need harnesses for externs
383386
not f.getTopLevel().isExterns()
387+
} or
388+
/**
389+
* A callable entity. This is a wrapper around either a `StmtContainer`, `LibraryCallable`, or `File`.
390+
*/
391+
MkGenericSynthesizedCallable(AstNode node, string tag) {
392+
any(AdditionalFlowInternal f).needsSynthesizedCallable(node, tag)
384393
}
385394

386395
/**
387-
* A callable entity. This is a wrapper around either a `StmtContainer`, `LibraryCallable`, or `File`.
396+
* A callable entity.
388397
*/
389398
class DataFlowCallable extends TDataFlowCallable {
390399
/** Gets a string representation of this callable. */
@@ -395,7 +404,7 @@ class DataFlowCallable extends TDataFlowCallable {
395404
or
396405
result = this.asFileCallable().toString()
397406
or
398-
result = this.asClassHarness().toString()
407+
this.isGenericSynthesizedCallable(_, result)
399408
}
400409

401410
/** Gets the location of this callable, if it is present in the source code. */
@@ -404,7 +413,10 @@ class DataFlowCallable extends TDataFlowCallable {
404413
or
405414
result = this.asFileCallable().getLocation()
406415
or
407-
result = this.asClassHarness().getLocation()
416+
exists(AstNode node |
417+
this.isGenericSynthesizedCallable(node, _) and
418+
result = node.getLocation()
419+
)
408420
}
409421

410422
/** Gets the corresponding `StmtContainer` if this is a source callable. */
@@ -414,7 +426,9 @@ class DataFlowCallable extends TDataFlowCallable {
414426
File asFileCallable() { this = MkFileCallable(result) }
415427

416428
/** Gets the class constructor for which this is a class harness. */
417-
Function asClassHarness() { this = MkClassHarnessCallable(result) }
429+
predicate isGenericSynthesizedCallable(AstNode node, string tag) {
430+
this = MkGenericSynthesizedCallable(node, tag)
431+
}
418432

419433
/** Gets the corresponding `StmtContainer` if this is a source callable. */
420434
pragma[nomagic]
@@ -544,6 +558,8 @@ private predicate isArgumentNodeImpl(Node n, DataFlowCall call, ArgumentPosition
544558
n = TDynamicArgumentArrayNode(invoke) and
545559
pos.isDynamicArgumentArray()
546560
)
561+
or
562+
any(AdditionalFlowInternal f).argument(call, pos, n)
547563
}
548564

549565
predicate isArgumentNode(ArgumentNode n, DataFlowCall call, ArgumentPosition pos) {
@@ -791,7 +807,7 @@ ContentApprox getContentApprox(Content c) {
791807
}
792808

793809
cached
794-
private newtype TDataFlowCall =
810+
newtype TDataFlowCall =
795811
MkOrdinaryCall(DataFlow::InvokeNode node) or
796812
MkPartialCall(DataFlow::PartialInvokeNode node, DataFlow::Node callback) {
797813
callback = node.getACallbackNode()
@@ -812,6 +828,9 @@ private newtype TDataFlowCall =
812828
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
813829
) {
814830
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
831+
} or
832+
MkGenericSynthesizedCall(AstNode node, string tag, DataFlowCallable container) {
833+
any(AdditionalFlowInternal f).needsSynthesizedCall(node, tag, container)
815834
}
816835

817836
private module TotalOrdering {
@@ -877,6 +896,10 @@ class DataFlowCall extends TDataFlowCall {
877896
this = MkSummaryCall(enclosingCallable, receiver)
878897
}
879898

899+
predicate isGenericSynthesizedCall(AstNode node, string tag, DataFlowCallable container) {
900+
this = MkGenericSynthesizedCall(node, tag, container)
901+
}
902+
880903
Location getLocation() { none() } // Overridden in subclass
881904

882905
int totalorder() {
@@ -995,6 +1018,20 @@ private class ImpliedLambdaCall extends DataFlowCall, MkImpliedLambdaCall {
9951018
}
9961019
}
9971020

1021+
class GenericSynthesizedCall extends DataFlowCall, MkGenericSynthesizedCall {
1022+
private AstNode node;
1023+
private string tag;
1024+
private DataFlowCallable container;
1025+
1026+
GenericSynthesizedCall() { this = MkGenericSynthesizedCall(node, tag, container) }
1027+
1028+
override string toString() { result = tag }
1029+
1030+
override Location getLocation() { result = node.getLocation() }
1031+
1032+
override DataFlowCallable getEnclosingCallable() { result = container }
1033+
}
1034+
9981035
private int getMaxArity() {
9991036
// TODO: account for flow summaries
10001037
result =
@@ -1092,6 +1129,8 @@ DataFlowCallable viableCallable(DataFlowCall node) {
10921129
)
10931130
or
10941131
result.asSourceCallableNotExterns() = node.asImpliedLambdaCall()
1132+
or
1133+
any(AdditionalFlowInternal f).viableCallable(node, result)
10951134
}
10961135

10971136
private DataFlowCall getACallOnThis(DataFlow::ClassNode cls) {

0 commit comments

Comments
 (0)