mirror of
https://github.com/github/codeql.git
synced 2026-04-24 08:15:14 +02:00
Rust: Instantiate variable capture library for data flow
This commit is contained in:
@@ -210,23 +210,22 @@ module Ssa {
|
||||
final CfgNode getWriteAccess() { result = write }
|
||||
|
||||
/**
|
||||
* Holds if this SSA definition assigns `value` to the underlying variable.
|
||||
* Holds if this SSA definition assigns `value` to the underlying
|
||||
* variable.
|
||||
*
|
||||
* This is either a direct assignment, `x = value`, or an assignment via
|
||||
* simple pattern matching
|
||||
*
|
||||
* ```rb
|
||||
* case value
|
||||
* in Foo => x then ...
|
||||
* in y => then ...
|
||||
* end
|
||||
* ```
|
||||
* This is either the value in a direct assignment, `x = value`, or in a
|
||||
* `let` statement, `let x = value`. Note that patterns on the rhs. are
|
||||
* currently not supported.
|
||||
*/
|
||||
predicate assigns(ExprCfgNode value) {
|
||||
exists(AssignmentExprCfgNode ae, BasicBlock bb, int i |
|
||||
this.definesAt(_, bb, i) and
|
||||
ae.getLhs() = bb.getNode(i) and
|
||||
value = ae.getRhs()
|
||||
exists(AssignmentExprCfgNode ae |
|
||||
ae.getLhs() = write and
|
||||
ae.getRhs() = value
|
||||
)
|
||||
or
|
||||
exists(LetStmtCfgNode ls |
|
||||
ls.getPat() = write and
|
||||
ls.getInitializer() = value
|
||||
)
|
||||
}
|
||||
|
||||
@@ -338,4 +337,37 @@ module Ssa {
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition inserted at a call that may update the value of a captured
|
||||
* variable. For example, in
|
||||
*
|
||||
* ```rb
|
||||
* fn capture_mut() {
|
||||
* let mut y = 0;
|
||||
* (0..5).for_each(|| {
|
||||
* y += x
|
||||
* });
|
||||
* y
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* a definition for `y` is inserted at the call to `for_each`.
|
||||
*/
|
||||
class CapturedCallDefinition extends Definition, SsaImpl::UncertainWriteDefinition {
|
||||
CapturedCallDefinition() {
|
||||
exists(Variable v, BasicBlock bb, int i |
|
||||
this.definesAt(v, bb, i) and
|
||||
SsaImpl::capturedCallWrite(_, bb, i, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the immediately preceding definition. Since this update is uncertain,
|
||||
* the value from the preceding definition might still be valid.
|
||||
*/
|
||||
final Definition getPriorDefinition() { result = SsaImpl::uncertainWriteDefinitionInput(this) }
|
||||
|
||||
override string toString() { result = "<captured exit> " + this.getSourceVariable() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +101,19 @@ final class ParameterPosition extends TParameterPosition {
|
||||
/** Holds if this position represents the `self` position. */
|
||||
predicate isSelf() { this = TSelfParameterPosition() }
|
||||
|
||||
/**
|
||||
* Holds if this position represents a reference to a lambda itself. Only
|
||||
* used for tracking flow through captured variables.
|
||||
*/
|
||||
predicate isLambdaSelf() { this = TLambdaSelfParameterPosition() }
|
||||
|
||||
/** Gets a textual representation of this position. */
|
||||
string toString() {
|
||||
result = this.getPosition().toString()
|
||||
or
|
||||
result = "self" and this.isSelf()
|
||||
or
|
||||
result = "lambda self" and this.isLambdaSelf()
|
||||
}
|
||||
|
||||
ParamBase getParameterIn(ParamList ps) {
|
||||
@@ -264,6 +272,26 @@ module Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The run-time representation of a closure itself at function entry, viewed
|
||||
* as a node in a data flow graph.
|
||||
*/
|
||||
final class ClosureParameterNode extends ParameterNode, TLambdaSelfReferenceNode {
|
||||
private CfgScope cfgScope;
|
||||
|
||||
ClosureParameterNode() { this = TLambdaSelfReferenceNode(cfgScope) }
|
||||
|
||||
final override CfgScope getCfgScope() { result = cfgScope }
|
||||
|
||||
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
|
||||
cfgScope = c.asCfgScope() and pos.isLambdaSelf()
|
||||
}
|
||||
|
||||
override Location getLocation() { result = cfgScope.getLocation() }
|
||||
|
||||
override string toString() { result = "lambda self in " + cfgScope }
|
||||
}
|
||||
|
||||
abstract class ArgumentNode extends Node {
|
||||
abstract predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos);
|
||||
}
|
||||
@@ -292,6 +320,21 @@ module Node {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that represents the run-time representation of a closure
|
||||
* passed into the closure body at an invocation.
|
||||
*/
|
||||
final class ClosureArgumentNode extends ArgumentNode, ExprNode {
|
||||
private CallExprCfgNode call_;
|
||||
|
||||
ClosureArgumentNode() { lambdaCallExpr(call_, _, this.asExpr()) }
|
||||
|
||||
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
|
||||
call.asCallExprCfgNode() = call_ and
|
||||
pos.isLambdaSelf()
|
||||
}
|
||||
}
|
||||
|
||||
/** An SSA node. */
|
||||
class SsaNode extends Node, TSsaNode {
|
||||
SsaImpl::DataFlowIntegration::SsaNode node;
|
||||
@@ -402,6 +445,37 @@ module Node {
|
||||
final override string toString() { result = PostUpdateNode.super.toString() }
|
||||
}
|
||||
|
||||
private class CapturePostUpdateNode extends PostUpdateNode, CaptureNode {
|
||||
private CaptureNode pre;
|
||||
|
||||
CapturePostUpdateNode() {
|
||||
VariableCapture::Flow::capturePostUpdateNode(this.getSynthesizedCaptureNode(),
|
||||
pre.getSynthesizedCaptureNode())
|
||||
}
|
||||
|
||||
override Node getPreUpdateNode() { result = pre }
|
||||
|
||||
final override string toString() { result = PostUpdateNode.super.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthesized data flow node representing a closure object that tracks
|
||||
* captured variables.
|
||||
*/
|
||||
class CaptureNode extends Node, TCaptureNode {
|
||||
private VariableCapture::Flow::SynthesizedCaptureNode cn;
|
||||
|
||||
CaptureNode() { this = TCaptureNode(cn) }
|
||||
|
||||
VariableCapture::Flow::SynthesizedCaptureNode getSynthesizedCaptureNode() { result = cn }
|
||||
|
||||
override CfgScope getCfgScope() { result = cn.getEnclosingCallable() }
|
||||
|
||||
override Location getLocation() { result = cn.getLocation() }
|
||||
|
||||
override string toString() { result = cn.toString() }
|
||||
}
|
||||
|
||||
final class CastNode = NaNode;
|
||||
}
|
||||
|
||||
@@ -625,6 +699,18 @@ private class StructFieldContent extends Content, TStructFieldContent {
|
||||
override string toString() { result = s.toString() + "." + field_.toString() }
|
||||
}
|
||||
|
||||
/** A captured variable. */
|
||||
private class CapturedVariableContent extends Content, TCapturedVariableContent {
|
||||
private Variable v;
|
||||
|
||||
CapturedVariableContent() { this = TCapturedVariableContent(v) }
|
||||
|
||||
/** Gets the captured variable. */
|
||||
Variable getVariable() { result = v }
|
||||
|
||||
override string toString() { result = "captured " + v }
|
||||
}
|
||||
|
||||
/**
|
||||
* An element in an array.
|
||||
*/
|
||||
@@ -681,6 +767,26 @@ final class SingletonContentSet extends ContentSet, TSingletonContentSet {
|
||||
override Content getAReadContent() { result = c }
|
||||
}
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
private predicate lambdaCreationExpr(Expr creation, LambdaCallKind kind) {
|
||||
creation instanceof ClosureExpr and exists(kind)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `call` is a lambda call of kind `kind` where `receiver` is the
|
||||
* invoked expression.
|
||||
*/
|
||||
predicate lambdaCallExpr(CallExprCfgNode call, LambdaCallKind kind, ExprCfgNode receiver) {
|
||||
receiver = call.getFunction() and
|
||||
// All calls to complex expressions and local variable accesses are lambda call.
|
||||
exists(Expr f | f = receiver.getExpr() |
|
||||
f instanceof PathExpr implies f = any(Variable v).getAnAccess()
|
||||
) and
|
||||
exists(kind)
|
||||
}
|
||||
|
||||
// Defines a set of aliases needed for the `RustDataFlow` module
|
||||
private module Aliases {
|
||||
class DataFlowCallableAlias = DataFlowCallable;
|
||||
@@ -694,6 +800,8 @@ private module Aliases {
|
||||
class ContentAlias = Content;
|
||||
|
||||
class ContentSetAlias = ContentSet;
|
||||
|
||||
class LambdaCallKindAlias = LambdaCallKind;
|
||||
}
|
||||
|
||||
module RustDataFlow implements InputSig<Location> {
|
||||
@@ -735,6 +843,12 @@ module RustDataFlow implements InputSig<Location> {
|
||||
node instanceof Node::SsaNode
|
||||
or
|
||||
node instanceof Node::FlowSummaryNode
|
||||
or
|
||||
node instanceof Node::CaptureNode
|
||||
or
|
||||
node instanceof Node::ClosureParameterNode
|
||||
or
|
||||
node instanceof Node::ClosureArgumentNode
|
||||
}
|
||||
|
||||
class DataFlowExpr = ExprCfgNode;
|
||||
@@ -775,6 +889,8 @@ module RustDataFlow implements InputSig<Location> {
|
||||
|
||||
class ContentSet = ContentSetAlias;
|
||||
|
||||
class LambdaCallKind = LambdaCallKindAlias;
|
||||
|
||||
predicate forceHighPrecision(Content c) { none() }
|
||||
|
||||
final class ContentApprox = Content; // TODO: Implement if needed
|
||||
@@ -799,12 +915,17 @@ module RustDataFlow implements InputSig<Location> {
|
||||
(
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(boolean isUseStep | SsaFlow::localFlowStep(_, nodeFrom, nodeTo, isUseStep) |
|
||||
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
|
|
||||
isUseStep = false
|
||||
or
|
||||
isUseStep = true and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
|
||||
)
|
||||
or
|
||||
VariableCapture::localFlowStep(nodeFrom, nodeTo)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
@@ -914,6 +1035,8 @@ module RustDataFlow implements InputSig<Location> {
|
||||
c.(VariantPositionContent).getVariantCanonicalPath(0).getExtendedCanonicalPath() =
|
||||
["crate::option::Option::Some", "crate::result::Result::Ok"]
|
||||
)
|
||||
or
|
||||
VariableCapture::readStep(node1, c, node2)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(Node::FlowSummaryNode).getSummaryNode(),
|
||||
@@ -995,6 +1118,8 @@ module RustDataFlow implements InputSig<Location> {
|
||||
node1.asExpr() = assignment.getRhs() and
|
||||
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = index.getBase()
|
||||
)
|
||||
or
|
||||
VariableCapture::storeStep(node1, c, node2)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(Node::FlowSummaryNode).getSummaryNode(),
|
||||
@@ -1011,6 +1136,8 @@ module RustDataFlow implements InputSig<Location> {
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(Node::FlowSummaryNode).getSummaryNode(),
|
||||
cs)
|
||||
or
|
||||
VariableCapture::clearsContent(n, cs.(SingletonContentSet).getContent())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1045,6 +1172,9 @@ module RustDataFlow implements InputSig<Location> {
|
||||
p.isParameterOf(c, pos) and
|
||||
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(c.asLibraryCallable(), pos)
|
||||
)
|
||||
or
|
||||
VariableCapture::Flow::heuristicAllowInstanceParameterReturnInSelf(p.(Node::ClosureParameterNode)
|
||||
.getCfgScope())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1064,15 +1194,11 @@ module RustDataFlow implements InputSig<Location> {
|
||||
.getSummaryNode(), node2.(Node::FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
class LambdaCallKind = Unit;
|
||||
|
||||
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
|
||||
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
|
||||
exists(ClosureExpr cl |
|
||||
cl = creation.asExpr().getExpr() and
|
||||
cl = c.asCfgScope()
|
||||
) and
|
||||
exists(kind)
|
||||
exists(Expr e |
|
||||
e = creation.asExpr().getExpr() and lambdaCreationExpr(e, kind) and e = c.asCfgScope()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1098,6 +1224,141 @@ module RustDataFlow implements InputSig<Location> {
|
||||
class DataFlowSecondLevelScope = Void;
|
||||
}
|
||||
|
||||
/** Provides logic related to captured variables. */
|
||||
module VariableCapture {
|
||||
private import codeql.dataflow.VariableCapture as SharedVariableCapture
|
||||
|
||||
private predicate closureFlowStep(ExprCfgNode e1, ExprCfgNode e2) {
|
||||
e1 = getALastEvalNode(e2)
|
||||
or
|
||||
exists(Ssa::Definition def |
|
||||
def.getARead() = e2 and
|
||||
def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(e1)
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureInput implements SharedVariableCapture::InputSig<Location> {
|
||||
private import rust as Ast
|
||||
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
|
||||
private import codeql.rust.elements.Variable as Variable
|
||||
|
||||
class BasicBlock extends BasicBlocks::BasicBlock {
|
||||
Callable getEnclosingCallable() { result = this.getScope() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class CapturedVariable extends Variable {
|
||||
CapturedVariable() { this.isCaptured() }
|
||||
|
||||
Callable getCallable() { result = this.getEnclosingCfgScope() }
|
||||
}
|
||||
|
||||
final class CapturedParameter extends CapturedVariable {
|
||||
ParamBase p;
|
||||
|
||||
CapturedParameter() { p = this.getParameter() }
|
||||
|
||||
Node::SourceParameterNode getParameterNode() { result.getParameter().getParamBase() = p }
|
||||
}
|
||||
|
||||
class Expr extends CfgNode {
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
class VariableWrite extends Expr {
|
||||
ExprCfgNode source;
|
||||
CapturedVariable v;
|
||||
|
||||
VariableWrite() {
|
||||
exists(AssignmentExprCfgNode assign, Variable::VariableWriteAccess write |
|
||||
this = assign and
|
||||
v = write.getVariable() and
|
||||
assign.getLhs().getExpr() = write and
|
||||
assign.getRhs() = source
|
||||
)
|
||||
or
|
||||
exists(LetStmtCfgNode ls |
|
||||
this = ls and
|
||||
v.getPat() = ls.getPat().getPat() and
|
||||
ls.getInitializer() = source
|
||||
)
|
||||
}
|
||||
|
||||
CapturedVariable getVariable() { result = v }
|
||||
|
||||
ExprCfgNode getSource() { result = source }
|
||||
}
|
||||
|
||||
class VariableRead extends Expr instanceof ExprCfgNode {
|
||||
CapturedVariable v;
|
||||
|
||||
VariableRead() {
|
||||
exists(VariableReadAccess read | this.getExpr() = read and v = read.getVariable())
|
||||
}
|
||||
|
||||
CapturedVariable getVariable() { result = v }
|
||||
}
|
||||
|
||||
class ClosureExpr extends Expr instanceof ExprCfgNode {
|
||||
ClosureExpr() { lambdaCreationExpr(super.getExpr(), _) }
|
||||
|
||||
predicate hasBody(Callable body) { body = super.getExpr() }
|
||||
|
||||
predicate hasAliasedAccess(Expr f) { closureFlowStep+(this, f) and not closureFlowStep(f, _) }
|
||||
}
|
||||
|
||||
class Callable extends CfgScope {
|
||||
predicate isConstructor() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
class CapturedVariable = CaptureInput::CapturedVariable;
|
||||
|
||||
module Flow = SharedVariableCapture::Flow<Location, CaptureInput>;
|
||||
|
||||
private Flow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(Node::CaptureNode).getSynthesizedCaptureNode()
|
||||
or
|
||||
result.(Flow::ExprNode).getExpr() = n.asExpr()
|
||||
or
|
||||
result.(Flow::VariableWriteSourceNode).getVariableWrite().getSource() = n.asExpr()
|
||||
or
|
||||
result.(Flow::ExprPostUpdateNode).getExpr() =
|
||||
n.(Node::PostUpdateNode).getPreUpdateNode().asExpr()
|
||||
or
|
||||
result.(Flow::ParameterNode).getParameter().getParameterNode() = n
|
||||
or
|
||||
result.(Flow::ThisParameterNode).getCallable() = n.(Node::ClosureParameterNode).getCfgScope()
|
||||
}
|
||||
|
||||
predicate storeStep(Node node1, CapturedVariableContent c, Node node2) {
|
||||
Flow::storeStep(asClosureNode(node1), c.getVariable(), asClosureNode(node2))
|
||||
}
|
||||
|
||||
predicate readStep(Node node1, CapturedVariableContent c, Node node2) {
|
||||
Flow::readStep(asClosureNode(node1), c.getVariable(), asClosureNode(node2))
|
||||
}
|
||||
|
||||
predicate localFlowStep(Node node1, Node node2) {
|
||||
Flow::localFlowStep(asClosureNode(node1), asClosureNode(node2))
|
||||
}
|
||||
|
||||
predicate clearsContent(Node node, CapturedVariableContent c) {
|
||||
Flow::clearsContent(asClosureNode(node), c.getVariable())
|
||||
}
|
||||
|
||||
class CapturedSsaDefinitionExt extends SsaImpl::DefinitionExt {
|
||||
CapturedSsaDefinitionExt() { this.getSourceVariable() instanceof CapturedVariable }
|
||||
}
|
||||
}
|
||||
|
||||
import MakeImpl<Location, RustDataFlow>
|
||||
|
||||
/** A collection of cached types and predicates to be evaluated in the same stage. */
|
||||
@@ -1112,6 +1373,8 @@ private module Cached {
|
||||
TPatNode(PatCfgNode p) or
|
||||
TExprPostUpdateNode(ExprCfgNode e) {
|
||||
isArgumentForCall(e, _, _) or
|
||||
lambdaCallExpr(_, _, e) or
|
||||
lambdaCreationExpr(e.getExpr(), _) or
|
||||
e =
|
||||
[
|
||||
any(IndexExprCfgNode i).getBase(), any(FieldExprCfgNode access).getExpr(),
|
||||
@@ -1119,7 +1382,9 @@ private module Cached {
|
||||
]
|
||||
} or
|
||||
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
||||
TLambdaSelfReferenceNode(CfgScope c) { lambdaCreationExpr(c, _) } or
|
||||
TCaptureNode(VariableCapture::Flow::SynthesizedCaptureNode cn)
|
||||
|
||||
cached
|
||||
newtype TDataFlowCall =
|
||||
@@ -1156,6 +1421,7 @@ private module Cached {
|
||||
or
|
||||
FlowSummaryImpl::ParsePositions::isParsedParameterPosition(_, i)
|
||||
} or
|
||||
TLambdaSelfParameterPosition() or
|
||||
TSelfParameterPosition()
|
||||
|
||||
cached
|
||||
@@ -1211,7 +1477,8 @@ private module Cached {
|
||||
} or
|
||||
TStructFieldContent(StructCanonicalPath s, string field) {
|
||||
field = s.getStruct().getFieldList().(RecordFieldList).getAField().getName().getText()
|
||||
}
|
||||
} or
|
||||
TCapturedVariableContent(VariableCapture::CapturedVariable v)
|
||||
|
||||
cached
|
||||
newtype TContentSet = TSingletonContentSet(Content c)
|
||||
|
||||
@@ -335,7 +335,7 @@ private module Cached {
|
||||
|
||||
/**
|
||||
* Holds if `v` is written at index `i` in basic block `bb`, and the corresponding
|
||||
* AST write access is `write`.
|
||||
* write access node in the CFG is `write`.
|
||||
*/
|
||||
cached
|
||||
predicate variableWriteActual(BasicBlock bb, int i, Variable v, CfgNode write) {
|
||||
|
||||
@@ -10,6 +10,9 @@ edges
|
||||
| main.rs:34:13:34:22 | f(...) | main.rs:35:10:35:10 | b | provenance | |
|
||||
| main.rs:34:21:34:21 | a | main.rs:27:20:27:23 | ... | provenance | |
|
||||
| main.rs:34:21:34:21 | a | main.rs:34:13:34:22 | f(...) | provenance | |
|
||||
| main.rs:42:16:42:25 | source(...) | main.rs:44:5:44:5 | [post] f [captured capt] | provenance | |
|
||||
| main.rs:44:5:44:5 | [post] f [captured capt] | main.rs:45:10:45:13 | capt | provenance | |
|
||||
| main.rs:44:5:44:5 | [post] f [captured capt] | main.rs:47:14:47:17 | capt | provenance | |
|
||||
nodes
|
||||
| main.rs:11:20:11:52 | if cond {...} else {...} | semmle.label | if cond {...} else {...} |
|
||||
| main.rs:11:30:11:39 | source(...) | semmle.label | source(...) |
|
||||
@@ -24,6 +27,10 @@ nodes
|
||||
| main.rs:34:13:34:22 | f(...) | semmle.label | f(...) |
|
||||
| main.rs:34:21:34:21 | a | semmle.label | a |
|
||||
| main.rs:35:10:35:10 | b | semmle.label | b |
|
||||
| main.rs:42:16:42:25 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:44:5:44:5 | [post] f [captured capt] | semmle.label | [post] f [captured capt] |
|
||||
| main.rs:45:10:45:13 | capt | semmle.label | capt |
|
||||
| main.rs:47:14:47:17 | capt | semmle.label | capt |
|
||||
subpaths
|
||||
| main.rs:34:21:34:21 | a | main.rs:27:20:27:23 | ... | main.rs:28:9:32:9 | if cond {...} else {...} | main.rs:34:13:34:22 | f(...) |
|
||||
testFailures
|
||||
@@ -31,3 +38,5 @@ testFailures
|
||||
| main.rs:12:10:12:16 | f(...) | main.rs:11:30:11:39 | source(...) | main.rs:12:10:12:16 | f(...) | $@ | main.rs:11:30:11:39 | source(...) | source(...) |
|
||||
| main.rs:18:18:18:21 | data | main.rs:22:13:22:22 | source(...) | main.rs:18:18:18:21 | data | $@ | main.rs:22:13:22:22 | source(...) | source(...) |
|
||||
| main.rs:35:10:35:10 | b | main.rs:33:13:33:22 | source(...) | main.rs:35:10:35:10 | b | $@ | main.rs:33:13:33:22 | source(...) | source(...) |
|
||||
| main.rs:45:10:45:13 | capt | main.rs:42:16:42:25 | source(...) | main.rs:45:10:45:13 | capt | $@ | main.rs:42:16:42:25 | source(...) | source(...) |
|
||||
| main.rs:47:14:47:17 | capt | main.rs:42:16:42:25 | source(...) | main.rs:47:14:47:17 | capt | $@ | main.rs:42:16:42:25 | source(...) | source(...) |
|
||||
|
||||
@@ -42,9 +42,9 @@ fn closure_captured_variable() {
|
||||
capt = source(73);
|
||||
};
|
||||
f();
|
||||
sink(capt); // $ MISSING: hasValueFlow=73
|
||||
sink(capt); // $ hasValueFlow=73
|
||||
let g = || {
|
||||
sink(capt); // $ MISSING: hasValueFlow=73
|
||||
sink(capt); // $ hasValueFlow=73
|
||||
};
|
||||
g();
|
||||
}
|
||||
|
||||
@@ -120,12 +120,12 @@ definition
|
||||
| variables.rs:418:9:418:13 | y | variables.rs:418:13:418:13 | y |
|
||||
| variables.rs:420:9:420:20 | closure2 | variables.rs:420:13:420:20 | closure2 |
|
||||
| variables.rs:421:9:421:9 | y | variables.rs:418:13:418:13 | y |
|
||||
| variables.rs:423:5:423:14 | closure2(...) | variables.rs:418:13:418:13 | y |
|
||||
| variables.rs:423:5:423:14 | <captured exit> y | variables.rs:418:13:418:13 | y |
|
||||
| variables.rs:428:9:428:20 | closure3 | variables.rs:428:13:428:20 | closure3 |
|
||||
| variables.rs:436:9:436:13 | i | variables.rs:436:13:436:13 | i |
|
||||
| variables.rs:437:9:437:13 | block | variables.rs:437:9:437:13 | block |
|
||||
| variables.rs:438:9:438:9 | i | variables.rs:436:13:436:13 | i |
|
||||
| variables.rs:441:5:441:15 | await block | variables.rs:436:13:436:13 | i |
|
||||
| variables.rs:441:5:441:15 | <captured exit> i | variables.rs:436:13:436:13 | i |
|
||||
| variables.rs:445:8:445:8 | b | variables.rs:445:8:445:8 | b |
|
||||
| variables.rs:446:9:446:13 | x | variables.rs:446:13:446:13 | x |
|
||||
| variables.rs:449:5:457:5 | phi | variables.rs:446:13:446:13 | x |
|
||||
@@ -248,10 +248,10 @@ read
|
||||
| variables.rs:412:9:412:16 | closure1 | variables.rs:412:9:412:16 | closure1 | variables.rs:415:5:415:12 | closure1 |
|
||||
| variables.rs:412:20:414:5 | <captured entry> x | variables.rs:410:13:410:13 | x | variables.rs:413:19:413:19 | x |
|
||||
| variables.rs:420:9:420:20 | closure2 | variables.rs:420:13:420:20 | closure2 | variables.rs:423:5:423:12 | closure2 |
|
||||
| variables.rs:423:5:423:14 | closure2(...) | variables.rs:418:13:418:13 | y | variables.rs:424:15:424:15 | y |
|
||||
| variables.rs:423:5:423:14 | <captured exit> y | variables.rs:418:13:418:13 | y | variables.rs:424:15:424:15 | y |
|
||||
| variables.rs:428:9:428:20 | closure3 | variables.rs:428:13:428:20 | closure3 | variables.rs:431:5:431:12 | closure3 |
|
||||
| variables.rs:437:9:437:13 | block | variables.rs:437:9:437:13 | block | variables.rs:441:5:441:9 | block |
|
||||
| variables.rs:441:5:441:15 | await block | variables.rs:436:13:436:13 | i | variables.rs:442:15:442:15 | i |
|
||||
| variables.rs:441:5:441:15 | <captured exit> i | variables.rs:436:13:436:13 | i | variables.rs:442:15:442:15 | i |
|
||||
| variables.rs:445:8:445:8 | b | variables.rs:445:8:445:8 | b | variables.rs:449:8:449:8 | b |
|
||||
| variables.rs:446:9:446:13 | x | variables.rs:446:13:446:13 | x | variables.rs:447:15:447:15 | x |
|
||||
| variables.rs:446:9:446:13 | x | variables.rs:446:13:446:13 | x | variables.rs:448:15:448:15 | x |
|
||||
@@ -363,10 +363,10 @@ firstRead
|
||||
| variables.rs:412:9:412:16 | closure1 | variables.rs:412:9:412:16 | closure1 | variables.rs:415:5:415:12 | closure1 |
|
||||
| variables.rs:412:20:414:5 | <captured entry> x | variables.rs:410:13:410:13 | x | variables.rs:413:19:413:19 | x |
|
||||
| variables.rs:420:9:420:20 | closure2 | variables.rs:420:13:420:20 | closure2 | variables.rs:423:5:423:12 | closure2 |
|
||||
| variables.rs:423:5:423:14 | closure2(...) | variables.rs:418:13:418:13 | y | variables.rs:424:15:424:15 | y |
|
||||
| variables.rs:423:5:423:14 | <captured exit> y | variables.rs:418:13:418:13 | y | variables.rs:424:15:424:15 | y |
|
||||
| variables.rs:428:9:428:20 | closure3 | variables.rs:428:13:428:20 | closure3 | variables.rs:431:5:431:12 | closure3 |
|
||||
| variables.rs:437:9:437:13 | block | variables.rs:437:9:437:13 | block | variables.rs:441:5:441:9 | block |
|
||||
| variables.rs:441:5:441:15 | await block | variables.rs:436:13:436:13 | i | variables.rs:442:15:442:15 | i |
|
||||
| variables.rs:441:5:441:15 | <captured exit> i | variables.rs:436:13:436:13 | i | variables.rs:442:15:442:15 | i |
|
||||
| variables.rs:445:8:445:8 | b | variables.rs:445:8:445:8 | b | variables.rs:449:8:449:8 | b |
|
||||
| variables.rs:446:9:446:13 | x | variables.rs:446:13:446:13 | x | variables.rs:447:15:447:15 | x |
|
||||
| variables.rs:449:5:457:5 | phi | variables.rs:446:13:446:13 | x | variables.rs:458:15:458:15 | x |
|
||||
@@ -471,10 +471,10 @@ lastRead
|
||||
| variables.rs:412:9:412:16 | closure1 | variables.rs:412:9:412:16 | closure1 | variables.rs:415:5:415:12 | closure1 |
|
||||
| variables.rs:412:20:414:5 | <captured entry> x | variables.rs:410:13:410:13 | x | variables.rs:413:19:413:19 | x |
|
||||
| variables.rs:420:9:420:20 | closure2 | variables.rs:420:13:420:20 | closure2 | variables.rs:423:5:423:12 | closure2 |
|
||||
| variables.rs:423:5:423:14 | closure2(...) | variables.rs:418:13:418:13 | y | variables.rs:424:15:424:15 | y |
|
||||
| variables.rs:423:5:423:14 | <captured exit> y | variables.rs:418:13:418:13 | y | variables.rs:424:15:424:15 | y |
|
||||
| variables.rs:428:9:428:20 | closure3 | variables.rs:428:13:428:20 | closure3 | variables.rs:431:5:431:12 | closure3 |
|
||||
| variables.rs:437:9:437:13 | block | variables.rs:437:9:437:13 | block | variables.rs:441:5:441:9 | block |
|
||||
| variables.rs:441:5:441:15 | await block | variables.rs:436:13:436:13 | i | variables.rs:442:15:442:15 | i |
|
||||
| variables.rs:441:5:441:15 | <captured exit> i | variables.rs:436:13:436:13 | i | variables.rs:442:15:442:15 | i |
|
||||
| variables.rs:445:8:445:8 | b | variables.rs:445:8:445:8 | b | variables.rs:449:8:449:8 | b |
|
||||
| variables.rs:446:9:446:13 | x | variables.rs:446:13:446:13 | x | variables.rs:448:15:448:15 | x |
|
||||
| variables.rs:449:5:457:5 | phi | variables.rs:446:13:446:13 | x | variables.rs:458:15:458:15 | x |
|
||||
@@ -592,10 +592,54 @@ ultimateDef
|
||||
| variables.rs:449:5:457:5 | phi | variables.rs:450:9:450:9 | x |
|
||||
| variables.rs:449:5:457:5 | phi | variables.rs:454:9:454:9 | x |
|
||||
assigns
|
||||
| variables.rs:16:9:16:10 | x1 | variables.rs:16:14:16:16 | "a" |
|
||||
| variables.rs:21:9:21:14 | x2 | variables.rs:21:18:21:18 | 4 |
|
||||
| variables.rs:23:5:23:6 | x2 | variables.rs:23:10:23:10 | 5 |
|
||||
| variables.rs:28:9:28:13 | x | variables.rs:28:17:28:17 | 1 |
|
||||
| variables.rs:30:5:30:5 | x | variables.rs:30:9:30:9 | 2 |
|
||||
| variables.rs:35:9:35:10 | x3 | variables.rs:35:14:35:14 | 1 |
|
||||
| variables.rs:37:9:37:10 | x3 | variables.rs:38:9:38:14 | ... + ... |
|
||||
| variables.rs:43:9:43:10 | x4 | variables.rs:43:14:43:16 | "a" |
|
||||
| variables.rs:46:13:46:14 | x4 | variables.rs:46:18:46:20 | "b" |
|
||||
| variables.rs:75:9:75:10 | p1 | variables.rs:75:14:75:37 | Point {...} |
|
||||
| variables.rs:85:9:85:10 | s1 | variables.rs:85:14:85:41 | Some(...) |
|
||||
| variables.rs:102:9:102:10 | s1 | variables.rs:102:14:102:41 | Some(...) |
|
||||
| variables.rs:111:9:111:10 | x6 | variables.rs:111:14:111:20 | Some(...) |
|
||||
| variables.rs:112:9:112:10 | y1 | variables.rs:112:14:112:15 | 10 |
|
||||
| variables.rs:128:9:128:15 | numbers | variables.rs:128:19:128:35 | TupleExpr |
|
||||
| variables.rs:155:9:155:10 | p2 | variables.rs:155:14:155:37 | Point {...} |
|
||||
| variables.rs:169:9:169:11 | msg | variables.rs:169:15:169:38 | ...::Hello {...} |
|
||||
| variables.rs:189:9:189:14 | either | variables.rs:189:18:189:33 | ...::Left(...) |
|
||||
| variables.rs:203:9:203:10 | tv | variables.rs:203:14:203:36 | ...::Second(...) |
|
||||
| variables.rs:219:9:219:14 | either | variables.rs:219:18:219:33 | ...::Left(...) |
|
||||
| variables.rs:229:9:229:14 | either | variables.rs:229:18:229:33 | ...::Left(...) |
|
||||
| variables.rs:253:9:253:10 | fv | variables.rs:253:14:253:35 | ...::Second(...) |
|
||||
| variables.rs:315:9:315:23 | example_closure | variables.rs:316:9:317:9 | \|...\| x |
|
||||
| variables.rs:318:9:318:10 | n1 | variables.rs:319:9:319:26 | example_closure(...) |
|
||||
| variables.rs:323:9:323:26 | immutable_variable | variables.rs:324:9:325:9 | \|...\| x |
|
||||
| variables.rs:326:9:326:10 | n2 | variables.rs:327:9:327:29 | immutable_variable(...) |
|
||||
| variables.rs:332:9:332:9 | v | variables.rs:332:13:332:41 | &... |
|
||||
| variables.rs:350:9:350:13 | ref_i | variables.rs:351:9:351:14 | &mut i |
|
||||
| variables.rs:373:9:373:9 | y | variables.rs:374:9:374:28 | mutate_param(...) |
|
||||
| variables.rs:380:9:380:9 | w | variables.rs:381:9:381:19 | &mut ... |
|
||||
| variables.rs:393:9:393:9 | y | variables.rs:394:9:394:14 | &mut x |
|
||||
| variables.rs:400:9:400:9 | x | variables.rs:400:13:400:15 | 100 |
|
||||
| variables.rs:402:9:402:11 | cap | variables.rs:402:15:404:5 | \|...\| ... |
|
||||
| variables.rs:410:9:410:13 | x | variables.rs:410:17:410:17 | 1 |
|
||||
| variables.rs:412:9:412:16 | closure1 | variables.rs:412:20:414:5 | \|...\| ... |
|
||||
| variables.rs:418:9:418:13 | y | variables.rs:418:17:418:17 | 2 |
|
||||
| variables.rs:420:9:420:20 | closure2 | variables.rs:420:24:422:5 | \|...\| ... |
|
||||
| variables.rs:421:9:421:9 | y | variables.rs:421:13:421:13 | 3 |
|
||||
| variables.rs:428:9:428:20 | closure3 | variables.rs:428:24:430:5 | \|...\| ... |
|
||||
| variables.rs:436:9:436:13 | i | variables.rs:436:22:436:22 | 0 |
|
||||
| variables.rs:437:9:437:13 | block | variables.rs:437:17:439:5 | { ... } |
|
||||
| variables.rs:438:9:438:9 | i | variables.rs:438:13:438:13 | 1 |
|
||||
| variables.rs:446:9:446:13 | x | variables.rs:446:17:446:17 | 1 |
|
||||
| variables.rs:450:9:450:9 | x | variables.rs:450:13:450:13 | 2 |
|
||||
| variables.rs:454:9:454:9 | x | variables.rs:454:13:454:13 | 3 |
|
||||
| variables.rs:462:9:462:9 | x | variables.rs:462:13:462:13 | 1 |
|
||||
| variables.rs:491:13:491:17 | f | variables.rs:491:21:494:9 | \|...\| ... |
|
||||
| variables.rs:510:9:510:13 | a | variables.rs:510:17:510:25 | [...] |
|
||||
| variables.rs:514:5:514:5 | a | variables.rs:514:9:514:17 | [...] |
|
||||
| variables.rs:519:9:519:9 | x | variables.rs:519:13:519:14 | 16 |
|
||||
| variables.rs:523:9:523:9 | z | variables.rs:523:13:523:14 | 17 |
|
||||
|
||||
Reference in New Issue
Block a user