Skip to content

Commit 215922c

Browse files
committed
Rust: Instantiate variable capture library for data flow
1 parent e8357a6 commit 215922c

File tree

6 files changed

+387
-35
lines changed

6 files changed

+387
-35
lines changed

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

+46-14
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 rhs. 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+
* ```rb
346+
* fn capture_mut() {
347+
* let mut y = 0;
348+
* (0..5).for_each(|| {
349+
* y += x
350+
* });
351+
* y
352+
* }
353+
* ```
354+
*
355+
* a definition for `y` is inserted at the call to `for_each`.
356+
*/
357+
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)