Skip to content

Commit 5c9e79e

Browse files
committed
Data flow: Workaround for lambda + capture flow
1 parent 9d6ece1 commit 5c9e79e

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed

shared/dataflow/codeql/dataflow/DataFlow.qll

+2
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ signature module InputSig<LocationSig Location> {
352352
Content getLambdaArgumentContent(LambdaCallKind kind, ArgumentPosition pos);
353353

354354
predicate isLambdaInstanceParameter(ParameterNode p);
355+
356+
predicate isVariableCaptureContentSet(ContentSet c);
355357
}
356358

357359
module Configs<LocationSig Location, InputSig<Location> Lang> {

shared/dataflow/codeql/dataflow/VariableCapture.qll

+2-2
Original file line numberDiff line numberDiff line change
@@ -1051,8 +1051,8 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
10511051
* since normal use-use flow for `fn` does not take the overwrite at (2) into account.
10521052
*/
10531053

1054-
storeStepClosure(_, v, node, true)
1055-
or
1054+
// storeStepClosure(_, v, node, true)
1055+
// or
10561056
exists(BasicBlock bb, int i |
10571057
captureWrite(v, bb, i, false, _) and
10581058
node = TSynthThisQualifier(bb, i, false)

shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll

+3-3
Original file line numberDiff line numberDiff line change
@@ -450,13 +450,13 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
450450
bindingset[c]
451451
private predicate expectsContentEx(NodeEx n, Content c) {
452452
exists(ContentSet cs |
453-
expectsContentCached(n.asNode(), cs) and
453+
expectsContentCached(n, cs) and
454454
pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent()
455455
)
456456
}
457457

458458
pragma[nomagic]
459-
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) }
459+
private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n, _) }
460460

461461
pragma[nomagic]
462462
private predicate storeExUnrestricted(
@@ -2618,7 +2618,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
26182618
(
26192619
castNode(this.asNode()) or
26202620
clearsContentCached(this.asNode(), _) or
2621-
expectsContentCached(this.asNode(), _) or
2621+
expectsContentCached(this, _) or
26222622
neverSkipInPathGraph(this.asNode()) or
26232623
Config::neverSkip(this.asNode())
26242624
)

shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll

+32-4
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
893893
or
894894
result = this.asLambdaArgsNode().toString() + " [LambdaArgs]"
895895
or
896+
result = this.asLambdaCaptureNode().toString() + " [LambdaCapture]"
897+
or
896898
result = this.asLambdaInstancePostUpdateNode().toString() + " [LambdaPostUpdate]"
897899
or
898900
exists(DataFlowCall synthCall, ArgumentPosition apos, boolean isPost |
@@ -918,6 +920,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
918920

919921
Node asLambdaArgsNode() { this = TNodeLambdaArgs(result) }
920922

923+
Node asLambdaCaptureNode() { this = TNodeLambdaCapture(result) }
924+
921925
predicate isLambdaArgNode(DataFlowCall synthCall, ArgumentPosition apos, boolean isPost) {
922926
this = TNodeLambdaArg(synthCall, apos, isPost)
923927
}
@@ -935,6 +939,10 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
935939
or
936940
this = TNodeLambdaArgs(result)
937941
or
942+
this = TNodeLambdaCapture(result)
943+
or
944+
this = TNodeLambdaCapture(result)
945+
or
938946
exists(DataFlowCall synthCall |
939947
this = TNodeLambdaArg(synthCall, _, _) and
940948
lambdaCreation(result, _, _, synthCall)
@@ -963,6 +971,8 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
963971
or
964972
nodeDataFlowType(this.asLambdaArgsNode(), result)
965973
or
974+
nodeDataFlowType(this.asLambdaCaptureNode(), result)
975+
or
966976
exists(
967977
DataFlowCall synthCall, ArgumentPosition apos, DataFlowCallable c, ParameterNode p,
968978
ParameterPosition ppos
@@ -1112,7 +1122,12 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
11121122
predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) }
11131123

11141124
cached
1115-
predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) }
1125+
predicate expectsContentCached(NodeEx n, ContentSet c) {
1126+
expectsContent(n.asNode(), c)
1127+
or
1128+
exists(n.asLambdaCaptureNode()) and
1129+
isVariableCaptureContentSet(c)
1130+
}
11161131

11171132
cached
11181133
predicate isUnreachableInCallCached(NodeRegion nr, DataFlowCall call) {
@@ -1133,6 +1148,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
11331148
exists(n.asLambdaInstancePostUpdateNode()) or
11341149
exists(n.asLambdaMallocNode()) or
11351150
exists(n.asLambdaArgsNode()) or
1151+
exists(n.asLambdaCaptureNode()) or
11361152
n.isLambdaArgNode(_, _, _) or
11371153
hiddenNode(any(NodeEx p | n.asParamReturnNode() = p.asNode()))
11381154
}
@@ -1554,7 +1570,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
15541570
argumentValueFlowsThroughCand(arg, node, false)
15551571
)
15561572
) and
1557-
not expectsContentCached(node, _)
1573+
not expectsContent(node, _)
15581574
}
15591575

15601576
pragma[nomagic]
@@ -2064,10 +2080,11 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
20642080
lambdaCreation(_, _, c, synthCall) and
20652081
isParameterNode(p, c, ppos) and
20662082
parameterMatch(ppos, apos) and
2067-
not isLambdaInstanceParameter(p) and
2083+
// not isLambdaInstanceParameter(p) and
20682084
exists(ispost)
20692085
)
2070-
}
2086+
} or
2087+
TNodeLambdaCapture(Node receiver) { lambdaCall(_, _, receiver) }
20712088

20722089
/*
20732090
* foo(() => "taint"); // taint --store(ReturnValue)--> this (post-update) [ReturnValue]
@@ -2108,6 +2125,17 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
21082125
or
21092126
LambdaFlow::lambdaFlowsToPostUpdate(node2.asLambdaArgsNode(), node1.asNode()) and
21102127
model = ""
2128+
or
2129+
// When data is stored in a captured variable content and reaches a lambda call,
2130+
// we need it to propagate back out to the lambda. We do this by adding flow
2131+
// from the lambda receiver to the post-update of the lambda receiver, but _only_
2132+
// for captured variable content. The latter restriction is enforced by going via
2133+
// an intermediate `expectsContent` node.
2134+
node1.asNode() = node2.asLambdaCaptureNode() and
2135+
model = ""
2136+
or
2137+
node2.asNode().(PostUpdateNode).getPreUpdateNode() = node1.asLambdaCaptureNode() and
2138+
model = ""
21112139
}
21122140

21132141
cached

0 commit comments

Comments
 (0)