Skip to content

Commit 353668e

Browse files
committed
Merge remote-tracking branch 'Areredify/large_stack_arrays' into rollup-new-lints
2 parents 213765a + 7fddac0 commit 353668e

File tree

8 files changed

+148
-1
lines changed

8 files changed

+148
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@ Released 2018-09-13
10601060
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
10611061
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
10621062
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
1063+
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
10631064
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
10641065
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
10651066
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
+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
@@ -212,6 +212,7 @@ pub mod int_plus_one;
212212
pub mod integer_division;
213213
pub mod items_after_statements;
214214
pub mod large_enum_variant;
215+
pub mod large_stack_arrays;
215216
pub mod len_zero;
216217
pub mod let_if_seq;
217218
pub mod lifetimes;
@@ -539,6 +540,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
539540
&integer_division::INTEGER_DIVISION,
540541
&items_after_statements::ITEMS_AFTER_STATEMENTS,
541542
&large_enum_variant::LARGE_ENUM_VARIANT,
543+
&large_stack_arrays::LARGE_STACK_ARRAYS,
542544
&len_zero::LEN_WITHOUT_IS_EMPTY,
543545
&len_zero::LEN_ZERO,
544546
&let_if_seq::USELESS_LET_IF_SEQ,
@@ -952,6 +954,8 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
952954
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
953955
store.register_late_pass(|| box exit::Exit);
954956
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
957+
let array_size_threshold = conf.array_size_threshold;
958+
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
955959

956960
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
957961
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1006,6 +1010,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
10061010
LintId::of(&if_not_else::IF_NOT_ELSE),
10071011
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
10081012
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
1013+
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
10091014
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
10101015
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
10111016
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

+7
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,13 @@ pub const ALL_LINTS: [Lint; 334] = [
910910
deprecation: None,
911911
module: "large_enum_variant",
912912
},
913+
Lint {
914+
name: "large_stack_arrays",
915+
group: "pedantic",
916+
desc: "allocating large arrays on stack may cause stack overflow",
917+
deprecation: None,
918+
module: "large_stack_arrays",
919+
},
913920
Lint {
914921
name: "len_without_is_empty",
915922
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)