Add new lint: large stack array

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
This commit is contained in:
Areredify 2019-11-12 22:22:53 +00:00 committed by Mikhail Babenko
parent 79d3b30cd7
commit 7fddac0404
9 changed files with 150 additions and 3 deletions

View file

@ -1059,6 +1059,7 @@ Released 2018-09-13
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups [`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant [`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return

View file

@ -6,7 +6,7 @@
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
[There are 333 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) [There are 334 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:

View file

@ -0,0 +1,67 @@
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::mir::interpret::ConstValue;
use rustc::ty;
use rustc::{declare_tool_lint, impl_lint_pass};
use if_chain::if_chain;
use crate::rustc_target::abi::LayoutOf;
use crate::utils::{snippet, span_help_and_lint};
declare_clippy_lint! {
/// **What it does:** Checks for local arrays that may be too large.
///
/// **Why is this bad?** Large local arrays may cause stack overflow.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust,ignore
/// let a = [0u32; 1_000_000];
/// ```
pub LARGE_STACK_ARRAYS,
pedantic,
"allocating large arrays on stack may cause stack overflow"
}
pub struct LargeStackArrays {
maximum_allowed_size: u64,
}
impl LargeStackArrays {
#[must_use]
pub fn new(maximum_allowed_size: u64) -> Self {
Self { maximum_allowed_size }
}
}
impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeStackArrays {
fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr) {
if_chain! {
if let ExprKind::Repeat(_, _) = expr.kind;
if let ty::Array(element_type, cst) = cx.tables.expr_ty(expr).kind;
if let ConstValue::Scalar(element_count) = cst.val;
if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
if self.maximum_allowed_size < element_count * element_size;
then {
span_help_and_lint(
cx,
LARGE_STACK_ARRAYS,
expr.span,
&format!(
"allocating a local array larger than {} bytes",
self.maximum_allowed_size
),
&format!(
"consider allocating on the heap with vec!{}.into_boxed_slice()",
snippet(cx, expr.span, "[...]")
),
);
}
}
}
}

View file

@ -211,6 +211,7 @@ pub mod int_plus_one;
pub mod integer_division; pub mod integer_division;
pub mod items_after_statements; pub mod items_after_statements;
pub mod large_enum_variant; pub mod large_enum_variant;
pub mod large_stack_arrays;
pub mod len_zero; pub mod len_zero;
pub mod let_if_seq; pub mod let_if_seq;
pub mod lifetimes; pub mod lifetimes;
@ -537,6 +538,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
&integer_division::INTEGER_DIVISION, &integer_division::INTEGER_DIVISION,
&items_after_statements::ITEMS_AFTER_STATEMENTS, &items_after_statements::ITEMS_AFTER_STATEMENTS,
&large_enum_variant::LARGE_ENUM_VARIANT, &large_enum_variant::LARGE_ENUM_VARIANT,
&large_stack_arrays::LARGE_STACK_ARRAYS,
&len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_WITHOUT_IS_EMPTY,
&len_zero::LEN_ZERO, &len_zero::LEN_ZERO,
&let_if_seq::USELESS_LET_IF_SEQ, &let_if_seq::USELESS_LET_IF_SEQ,
@ -949,6 +951,8 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
store.register_late_pass(|| box exit::Exit); store.register_late_pass(|| box exit::Exit);
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
let array_size_threshold = conf.array_size_threshold;
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC), LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1002,6 +1006,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
LintId::of(&if_not_else::IF_NOT_ELSE), LintId::of(&if_not_else::IF_NOT_ELSE),
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP),

View file

@ -151,6 +151,8 @@ define_Conf! {
(trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>), (trivial_copy_size_limit, "trivial_copy_size_limit", None => Option<u64>),
/// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have /// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
(too_many_lines_threshold, "too_many_lines_threshold", 100 => u64), (too_many_lines_threshold, "too_many_lines_threshold", 100 => u64),
/// Lint: LARGE_STACK_ARRAYS. The maximum allowed size for arrays on the stack
(array_size_threshold, "array_size_threshold", 512_000 => u64),
} }
impl Default for Conf { impl Default for Conf {

View file

@ -6,7 +6,7 @@ pub use lint::Lint;
pub use lint::LINT_LEVELS; pub use lint::LINT_LEVELS;
// begin lint list, do not remove this comment, its used in `update_lints` // begin lint list, do not remove this comment, its used in `update_lints`
pub const ALL_LINTS: [Lint; 333] = [ pub const ALL_LINTS: [Lint; 334] = [
Lint { Lint {
name: "absurd_extreme_comparisons", name: "absurd_extreme_comparisons",
group: "correctness", group: "correctness",
@ -903,6 +903,13 @@ pub const ALL_LINTS: [Lint; 333] = [
deprecation: None, deprecation: None,
module: "large_enum_variant", module: "large_enum_variant",
}, },
Lint {
name: "large_stack_arrays",
group: "pedantic",
desc: "allocating large arrays on stack may cause stack overflow",
deprecation: None,
module: "large_stack_arrays",
},
Lint { Lint {
name: "len_without_is_empty", name: "len_without_is_empty",
group: "style", group: "style",

View file

@ -1,4 +1,4 @@
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 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
error: aborting due to previous error error: aborting due to previous error

View file

@ -0,0 +1,30 @@
#![warn(clippy::large_stack_arrays)]
#![allow(clippy::large_enum_variant)]
#[derive(Clone, Copy)]
struct S {
pub data: [u64; 32],
}
#[derive(Clone, Copy)]
enum E {
S(S),
T(u32),
}
fn main() {
let bad = (
[0u32; 20_000_000],
[S { data: [0; 32] }; 5000],
[Some(""); 20_000_000],
[E::T(0); 5000],
);
let good = (
[0u32; 1000],
[S { data: [0; 32] }; 1000],
[Some(""); 1000],
[E::T(0); 1000],
[(); 20_000_000],
);
}

View file

@ -0,0 +1,35 @@
error: allocating a local array larger than 512000 bytes
--> $DIR/large_stack_arrays.rs:17:9
|
LL | [0u32; 20_000_000],
| ^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::large-stack-arrays` implied by `-D warnings`
= help: consider allocating on the heap with vec![0u32; 20_000_000].into_boxed_slice()
error: allocating a local array larger than 512000 bytes
--> $DIR/large_stack_arrays.rs:18:9
|
LL | [S { data: [0; 32] }; 5000],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider allocating on the heap with vec![S { data: [0; 32] }; 5000].into_boxed_slice()
error: allocating a local array larger than 512000 bytes
--> $DIR/large_stack_arrays.rs:19:9
|
LL | [Some(""); 20_000_000],
| ^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider allocating on the heap with vec![Some(""); 20_000_000].into_boxed_slice()
error: allocating a local array larger than 512000 bytes
--> $DIR/large_stack_arrays.rs:20:9
|
LL | [E::T(0); 5000],
| ^^^^^^^^^^^^^^^
|
= help: consider allocating on the heap with vec![E::T(0); 5000].into_boxed_slice()
error: aborting due to 4 previous errors