Skip to content

Commit 61671a2

Browse files
committed
Detect fetch_update misuse in invalid_atomic_ordering too
1 parent 6211599 commit 61671a2

File tree

4 files changed

+188
-6
lines changed

4 files changed

+188
-6
lines changed

clippy_lints/src/atomic_ordering.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
88

99
declare_clippy_lint! {
1010
/// **What it does:** Checks for usage of invalid atomic
11-
/// ordering in atomic loads/stores/exchanges and memory fences
11+
/// ordering in atomic loads/stores/exchanges/updates and
12+
/// memory fences.
1213
///
1314
/// **Why is this bad?** Using an invalid atomic ordering
1415
/// will cause a panic at run-time.
@@ -32,10 +33,11 @@ declare_clippy_lint! {
3233
///
3334
/// let _ = x.compare_exchange(false, false, Ordering::Relaxed, Ordering::SeqCst);
3435
/// let _ = x.compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Release);
36+
/// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val ^ val));
3537
/// ```
3638
pub INVALID_ATOMIC_ORDERING,
3739
correctness,
38-
"usage of invalid atomic ordering in atomic loads/stores/exchanges ane memory fences"
40+
"usage of invalid atomic ordering in atomic operations and memory fences"
3941
}
4042

4143
declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);
@@ -142,8 +144,12 @@ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
142144
if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
143145
let method = method_path.ident.name.as_str();
144146
if type_is_atomic(cx, &args[0]);
145-
if method == "compare_exchange" || method == "compare_exchange_weak";
146-
let failure_order_arg = &args[4];
147+
if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update";
148+
let (success_order_arg, failure_order_arg) = if method == "fetch_update" {
149+
(&args[1], &args[2])
150+
} else {
151+
(&args[3], &args[4])
152+
};
147153
if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg);
148154
then {
149155
// Helper type holding on to some checking and error reporting data. Has
@@ -158,7 +164,7 @@ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
158164
let acqrel = ("AcqRel", acquire.1, acquire.2);
159165
let search = [relaxed, acquire, seq_cst, release, acqrel];
160166

161-
let success_lint_info = opt_ordering_defid(cx, &args[3])
167+
let success_lint_info = opt_ordering_defid(cx, success_order_arg)
162168
.and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
163169
search
164170
.iter()

src/lintlist/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
923923
Lint {
924924
name: "invalid_atomic_ordering",
925925
group: "correctness",
926-
desc: "usage of invalid atomic ordering in atomic loads/stores and memory fences",
926+
desc: "usage of invalid atomic ordering in atomic operations and memory fences",
927927
deprecation: None,
928928
module: "atomic_ordering",
929929
},
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#![warn(clippy::invalid_atomic_ordering)]
2+
3+
use std::sync::atomic::{AtomicIsize, Ordering};
4+
5+
fn main() {
6+
// `fetch_update` testing
7+
let x = AtomicIsize::new(0);
8+
9+
// Allowed ordering combos
10+
let _ = x.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| Some(old + 1));
11+
let _ = x.fetch_update(Ordering::Acquire, Ordering::Acquire, |old| Some(old + 1));
12+
let _ = x.fetch_update(Ordering::Acquire, Ordering::Relaxed, |old| Some(old + 1));
13+
let _ = x.fetch_update(Ordering::Release, Ordering::Relaxed, |old| Some(old + 1));
14+
let _ = x.fetch_update(Ordering::AcqRel, Ordering::Acquire, |old| Some(old + 1));
15+
let _ = x.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |old| Some(old + 1));
16+
let _ = x.fetch_update(Ordering::SeqCst, Ordering::Relaxed, |old| Some(old + 1));
17+
let _ = x.fetch_update(Ordering::SeqCst, Ordering::Acquire, |old| Some(old + 1));
18+
let _ = x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + 1));
19+
20+
// AcqRel is always forbidden as a failure ordering
21+
let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1));
22+
let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1));
23+
let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1));
24+
let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1));
25+
let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1));
26+
27+
// Release is always forbidden as a failure ordering
28+
let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1));
29+
let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1));
30+
let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1));
31+
let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1));
32+
let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1));
33+
34+
// Release success order forbids failure order of Acquire or SeqCst
35+
let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1));
36+
let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1));
37+
38+
// Relaxed success order also forbids failure order of Acquire or SeqCst
39+
let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1));
40+
let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1));
41+
42+
// Acquire/AcqRel forbids failure order of SeqCst
43+
let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1));
44+
let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1));
45+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
2+
--> $DIR/atomic_ordering_fetch_update.rs:21:47
3+
|
4+
LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::AcqRel, |old| Some(old + 1));
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::invalid-atomic-ordering` implied by `-D warnings`
8+
= help: consider using ordering mode `Relaxed` instead
9+
10+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
11+
--> $DIR/atomic_ordering_fetch_update.rs:22:47
12+
|
13+
LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::AcqRel, |old| Some(old + 1));
14+
| ^^^^^^^^^^^^^^^^
15+
|
16+
= help: consider using ordering modes `Acquire` or `Relaxed` instead
17+
18+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
19+
--> $DIR/atomic_ordering_fetch_update.rs:23:47
20+
|
21+
LL | let _ = x.fetch_update(Ordering::Release, Ordering::AcqRel, |old| Some(old + 1));
22+
| ^^^^^^^^^^^^^^^^
23+
|
24+
= help: consider using ordering mode `Relaxed` instead
25+
26+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
27+
--> $DIR/atomic_ordering_fetch_update.rs:24:46
28+
|
29+
LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |old| Some(old + 1));
30+
| ^^^^^^^^^^^^^^^^
31+
|
32+
= help: consider using ordering modes `Acquire` or `Relaxed` instead
33+
34+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
35+
--> $DIR/atomic_ordering_fetch_update.rs:25:46
36+
|
37+
LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::AcqRel, |old| Some(old + 1));
38+
| ^^^^^^^^^^^^^^^^
39+
|
40+
= help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
41+
42+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
43+
--> $DIR/atomic_ordering_fetch_update.rs:28:47
44+
|
45+
LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Release, |old| Some(old + 1));
46+
| ^^^^^^^^^^^^^^^^^
47+
|
48+
= help: consider using ordering mode `Relaxed` instead
49+
50+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
51+
--> $DIR/atomic_ordering_fetch_update.rs:29:47
52+
|
53+
LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::Release, |old| Some(old + 1));
54+
| ^^^^^^^^^^^^^^^^^
55+
|
56+
= help: consider using ordering modes `Acquire` or `Relaxed` instead
57+
58+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
59+
--> $DIR/atomic_ordering_fetch_update.rs:30:47
60+
|
61+
LL | let _ = x.fetch_update(Ordering::Release, Ordering::Release, |old| Some(old + 1));
62+
| ^^^^^^^^^^^^^^^^^
63+
|
64+
= help: consider using ordering mode `Relaxed` instead
65+
66+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
67+
--> $DIR/atomic_ordering_fetch_update.rs:31:46
68+
|
69+
LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::Release, |old| Some(old + 1));
70+
| ^^^^^^^^^^^^^^^^^
71+
|
72+
= help: consider using ordering modes `Acquire` or `Relaxed` instead
73+
74+
error: fetch_update's failure ordering may not be `Release` or `AcqRel`
75+
--> $DIR/atomic_ordering_fetch_update.rs:32:46
76+
|
77+
LL | let _ = x.fetch_update(Ordering::SeqCst, Ordering::Release, |old| Some(old + 1));
78+
| ^^^^^^^^^^^^^^^^^
79+
|
80+
= help: consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` instead
81+
82+
error: fetch_update's failure ordering may not stronger than the success ordering of `Release`
83+
--> $DIR/atomic_ordering_fetch_update.rs:35:47
84+
|
85+
LL | let _ = x.fetch_update(Ordering::Release, Ordering::Acquire, |old| Some(old + 1));
86+
| ^^^^^^^^^^^^^^^^^
87+
|
88+
= help: consider using ordering mode `Relaxed` instead
89+
90+
error: fetch_update's failure ordering may not stronger than the success ordering of `Release`
91+
--> $DIR/atomic_ordering_fetch_update.rs:36:47
92+
|
93+
LL | let _ = x.fetch_update(Ordering::Release, Ordering::SeqCst, |old| Some(old + 1));
94+
| ^^^^^^^^^^^^^^^^
95+
|
96+
= help: consider using ordering mode `Relaxed` instead
97+
98+
error: fetch_update's failure ordering may not stronger than the success ordering of `Relaxed`
99+
--> $DIR/atomic_ordering_fetch_update.rs:39:47
100+
|
101+
LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::SeqCst, |old| Some(old + 1));
102+
| ^^^^^^^^^^^^^^^^
103+
|
104+
= help: consider using ordering mode `Relaxed` instead
105+
106+
error: fetch_update's failure ordering may not stronger than the success ordering of `Relaxed`
107+
--> $DIR/atomic_ordering_fetch_update.rs:40:47
108+
|
109+
LL | let _ = x.fetch_update(Ordering::Relaxed, Ordering::Acquire, |old| Some(old + 1));
110+
| ^^^^^^^^^^^^^^^^^
111+
|
112+
= help: consider using ordering mode `Relaxed` instead
113+
114+
error: fetch_update's failure ordering may not stronger than the success ordering of `Acquire`
115+
--> $DIR/atomic_ordering_fetch_update.rs:43:47
116+
|
117+
LL | let _ = x.fetch_update(Ordering::Acquire, Ordering::SeqCst, |old| Some(old + 1));
118+
| ^^^^^^^^^^^^^^^^
119+
|
120+
= help: consider using ordering modes `Acquire` or `Relaxed` instead
121+
122+
error: fetch_update's failure ordering may not stronger than the success ordering of `AcqRel`
123+
--> $DIR/atomic_ordering_fetch_update.rs:44:46
124+
|
125+
LL | let _ = x.fetch_update(Ordering::AcqRel, Ordering::SeqCst, |old| Some(old + 1));
126+
| ^^^^^^^^^^^^^^^^
127+
|
128+
= help: consider using ordering modes `Acquire` or `Relaxed` instead
129+
130+
error: aborting due to 16 previous errors
131+

0 commit comments

Comments
 (0)