Skip to content

Commit e9a50f2

Browse files
committed
Auto merge of #12451 - Jacherr:issue-12391, r=llogiq
new restriction lint: `integer_division_remainder_used` Fixes #12391 Introduces a restriction lint which disallows the use of `/` and `%` operators on any `Int` or `Uint` types (i.e., any that use the default `Div` or `Rem` trait implementations). Custom implementations of these traits are ignored. ---- changelog: Add new restriction lint [`integer_division_remainder_used`]
2 parents d202eb6 + edcf10e commit e9a50f2

6 files changed

+154
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5281,6 +5281,7 @@ Released 2018-09-13
52815281
[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
52825282
[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
52835283
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
5284+
[`integer_division_remainder_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division_remainder_used
52845285
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
52855286
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
52865287
[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
236236
crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO,
237237
crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
238238
crate::int_plus_one::INT_PLUS_ONE_INFO,
239+
crate::integer_division_remainder_used::INTEGER_DIVISION_REMAINDER_USED_INFO,
239240
crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
240241
crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
241242
crate::item_name_repetitions::MODULE_INCEPTION_INFO,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use rustc_ast::BinOpKind;
3+
use rustc_hir::{Expr, ExprKind};
4+
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_middle::ty::{self};
6+
use rustc_session::declare_lint_pass;
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
/// Checks for the usage of division (/) and remainder (%) operations
11+
/// when performed on any integer types using the default Div and Rem trait implementations.
12+
///
13+
/// ### Why is this bad?
14+
/// In cryptographic contexts, division can result in timing sidechannel vulnerabilities,
15+
/// and needs to be replaced with constant-time code instead (e.g. Barrett reduction).
16+
///
17+
/// ### Example
18+
/// ```no_run
19+
/// let my_div = 10 / 2;
20+
/// ```
21+
/// Use instead:
22+
/// ```no_run
23+
/// let my_div = 10 >> 1;
24+
/// ```
25+
#[clippy::version = "1.78.0"]
26+
pub INTEGER_DIVISION_REMAINDER_USED,
27+
restriction,
28+
"use of disallowed default division and remainder operations"
29+
}
30+
31+
declare_lint_pass!(IntegerDivisionRemainderUsed => [INTEGER_DIVISION_REMAINDER_USED]);
32+
33+
impl LateLintPass<'_> for IntegerDivisionRemainderUsed {
34+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
35+
if let ExprKind::Binary(op, lhs, rhs) = &expr.kind
36+
&& let BinOpKind::Div | BinOpKind::Rem = op.node
37+
&& let lhs_ty = cx.typeck_results().expr_ty(lhs)
38+
&& let rhs_ty = cx.typeck_results().expr_ty(rhs)
39+
&& let ty::Int(_) | ty::Uint(_) = lhs_ty.peel_refs().kind()
40+
&& let ty::Int(_) | ty::Uint(_) = rhs_ty.peel_refs().kind()
41+
{
42+
span_lint(
43+
cx,
44+
INTEGER_DIVISION_REMAINDER_USED,
45+
expr.span.source_callsite(),
46+
&format!("use of {} has been disallowed in this context", op.node.as_str()),
47+
);
48+
}
49+
}
50+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ mod init_numbered_fields;
172172
mod inline_fn_without_body;
173173
mod instant_subtraction;
174174
mod int_plus_one;
175+
mod integer_division_remainder_used;
175176
mod invalid_upcast_comparisons;
176177
mod item_name_repetitions;
177178
mod items_after_statements;
@@ -1124,6 +1125,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
11241125
store.register_late_pass(|_| Box::new(assigning_clones::AssigningClones));
11251126
store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
11261127
store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
1128+
store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
11271129
// add lints here, do not remove this comment, it's used in `new_lint`
11281130
}
11291131

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#![warn(clippy::integer_division_remainder_used)]
2+
#![allow(unused_variables)]
3+
#![allow(clippy::op_ref)]
4+
5+
struct CustomOps(pub i32);
6+
impl std::ops::Div for CustomOps {
7+
type Output = Self;
8+
9+
fn div(self, rhs: Self) -> Self::Output {
10+
Self(self.0 / rhs.0)
11+
}
12+
}
13+
impl std::ops::Rem for CustomOps {
14+
type Output = Self;
15+
16+
fn rem(self, rhs: Self) -> Self::Output {
17+
Self(self.0 % rhs.0)
18+
}
19+
}
20+
21+
fn main() {
22+
// should trigger
23+
let a = 10;
24+
let b = 5;
25+
let c = a / b;
26+
let d = a % b;
27+
let e = &a / b;
28+
let f = a % &b;
29+
let g = &a / &b;
30+
let h = &10 % b;
31+
let i = a / &4;
32+
33+
// should not trigger on custom Div and Rem
34+
let w = CustomOps(3);
35+
let x = CustomOps(4);
36+
let y = w / x;
37+
38+
let w = CustomOps(3);
39+
let x = CustomOps(4);
40+
let z = w % x;
41+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
error: use of / has been disallowed in this context
2+
--> tests/ui/integer_division_remainder_used.rs:10:14
3+
|
4+
LL | Self(self.0 / rhs.0)
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::integer-division-remainder-used` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::integer_division_remainder_used)]`
9+
10+
error: use of % has been disallowed in this context
11+
--> tests/ui/integer_division_remainder_used.rs:17:14
12+
|
13+
LL | Self(self.0 % rhs.0)
14+
| ^^^^^^^^^^^^^^
15+
16+
error: use of / has been disallowed in this context
17+
--> tests/ui/integer_division_remainder_used.rs:25:13
18+
|
19+
LL | let c = a / b;
20+
| ^^^^^
21+
22+
error: use of % has been disallowed in this context
23+
--> tests/ui/integer_division_remainder_used.rs:26:13
24+
|
25+
LL | let d = a % b;
26+
| ^^^^^
27+
28+
error: use of / has been disallowed in this context
29+
--> tests/ui/integer_division_remainder_used.rs:27:13
30+
|
31+
LL | let e = &a / b;
32+
| ^^^^^^
33+
34+
error: use of % has been disallowed in this context
35+
--> tests/ui/integer_division_remainder_used.rs:28:13
36+
|
37+
LL | let f = a % &b;
38+
| ^^^^^^
39+
40+
error: use of / has been disallowed in this context
41+
--> tests/ui/integer_division_remainder_used.rs:29:13
42+
|
43+
LL | let g = &a / &b;
44+
| ^^^^^^^
45+
46+
error: use of % has been disallowed in this context
47+
--> tests/ui/integer_division_remainder_used.rs:30:13
48+
|
49+
LL | let h = &10 % b;
50+
| ^^^^^^^
51+
52+
error: use of / has been disallowed in this context
53+
--> tests/ui/integer_division_remainder_used.rs:31:13
54+
|
55+
LL | let i = a / &4;
56+
| ^^^^^^
57+
58+
error: aborting due to 9 previous errors
59+

0 commit comments

Comments
 (0)