Skip to content

Commit 08b7931

Browse files
committed
Merge pull request #741 from martiansideofthemoon/blastoise
Linting classical overflow checks
2 parents 1278ff6 + 9faffd2 commit 08b7931

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
88
[Jump to usage instructions](#usage)
99

1010
##Lints
11-
There are 130 lints included in this crate:
11+
There are 131 lints included in this crate:
1212

1313
name | default | meaning
1414
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -92,6 +92,7 @@ name
9292
[option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()`
9393
[or_fun_call](https://github.com/Manishearth/rust-clippy/wiki#or_fun_call) | warn | using any `*or` method when the `*or_else` would do
9494
[out_of_bounds_indexing](https://github.com/Manishearth/rust-clippy/wiki#out_of_bounds_indexing) | deny | out of bound constant indexing
95+
[overflow_check_conditional](https://github.com/Manishearth/rust-clippy/wiki#overflow_check_conditional) | warn | Using overflow checks which are likely to panic
9596
[panic_params](https://github.com/Manishearth/rust-clippy/wiki#panic_params) | warn | missing parameters in `panic!`
9697
[precedence](https://github.com/Manishearth/rust-clippy/wiki#precedence) | warn | catches operations where precedence may be unclear. See the wiki for a list of cases caught
9798
[print_stdout](https://github.com/Manishearth/rust-clippy/wiki#print_stdout) | allow | printing on stdout

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ pub mod needless_features;
7979
pub mod needless_update;
8080
pub mod no_effect;
8181
pub mod open_options;
82+
pub mod overflow_check_conditional;
8283
pub mod panic;
8384
pub mod precedence;
8485
pub mod print;
@@ -173,6 +174,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
173174
reg.register_early_lint_pass(box formatting::Formatting);
174175
reg.register_late_lint_pass(box swap::Swap);
175176
reg.register_early_lint_pass(box if_not_else::IfNotElse);
177+
reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional);
176178

177179
reg.register_lint_group("clippy_pedantic", vec![
178180
enum_glob_use::ENUM_GLOB_USE,
@@ -283,6 +285,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
283285
needless_update::NEEDLESS_UPDATE,
284286
no_effect::NO_EFFECT,
285287
open_options::NONSENSICAL_OPEN_OPTIONS,
288+
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
286289
panic::PANIC_PARAMS,
287290
precedence::PRECEDENCE,
288291
ptr_arg::PTR_ARG,

src/overflow_check_conditional.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#![allow(cyclomatic_complexity)]
2+
use rustc::lint::*;
3+
use rustc_front::hir::*;
4+
use utils::{span_lint};
5+
6+
/// **What it does:** This lint finds classic underflow / overflow checks.
7+
///
8+
/// **Why is this bad?** Most classic C underflow / overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
9+
///
10+
/// **Known problems:** None.
11+
///
12+
/// **Example:** `a + b < a`
13+
14+
declare_lint!(pub OVERFLOW_CHECK_CONDITIONAL, Warn,
15+
"Using overflow checks which are likely to panic");
16+
17+
#[derive(Copy, Clone)]
18+
pub struct OverflowCheckConditional;
19+
20+
impl LintPass for OverflowCheckConditional {
21+
fn get_lints(&self) -> LintArray {
22+
lint_array!(OVERFLOW_CHECK_CONDITIONAL)
23+
}
24+
}
25+
26+
impl LateLintPass for OverflowCheckConditional {
27+
// a + b < a, a > a + b, a < a - b, a - b > a
28+
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
29+
if_let_chain! {[
30+
let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
31+
let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = first.node,
32+
let Expr_::ExprPath(_,ref path1) = ident1.node,
33+
let Expr_::ExprPath(_, ref path2) = ident2.node,
34+
let Expr_::ExprPath(_, ref path3) = second.node,
35+
(&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier,
36+
cx.tcx.expr_ty(ident1).is_integral(),
37+
cx.tcx.expr_ty(ident2).is_integral()
38+
], {
39+
if let BinOp_::BiLt = op.node {
40+
if let BinOp_::BiAdd = op2.node {
41+
span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditons that will fail in Rust.");
42+
}
43+
}
44+
if let BinOp_::BiGt = op.node {
45+
if let BinOp_::BiSub = op2.node {
46+
span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditons that will fail in Rust.");
47+
}
48+
}
49+
}}
50+
51+
if_let_chain! {[
52+
let Expr_::ExprBinary(ref op, ref first, ref second) = expr.node,
53+
let Expr_::ExprBinary(ref op2, ref ident1, ref ident2) = second.node,
54+
let Expr_::ExprPath(_,ref path1) = ident1.node,
55+
let Expr_::ExprPath(_, ref path2) = ident2.node,
56+
let Expr_::ExprPath(_, ref path3) = first.node,
57+
(&path1.segments[0]).identifier == (&path3.segments[0]).identifier || (&path2.segments[0]).identifier == (&path3.segments[0]).identifier,
58+
cx.tcx.expr_ty(ident1).is_integral(),
59+
cx.tcx.expr_ty(ident2).is_integral()
60+
], {
61+
if let BinOp_::BiGt = op.node {
62+
if let BinOp_::BiAdd = op2.node {
63+
span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C overflow conditons that will fail in Rust.");
64+
}
65+
}
66+
if let BinOp_::BiLt = op.node {
67+
if let BinOp_::BiSub = op2.node {
68+
span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, "You are trying to use classic C underflow conditons that will fail in Rust.");
69+
}
70+
}
71+
}}
72+
}
73+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
4+
#![deny(overflow_check_conditional)]
5+
6+
fn main() {
7+
let a: u32 = 1;
8+
let b: u32 = 2;
9+
let c: u32 = 3;
10+
if a + b < a { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust.
11+
12+
}
13+
if a > a + b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust.
14+
15+
}
16+
if a + b < b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust.
17+
18+
}
19+
if b > a + b { //~ERROR You are trying to use classic C overflow conditons that will fail in Rust.
20+
21+
}
22+
if a - b > b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust.
23+
24+
}
25+
if b < a - b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust.
26+
27+
}
28+
if a - b > a { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust.
29+
30+
}
31+
if a < a - b { //~ERROR You are trying to use classic C underflow conditons that will fail in Rust.
32+
33+
}
34+
if a + b < c {
35+
36+
}
37+
if c > a + b {
38+
39+
}
40+
if a - b < c {
41+
42+
}
43+
if c > a - b {
44+
45+
}
46+
let i = 1.1;
47+
let j = 2.2;
48+
if i + j < i {
49+
50+
}
51+
if i - j < i {
52+
53+
}
54+
if i > i + j {
55+
56+
}
57+
if i - j < i {
58+
59+
}
60+
}
61+

0 commit comments

Comments
 (0)