Skip to content

Commit 8648e3d

Browse files
committed
initial implementation
added documentation minor style fix change as to ::from add ignore to doc include threshold in lint message/make suggestion more apparent/use Scalar api instead of matching style fix shange snippet_opt to snippet
1 parent 79d3b30 commit 8648e3d

File tree

9 files changed

+150
-3
lines changed

9 files changed

+150
-3
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,7 @@ Released 2018-09-13
10591059
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
10601060
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
10611061
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
1062+
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
10621063
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
10631064
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
10641065
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1212

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use rustc::hir::*;
2+
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
3+
use rustc::mir::interpret::ConstValue;
4+
use rustc::ty;
5+
use rustc::{declare_tool_lint, impl_lint_pass};
6+
7+
use if_chain::if_chain;
8+
9+
use crate::rustc_target::abi::LayoutOf;
10+
use crate::utils::{snippet, span_help_and_lint};
11+
12+
declare_clippy_lint! {
13+
/// **What it does:** Checks for local arrays that may be too large.
14+
///
15+
/// **Why is this bad?** Large local arrays may cause stack overflow.
16+
///
17+
/// **Known problems:** None.
18+
///
19+
/// **Example:**
20+
/// ```rust,ignore
21+
/// let a = [0u32; 1_000_000];
22+
/// ```
23+
pub LARGE_STACK_ARRAYS,
24+
pedantic,
25+
"allocating large arrays on stack may cause stack overflow"
26+
}
27+
28+
pub struct LargeStackArrays {
29+
maximum_allowed_size: u64,
30+
}
31+
32+
impl LargeStackArrays {
33+
#[must_use]
34+
pub fn new(maximum_allowed_size: u64) -> Self {
35+
Self { maximum_allowed_size }
36+
}
37+
}
38+
39+
impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
40+
41+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays {
42+
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
43+
if_chain! {
44+
if let ExprKind::Repeat(_, _) = expr.kind;
45+
if let ty::Array(element_type, cst) = cx.tables.expr_ty(expr).kind;
46+
if let ConstValue::Scalar(element_count) = cst.val;
47+
if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
48+
if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
49+
if self.maximum_allowed_size < element_count * element_size;
50+
then {
51+
span_help_and_lint(
52+
cx,
53+
LARGE_STACK_ARRAYS,
54+
expr.span,
55+
&format!(
56+
"allocating a local array larger than {} bytes",
57+
self.maximum_allowed_size
58+
),
59+
&format!(
60+
"consider allocating on the heap with vec!{}.into_boxed_slice()",
61+
snippet(cx, expr.span, "[...]")
62+
),
63+
);
64+
}
65+
}
66+
}
67+
}

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ pub mod int_plus_one;
211211
pub mod integer_division;
212212
pub mod items_after_statements;
213213
pub mod large_enum_variant;
214+
pub mod large_stack_arrays;
214215
pub mod len_zero;
215216
pub mod let_if_seq;
216217
pub mod lifetimes;
@@ -537,6 +538,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
537538
&integer_division::INTEGER_DIVISION,
538539
&items_after_statements::ITEMS_AFTER_STATEMENTS,
539540
&large_enum_variant::LARGE_ENUM_VARIANT,
541+
&large_stack_arrays::LARGE_STACK_ARRAYS,
540542
&len_zero::LEN_WITHOUT_IS_EMPTY,
541543
&len_zero::LEN_ZERO,
542544
&let_if_seq::USELESS_LET_IF_SEQ,
@@ -949,6 +951,8 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
949951
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
950952
store.register_late_pass(|| box exit::Exit);
951953
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
954+
let array_size_threshold = conf.array_size_threshold;
955+
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
952956

953957
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
954958
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1002,6 +1006,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
10021006
LintId::of(&if_not_else::IF_NOT_ELSE),
10031007
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
10041008
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
1009+
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
10051010
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
10061011
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
10071012
LintId::of(&loops::EXPLICIT_ITER_LOOP),

clippy_lints/src/utils/conf.rs

+2
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ define_Conf! {
151151
(trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
152152
/// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
153153
(too_many_lines_threshold, "too_many_lines_threshold", 100 => u64),
154+
/// Lint: LARGE_STACK_ARRAYS. The maximum allowed size for arrays on the stack
155+
(array_size_threshold, "array_size_threshold", 512_000 => u64),
154156
}
155157

156158
impl Default for Conf {

src/lintlist/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use lint::Lint;
66
pub use lint::LINT_LEVELS;
77

88
// begin lint list, do not remove this comment, it’s used in `update_lints`
9-
pub const ALL_LINTS: [Lint; 333] = [
9+
pub const ALL_LINTS: [Lint; 334] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -903,6 +903,13 @@ pub const ALL_LINTS: [Lint; 333] = [
903903
deprecation: None,
904904
module: "large_enum_variant",
905905
},
906+
Lint {
907+
name: "large_stack_arrays",
908+
group: "pedantic",
909+
desc: "allocating large arrays on stack may cause stack overflow",
910+
deprecation: None,
911+
module: "large_stack_arrays",
912+
},
906913
Lint {
907914
name: "len_without_is_empty",
908915
group: "style",
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `third-party` at line 5 column 1
1+
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `third-party` at line 5 column 1
22

33
error: aborting due to previous error
44

tests/ui/large_stack_arrays.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![warn(clippy::large_stack_arrays)]
2+
#![allow(clippy::large_enum_variant)]
3+
4+
#[derive(Clone, Copy)]
5+
struct S {
6+
pub data: [u64; 32],
7+
}
8+
9+
#[derive(Clone, Copy)]
10+
enum E {
11+
S(S),
12+
T(u32),
13+
}
14+
15+
fn main() {
16+
let bad = (
17+
[0u32; 20_000_000],
18+
[S { data: [0; 32] }; 5000],
19+
[Some(""); 20_000_000],
20+
[E::T(0); 5000],
21+
);
22+
23+
let good = (
24+
[0u32; 1000],
25+
[S { data: [0; 32] }; 1000],
26+
[Some(""); 1000],
27+
[E::T(0); 1000],
28+
[(); 20_000_000],
29+
);
30+
}

tests/ui/large_stack_arrays.stderr

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: allocating a local array larger than 512000 bytes
2+
--> $DIR/large_stack_arrays.rs:17:9
3+
|
4+
LL | [0u32; 20_000_000],
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::large-stack-arrays` implied by `-D warnings`
8+
= help: consider allocating on the heap with vec![0u32; 20_000_000].into_boxed_slice()
9+
10+
error: allocating a local array larger than 512000 bytes
11+
--> $DIR/large_stack_arrays.rs:18:9
12+
|
13+
LL | [S { data: [0; 32] }; 5000],
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: consider allocating on the heap with vec![S { data: [0; 32] }; 5000].into_boxed_slice()
17+
18+
error: allocating a local array larger than 512000 bytes
19+
--> $DIR/large_stack_arrays.rs:19:9
20+
|
21+
LL | [Some(""); 20_000_000],
22+
| ^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
= help: consider allocating on the heap with vec![Some(""); 20_000_000].into_boxed_slice()
25+
26+
error: allocating a local array larger than 512000 bytes
27+
--> $DIR/large_stack_arrays.rs:20:9
28+
|
29+
LL | [E::T(0); 5000],
30+
| ^^^^^^^^^^^^^^^
31+
|
32+
= help: consider allocating on the heap with vec![E::T(0); 5000].into_boxed_slice()
33+
34+
error: aborting due to 4 previous errors
35+

0 commit comments

Comments
 (0)