Skip to content

Commit 3171752

Browse files
authored
Merge pull request #18270 from paldepind/rust-captured-variables
Rust: Flow through captured variables
2 parents 7ab06fc + 9da5d71 commit 3171752

File tree

12 files changed

+572
-132
lines changed

12 files changed

+572
-132
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @name Variable capture data flow inconsistencies
3+
* @description Lists the variable capture data flow inconsistencies in the database. This query is intended for internal use.
4+
* @kind table
5+
* @id rust/diagnostics/variable-capture-data-flow-consistency
6+
*/
7+
8+
import codeql.rust.dataflow.internal.DataFlowImpl::VariableCapture::Flow::ConsistencyChecks

rust/ql/lib/codeql/rust/dataflow/Ssa.qll

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -210,23 +210,22 @@ module Ssa {
210210
final CfgNode getWriteAccess() { result = write }
211211

212212
/**
213-
* Holds if this SSA definition assigns `value` to the underlying variable.
213+
* Holds if this SSA definition assigns `value` to the underlying
214+
* variable.
214215
*
215-
* This is either a direct assignment, `x = value`, or an assignment via
216-
* simple pattern matching
217-
*
218-
* ```rb
219-
* case value
220-
* in Foo => x then ...
221-
* in y => then ...
222-
* end
223-
* ```
216+
* This is either the value in a direct assignment, `x = value`, or in a
217+
* `let` statement, `let x = value`. Note that patterns on the lhs. are
218+
* currently not supported.
224219
*/
225220
predicate assigns(ExprCfgNode value) {
226-
exists(AssignmentExprCfgNode ae, BasicBlock bb, int i |
227-
this.definesAt(_, bb, i) and
228-
ae.getLhs() = bb.getNode(i) and
229-
value = ae.getRhs()
221+
exists(AssignmentExprCfgNode ae |
222+
ae.getLhs() = write and
223+
ae.getRhs() = value
224+
)
225+
or
226+
exists(LetStmtCfgNode ls |
227+
ls.getPat() = write and
228+
ls.getInitializer() = value
230229
)
231230
}
232231

@@ -338,4 +337,37 @@ module Ssa {
338337

339338
override Location getLocation() { result = this.getBasicBlock().getLocation() }
340339
}
340+
341+
/**
342+
* An SSA definition inserted at a call that may update the value of a captured
343+
* variable. For example, in
344+
*
345+
* ```rust
346+
* fn capture_mut() {
347+
* let mut y = 0;
348+
* (0..5).for_each(|x| {
349+
* y += x
350+
* });
351+
* y
352+
* }
353+
* ```
354+
*
355+
* a definition for `y` is inserted at the call to `for_each`.
356+
*/
357+
private class CapturedCallDefinition extends Definition, SsaImpl::UncertainWriteDefinition {
358+
CapturedCallDefinition() {
359+
exists(Variable v, BasicBlock bb, int i |
360+
this.definesAt(v, bb, i) and
361+
SsaImpl::capturedCallWrite(_, bb, i, v)
362+
)
363+
}
364+
365+
/**
366+
* Gets the immediately preceding definition. Since this update is uncertain,
367+
* the value from the preceding definition might still be valid.
368+
*/
369+
final Definition getPriorDefinition() { result = SsaImpl::uncertainWriteDefinitionInput(this) }
370+
371+
override string toString() { result = "<captured exit> " + this.getSourceVariable() }
372+
}
341373
}

0 commit comments

Comments
 (0)