Skip to content

Commit

Permalink
Merge pull request #17655 from hvitved/rust/variable-mut
Browse files Browse the repository at this point in the history
Rust: `&(mut) x` is neither a read nor a write
  • Loading branch information
hvitved authored Oct 4, 2024
2 parents 306b087 + 50c2d10 commit 04a4fb2
Show file tree
Hide file tree
Showing 7 changed files with 1,154 additions and 965 deletions.
51 changes: 51 additions & 0 deletions rust/ql/lib/codeql/rust/elements/AssignmentOperation.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/** Provides classes for assignment operations. */

private import rust
private import codeql.rust.elements.internal.BinaryExprImpl

/** An assignment operation. */
abstract private class AssignmentOperationImpl extends Impl::BinaryExpr { }

final class AssignmentOperation = AssignmentOperationImpl;

/**
* An assignment expression, for example
*
* ```rust
* x = y;
* ```
*/
final class AssignmentExpr extends AssignmentOperationImpl {
AssignmentExpr() { this.getOperatorName() = "=" }

override string getAPrimaryQlClass() { result = "AssignmentExpr" }
}

/**
* A compound assignment expression, for example
*
* ```rust
* x += y;
* ```
*
* Note that compound assignment expressions are syntatic sugar for
* trait invocations, i.e., the above actually means
*
* ```rust
* (&mut x).add_assign(y);
* ```
*/
final class CompoundAssignmentExpr extends AssignmentOperationImpl {
private string operator;

CompoundAssignmentExpr() {
this.getOperatorName().regexpCapture("(\\+|-|\\*|/|%|&|\\||\\^|<<|>>)=", 1) = operator
}

/**
* Gets the operator of this compound assignment expression.
*/
string getOperator() { result = operator }

override string getAPrimaryQlClass() { result = "CompoundAssignmentExpr" }
}
25 changes: 9 additions & 16 deletions rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -395,34 +395,27 @@ module Impl {
}

/** Holds if `e` occurs in the LHS of an assignment or compound assignment. */
private predicate assignLhs(Expr e, boolean compound) {
exists(BinaryExpr be, string op |
op = be.getOperatorName().regexpCapture("(.*)=", 1) and
e = be.getLhs()
|
op = "" and compound = false
or
op != "" and compound = true
)
private predicate assignmentExprDescendant(Expr e) {
e = any(AssignmentExpr ae).getLhs()
or
exists(Expr mid |
assignLhs(mid, compound) and
getImmediateParent(e) = mid
assignmentExprDescendant(mid) and
getImmediateParent(e) = mid and
not mid.(PrefixExpr).getOperatorName() = "*"
)
}

/** A variable write. */
class VariableWriteAccess extends VariableAccess {
VariableWriteAccess() { assignLhs(this, _) }
VariableWriteAccess() { assignmentExprDescendant(this) }
}

/** A variable read. */
class VariableReadAccess extends VariableAccess {
VariableReadAccess() {
not this instanceof VariableWriteAccess
or
// consider LHS in compound assignments both reads and writes
assignLhs(this, true)
not this instanceof VariableWriteAccess and
not this = any(RefExpr re).getExpr() and
not this = any(CompoundAssignmentExpr cae).getLhs()
}
}

Expand Down
1 change: 1 addition & 0 deletions rust/ql/lib/rust.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
import codeql.rust.elements
import codeql.Locations
import codeql.files.FileSystem
import codeql.rust.elements.AssignmentOperation
import codeql.rust.elements.LogicalOperation
import codeql.rust.elements.Variable
1,291 changes: 683 additions & 608 deletions rust/ql/test/library-tests/variables/Cfg.expected

Large diffs are not rendered by default.

Loading

0 comments on commit 04a4fb2

Please sign in to comment.