Skip to content

Commit 1ea7717

Browse files
committed
Capture flow: Take overwrites in nested scopes into account
1 parent 0c43ad4 commit 1ea7717

File tree

6 files changed

+28
-4
lines changed

6 files changed

+28
-4
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ private predicate captureReadStep(Node node1, CapturedVariableContent c, Node no
178178
CaptureFlow::readStep(asClosureNode(node1), c.getVariable(), asClosureNode(node2))
179179
}
180180

181+
private predicate captureClearsContent(Node node, CapturedVariableContent c) {
182+
CaptureFlow::clearsContent(asClosureNode(node), c.getVariable())
183+
}
184+
181185
predicate captureValueStep(Node node1, Node node2) {
182186
CaptureFlow::localFlowStep(asClosureNode(node1), asClosureNode(node2))
183187
}
@@ -311,6 +315,8 @@ predicate clearsContent(Node n, ContentSet c) {
311315
)
312316
or
313317
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
318+
or
319+
captureClearsContent(n, c)
314320
}
315321

316322
/**

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,8 @@ predicate clearsContent(Node n, ContentSet c) {
979979
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
980980
or
981981
dictSplatParameterNodeClearStep(n, c)
982+
or
983+
VariableCapture::clearsContent(n, c)
982984
}
983985

984986
/**

python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ predicate readStep(Node nodeFrom, CapturedVariableContent c, Node nodeTo) {
144144
Flow::readStep(asClosureNode(nodeFrom), c.getVariable(), asClosureNode(nodeTo))
145145
}
146146

147+
predicate clearsContent(Node node, CapturedVariableContent c) {
148+
Flow::clearsContent(asClosureNode(node), c.getVariable())
149+
}
150+
147151
predicate valueStep(Node nodeFrom, Node nodeTo) {
148152
Flow::localFlowStep(asClosureNode(nodeFrom), asClosureNode(nodeTo))
149153
}

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ module VariableCapture {
453453
Flow::localFlowStep(asClosureNode(node1), asClosureNode(node2))
454454
}
455455

456+
predicate clearsContent(Node node, Content::CapturedVariableContent c) {
457+
Flow::clearsContent(asClosureNode(node), c.getVariable())
458+
}
459+
456460
class CapturedSsaDefinitionExt extends SsaImpl::DefinitionExt {
457461
CapturedSsaDefinitionExt() { this.getSourceVariable() instanceof CapturedVariable }
458462
}
@@ -1930,6 +1934,8 @@ predicate clearsContent(Node n, ContentSet c) {
19301934
c.isKnownOrUnknownElement(TKnownElementContent(cv)) and
19311935
cv.isSymbol(name)
19321936
)
1937+
or
1938+
VariableCapture::clearsContent(n, any(Content::CapturedVariableContent v | c.isSingleton(v)))
19331939
}
19341940

19351941
/**

ruby/ql/test/library-tests/dataflow/global/Flow.expected

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
testFailures
2-
| captured_variables.rb:212:14:212:14 | x | Unexpected result: hasValueFlow=17 |
32
edges
43
| blocks.rb:14:12:14:20 | call to source | blocks.rb:8:10:8:14 | yield ... | provenance | |
54
| captured_variables.rb:9:24:9:24 | x | captured_variables.rb:10:10:10:23 | -> { ... } [captured x] | provenance | |
@@ -117,7 +116,6 @@ edges
117116
| captured_variables.rb:194:1:194:1 | c [@x] | captured_variables.rb:185:5:189:7 | self in baz [@x] | provenance | |
118117
| captured_variables.rb:197:9:197:17 | call to taint | captured_variables.rb:199:10:199:10 | x | provenance | |
119118
| captured_variables.rb:206:13:206:21 | call to taint | captured_variables.rb:208:14:208:14 | x | provenance | |
120-
| captured_variables.rb:206:13:206:21 | call to taint | captured_variables.rb:212:14:212:14 | x | provenance | |
121119
| instance_variables.rb:10:19:10:19 | x | instance_variables.rb:11:18:11:18 | x | provenance | |
122120
| instance_variables.rb:11:18:11:18 | x | instance_variables.rb:11:9:11:14 | [post] self [@field] | provenance | |
123121
| instance_variables.rb:13:5:15:7 | self in get_field [@field] | instance_variables.rb:14:16:14:21 | self [@field] | provenance | |
@@ -376,7 +374,6 @@ nodes
376374
| captured_variables.rb:199:10:199:10 | x | semmle.label | x |
377375
| captured_variables.rb:206:13:206:21 | call to taint | semmle.label | call to taint |
378376
| captured_variables.rb:208:14:208:14 | x | semmle.label | x |
379-
| captured_variables.rb:212:14:212:14 | x | semmle.label | x |
380377
| instance_variables.rb:10:19:10:19 | x | semmle.label | x |
381378
| instance_variables.rb:11:9:11:14 | [post] self [@field] | semmle.label | [post] self [@field] |
382379
| instance_variables.rb:11:18:11:18 | x | semmle.label | x |
@@ -586,7 +583,6 @@ subpaths
586583
| captured_variables.rb:187:18:187:19 | @x | captured_variables.rb:178:14:178:22 | call to taint | captured_variables.rb:187:18:187:19 | @x | $@ | captured_variables.rb:178:14:178:22 | call to taint | call to taint |
587584
| captured_variables.rb:199:10:199:10 | x | captured_variables.rb:197:9:197:17 | call to taint | captured_variables.rb:199:10:199:10 | x | $@ | captured_variables.rb:197:9:197:17 | call to taint | call to taint |
588585
| captured_variables.rb:208:14:208:14 | x | captured_variables.rb:206:13:206:21 | call to taint | captured_variables.rb:208:14:208:14 | x | $@ | captured_variables.rb:206:13:206:21 | call to taint | call to taint |
589-
| captured_variables.rb:212:14:212:14 | x | captured_variables.rb:206:13:206:21 | call to taint | captured_variables.rb:212:14:212:14 | x | $@ | captured_variables.rb:206:13:206:21 | call to taint | call to taint |
590586
| instance_variables.rb:20:10:20:13 | @foo | instance_variables.rb:19:12:19:21 | call to taint | instance_variables.rb:20:10:20:13 | @foo | $@ | instance_variables.rb:19:12:19:21 | call to taint | call to taint |
591587
| instance_variables.rb:36:10:36:33 | call to get_field | instance_variables.rb:36:14:36:22 | call to taint | instance_variables.rb:36:10:36:33 | call to get_field | $@ | instance_variables.rb:36:14:36:22 | call to taint | call to taint |
592588
| instance_variables.rb:39:6:39:33 | call to get_field | instance_variables.rb:39:14:39:22 | call to taint | instance_variables.rb:39:6:39:33 | call to get_field | $@ | instance_variables.rb:39:14:39:22 | call to taint | call to taint |

shared/dataflow/codeql/dataflow/VariableCapture.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ signature module OutputSig<LocationSig Location, InputSig<Location> I> {
232232

233233
/** Holds if this-to-this summaries are expected for `c`. */
234234
predicate heuristicAllowInstanceParameterReturnInSelf(I::Callable c);
235+
236+
/** Holds if captured variable `v` is cleared at `node`. */
237+
predicate clearsContent(ClosureNode node, I::CapturedVariable v);
235238
}
236239

237240
/**
@@ -959,4 +962,11 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
959962
)
960963
)
961964
}
965+
966+
predicate clearsContent(ClosureNode node, CapturedVariable v) {
967+
exists(BasicBlock bb, int i |
968+
captureWrite(v, bb, i, false, _) and
969+
node = TSynthThisQualifier(bb, i, false)
970+
)
971+
}
962972
}

0 commit comments

Comments
 (0)