Skip to content

Commit 04a4fb2

Browse files
authored
Merge pull request #17655 from hvitved/rust/variable-mut
Rust: `&(mut) x` is neither a read nor a write
2 parents 306b087 + 50c2d10 commit 04a4fb2

File tree

7 files changed

+1154
-965
lines changed

7 files changed

+1154
-965
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/** Provides classes for assignment operations. */
2+
3+
private import rust
4+
private import codeql.rust.elements.internal.BinaryExprImpl
5+
6+
/** An assignment operation. */
7+
abstract private class AssignmentOperationImpl extends Impl::BinaryExpr { }
8+
9+
final class AssignmentOperation = AssignmentOperationImpl;
10+
11+
/**
12+
* An assignment expression, for example
13+
*
14+
* ```rust
15+
* x = y;
16+
* ```
17+
*/
18+
final class AssignmentExpr extends AssignmentOperationImpl {
19+
AssignmentExpr() { this.getOperatorName() = "=" }
20+
21+
override string getAPrimaryQlClass() { result = "AssignmentExpr" }
22+
}
23+
24+
/**
25+
* A compound assignment expression, for example
26+
*
27+
* ```rust
28+
* x += y;
29+
* ```
30+
*
31+
* Note that compound assignment expressions are syntatic sugar for
32+
* trait invocations, i.e., the above actually means
33+
*
34+
* ```rust
35+
* (&mut x).add_assign(y);
36+
* ```
37+
*/
38+
final class CompoundAssignmentExpr extends AssignmentOperationImpl {
39+
private string operator;
40+
41+
CompoundAssignmentExpr() {
42+
this.getOperatorName().regexpCapture("(\\+|-|\\*|/|%|&|\\||\\^|<<|>>)=", 1) = operator
43+
}
44+
45+
/**
46+
* Gets the operator of this compound assignment expression.
47+
*/
48+
string getOperator() { result = operator }
49+
50+
override string getAPrimaryQlClass() { result = "CompoundAssignmentExpr" }
51+
}

rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -395,34 +395,27 @@ module Impl {
395395
}
396396

397397
/** Holds if `e` occurs in the LHS of an assignment or compound assignment. */
398-
private predicate assignLhs(Expr e, boolean compound) {
399-
exists(BinaryExpr be, string op |
400-
op = be.getOperatorName().regexpCapture("(.*)=", 1) and
401-
e = be.getLhs()
402-
|
403-
op = "" and compound = false
404-
or
405-
op != "" and compound = true
406-
)
398+
private predicate assignmentExprDescendant(Expr e) {
399+
e = any(AssignmentExpr ae).getLhs()
407400
or
408401
exists(Expr mid |
409-
assignLhs(mid, compound) and
410-
getImmediateParent(e) = mid
402+
assignmentExprDescendant(mid) and
403+
getImmediateParent(e) = mid and
404+
not mid.(PrefixExpr).getOperatorName() = "*"
411405
)
412406
}
413407

414408
/** A variable write. */
415409
class VariableWriteAccess extends VariableAccess {
416-
VariableWriteAccess() { assignLhs(this, _) }
410+
VariableWriteAccess() { assignmentExprDescendant(this) }
417411
}
418412

419413
/** A variable read. */
420414
class VariableReadAccess extends VariableAccess {
421415
VariableReadAccess() {
422-
not this instanceof VariableWriteAccess
423-
or
424-
// consider LHS in compound assignments both reads and writes
425-
assignLhs(this, true)
416+
not this instanceof VariableWriteAccess and
417+
not this = any(RefExpr re).getExpr() and
418+
not this = any(CompoundAssignmentExpr cae).getLhs()
426419
}
427420
}
428421

rust/ql/lib/rust.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
import codeql.rust.elements
44
import codeql.Locations
55
import codeql.files.FileSystem
6+
import codeql.rust.elements.AssignmentOperation
67
import codeql.rust.elements.LogicalOperation
78
import codeql.rust.elements.Variable

rust/ql/test/library-tests/variables/Cfg.expected

Lines changed: 683 additions & 608 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)