-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Allow SSA and some data flow for mutable borrows #18872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
51ae7c6
476fef4
518f164
bc651af
d8d8829
1225c5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |||||
|
|
||||||
| private import codeql.util.Void | ||||||
| private import codeql.util.Unit | ||||||
| private import codeql.util.Boolean | ||||||
| private import codeql.dataflow.DataFlow | ||||||
| private import codeql.dataflow.internal.DataFlowImpl | ||||||
| private import rust | ||||||
|
|
@@ -96,6 +97,8 @@ final class ParameterPosition extends TParameterPosition { | |||||
| /** Gets the underlying integer position, if any. */ | ||||||
| int getPosition() { this = TPositionalParameterPosition(result) } | ||||||
|
|
||||||
| predicate hasPosition() { exists(this.getPosition()) } | ||||||
|
|
||||||
| /** Holds if this position represents the `self` position. */ | ||||||
| predicate isSelf() { this = TSelfParameterPosition() } | ||||||
|
|
||||||
|
|
@@ -367,13 +370,41 @@ module Node { | |||||
| private CallExprBaseCfgNode call_; | ||||||
| private RustDataFlow::ArgumentPosition pos_; | ||||||
|
|
||||||
| ExprArgumentNode() { isArgumentForCall(n, call_, pos_) } | ||||||
| ExprArgumentNode() { | ||||||
| isArgumentForCall(n, call_, pos_) and | ||||||
| // For receivers in method calls the `ReceiverNode` is the argument. | ||||||
| not call_.(MethodCallExprCfgNode).getReceiver() = n | ||||||
| } | ||||||
|
|
||||||
| override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) { | ||||||
| call.asCallBaseExprCfgNode() = call_ and pos = pos_ | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * The receiver of a method call _after_ any implicit borrow or dereferences | ||||||
|
||||||
| * The receiver of a method call _after_ any implicit borrow or dereferences | |
| * The receiver of a method call _after_ any implicit borrow or dereferencing |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to use this.getReceiver().getLocation().
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -54,19 +54,7 @@ module SsaInput implements SsaImplCommon::InputSig<Location> { | |||||||||||||||||||||||||||||||
| * those that are not borrowed (either explicitly using `& mut`, or | ||||||||||||||||||||||||||||||||
| * (potentially) implicit as borrowed receivers in a method call). | ||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
| class SourceVariable extends Variable { | ||||||||||||||||||||||||||||||||
| SourceVariable() { | ||||||||||||||||||||||||||||||||
| this.isMutable() | ||||||||||||||||||||||||||||||||
| implies | ||||||||||||||||||||||||||||||||
| not exists(VariableAccess va | va = this.getAnAccess() | | ||||||||||||||||||||||||||||||||
| va = any(RefExpr re | re.isMut()).getExpr() | ||||||||||||||||||||||||||||||||
| or | ||||||||||||||||||||||||||||||||
| // receivers can be borrowed implicitly, cf. | ||||||||||||||||||||||||||||||||
| // https://doc.rust-lang.org/reference/expressions/method-call-expr.html | ||||||||||||||||||||||||||||||||
| va = any(MethodCallExpr mce).getReceiver() | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| class SourceVariable = Variable; | ||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The QL doc needs to be updated now (or perhaps simply be removed). |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { | ||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||
|
|
@@ -76,7 +64,12 @@ module SsaInput implements SsaImplCommon::InputSig<Location> { | |||||||||||||||||||||||||||||||
| ) and | ||||||||||||||||||||||||||||||||
| certain = true | ||||||||||||||||||||||||||||||||
| or | ||||||||||||||||||||||||||||||||
| capturedCallWrite(_, bb, i, v) and certain = false | ||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||
| capturedCallWrite(_, bb, i, v) | ||||||||||||||||||||||||||||||||
| or | ||||||||||||||||||||||||||||||||
| mutablyBorrows(bb.getNode(i).getAstNode(), v) | ||||||||||||||||||||||||||||||||
| ) and | ||||||||||||||||||||||||||||||||
| certain = false | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { | ||||||||||||||||||||||||||||||||
|
|
@@ -229,6 +222,14 @@ predicate capturedCallWrite(Expr call, BasicBlock bb, int i, Variable v) { | |||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** Holds if `v` may be mutably borrowed in `e`. */ | ||||||||||||||||||||||||||||||||
| private predicate mutablyBorrows(Expr e, Variable v) { | ||||||||||||||||||||||||||||||||
| e = any(MethodCallExpr mc).getReceiver() and | ||||||||||||||||||||||||||||||||
| e.(VariableAccess).getVariable() = v | ||||||||||||||||||||||||||||||||
| or | ||||||||||||||||||||||||||||||||
| exists(RefExpr re | re = e and re.isMut() and re.getExpr().(VariableAccess).getVariable() = v) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Holds if a pseudo read of captured variable `v` should be inserted | ||||||||||||||||||||||||||||||||
| * at index `i` in exit block `bb`. | ||||||||||||||||||||||||||||||||
|
|
@@ -379,6 +380,12 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu | |||||||||||||||||||||||||||||||
| none() // handled in `DataFlowImpl.qll` instead | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| predicate allowFlowIntoUncertainDef(UncertainWriteDefinition def) { | ||||||||||||||||||||||||||||||||
| exists(Variable v, BasicBlock bb, int i | | ||||||||||||||||||||||||||||||||
| def.definesAt(v, bb, i) and mutablyBorrows(bb.getNode(i).getAstNode(), v) | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed offline, perhaps this should be restricted to borrows passed into calls, i.e.
Suggested change
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| class Parameter = CfgNodes::ParamBaseCfgNode; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** Holds if SSA definition `def` initializes parameter `p` at function entry. */ | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps instead remove the
arg = call.(MethodCallExprCfgNode).getReceiver() and pos.isSelf()case insideisArgumentForCall, and then remove this restriction and add ae = any(MethodCallExprCfgNode mc).getReceiver()case toTExprPostUpdateNode.