-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add diagnostic for stack allocations of 1 GB or more #119798
base: master
Are you sure you want to change the base?
Changes from all commits
48975e3
1dbc746
3cb7556
9953a42
5d77f9b
91c22d1
a0338cf
deb7c8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,12 +1,14 @@ | ||||||
use std::iter; | ||||||
|
||||||
use rustc_hir::CRATE_HIR_ID; | ||||||
use rustc_index::IndexVec; | ||||||
use rustc_index::bit_set::BitSet; | ||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; | ||||||
use rustc_middle::mir::{UnwindTerminateReason, traversal}; | ||||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; | ||||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; | ||||||
use rustc_middle::{bug, mir, span_bug}; | ||||||
use rustc_session::lint; | ||||||
use rustc_target::abi::call::{FnAbi, PassMode}; | ||||||
use tracing::{debug, instrument}; | ||||||
|
||||||
|
@@ -29,6 +31,8 @@ use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo}; | |||||
use self::operand::{OperandRef, OperandValue}; | ||||||
use self::place::PlaceRef; | ||||||
|
||||||
const MIN_DANGEROUS_SIZE: u64 = 1024 * 1024 * 1024 * 1; // 1 GB | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not to change, but to discuss: would making this lower than 1GB be worth it, so that people that we can guide people that are not hitting the limits, but are on their way to do so get some early warning? |
||||||
|
||||||
// Used for tracking the state of generated basic blocks. | ||||||
enum CachedLlbb<T> { | ||||||
/// Nothing created yet. | ||||||
|
@@ -234,6 +238,21 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |||||
let layout = start_bx.layout_of(fx.monomorphize(decl.ty)); | ||||||
assert!(!layout.ty.has_erasable_regions()); | ||||||
|
||||||
if layout.size.bytes() >= MIN_DANGEROUS_SIZE { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
let (size_quantity, size_unit) = human_readable_bytes(layout.size.bytes()); | ||||||
cx.tcx().node_span_lint( | ||||||
lint::builtin::DANGEROUS_STACK_ALLOCATION, | ||||||
CRATE_HIR_ID, | ||||||
decl.source_info.span, | ||||||
|lint| { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could add more context, like in the lint description, about some common platform limits. |
||||||
lint.primary_message(format!( | ||||||
"allocation of size: {:.2} {} exceeds most system architecture limits", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
size_quantity, size_unit | ||||||
)); | ||||||
}, | ||||||
); | ||||||
} | ||||||
|
||||||
if local == mir::RETURN_PLACE { | ||||||
match fx.fn_abi.ret.mode { | ||||||
PassMode::Indirect { .. } => { | ||||||
|
@@ -299,6 +318,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( | |||||
} | ||||||
} | ||||||
|
||||||
/// Formats a number of bytes into a human readable SI-prefixed size. | ||||||
/// Returns a tuple of `(quantity, units)`. | ||||||
pub fn human_readable_bytes(bytes: u64) -> (u64, &'static str) { | ||||||
static UNITS: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; | ||||||
let i = ((bytes.checked_ilog2().unwrap_or(0) / 10) as usize).min(UNITS.len() - 1); | ||||||
(bytes >> (10 * i), UNITS[i]) | ||||||
} | ||||||
Comment on lines
+321
to
+327
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could have sworn that we did this already, but alas it is in cargo 😅 |
||||||
|
||||||
/// Produces, for each argument, a `Value` pointing at the | ||||||
/// argument's value. As arguments are places, these are always | ||||||
/// indirect. | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -31,6 +31,7 @@ declare_lint_pass! { | |||||||||||||||||||||||||||||
CONFLICTING_REPR_HINTS, | ||||||||||||||||||||||||||||||
CONST_EVALUATABLE_UNCHECKED, | ||||||||||||||||||||||||||||||
CONST_ITEM_MUTATION, | ||||||||||||||||||||||||||||||
DANGEROUS_STACK_ALLOCATION, | ||||||||||||||||||||||||||||||
DEAD_CODE, | ||||||||||||||||||||||||||||||
DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, | ||||||||||||||||||||||||||||||
DEPRECATED, | ||||||||||||||||||||||||||||||
|
@@ -709,6 +710,50 @@ declare_lint! { | |||||||||||||||||||||||||||||
"detect assignments that will never be read" | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
declare_lint! { | ||||||||||||||||||||||||||||||
/// The `dangerous_stack_allocation` lint detects stack allocations that | ||||||||||||||||||||||||||||||
/// are 1 GB or more. | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
/// ### Example | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
/// ``` rust | ||||||||||||||||||||||||||||||
/// fn func() { | ||||||||||||||||||||||||||||||
/// const CAP: usize = std::u32::MAX as usize; | ||||||||||||||||||||||||||||||
/// let mut x: [u8; CAP>>1] = [0; CAP>>1]; | ||||||||||||||||||||||||||||||
/// x[2] = 123; | ||||||||||||||||||||||||||||||
/// println!("{}", x[2]); | ||||||||||||||||||||||||||||||
/// } | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
/// fn main() { | ||||||||||||||||||||||||||||||
/// std::thread::Builder::new() | ||||||||||||||||||||||||||||||
/// .stack_size(3 * 1024 * 1024 * 1024) | ||||||||||||||||||||||||||||||
/// .spawn(func) | ||||||||||||||||||||||||||||||
/// .unwrap() | ||||||||||||||||||||||||||||||
/// .join() | ||||||||||||||||||||||||||||||
/// .unwrap(); | ||||||||||||||||||||||||||||||
/// } | ||||||||||||||||||||||||||||||
/// ``` | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
/// {{produces}} | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
/// ```text | ||||||||||||||||||||||||||||||
/// warning: allocation of size: 1 GiB exceeds most system architecture limits | ||||||||||||||||||||||||||||||
/// --> $DIR/large-stack-size-issue-83060.rs:7:9 | ||||||||||||||||||||||||||||||
/// | | ||||||||||||||||||||||||||||||
/// LL | let mut x: [u8; CAP>>1] = [0; CAP>>1]; | ||||||||||||||||||||||||||||||
/// | ^^^^^ | ||||||||||||||||||||||||||||||
/// | | ||||||||||||||||||||||||||||||
/// = note: `#[warn(dangerous_stack_allocation)]` on by default | ||||||||||||||||||||||||||||||
Comment on lines
+740
to
+746
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will likely fail because of the textual formatting not being correctly left aligned.
Comment on lines
+740
to
+746
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
/// ``` | ||||||||||||||||||||||||||||||
/// ### Explanation | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
/// Large arras may cause stack overflow due to the limited size of the | ||||||||||||||||||||||||||||||
/// stack on most platforms. | ||||||||||||||||||||||||||||||
Comment on lines
+750
to
+751
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We should probably extend this to be more explicit about which platforms this is an issue in (no need to be exhaustive). |
||||||||||||||||||||||||||||||
pub DANGEROUS_STACK_ALLOCATION, | ||||||||||||||||||||||||||||||
Warn, | ||||||||||||||||||||||||||||||
"Detects dangerous stack allocations at the limit of most architectures" | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
declare_lint! { | ||||||||||||||||||||||||||||||
/// The `dead_code` lint detects unused, unexported items. | ||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// This test checks that allocating a stack size of 1GB or more results in a warning | ||
//@build-pass | ||
//@ only-64bit | ||
|
||
fn func() { | ||
const CAP: usize = std::u32::MAX as usize; | ||
let mut x: [u8; CAP>>1] = [0; CAP>>1]; | ||
//~^ warning: allocation of size: 1 GiB exceeds most system architecture limits | ||
//~| NOTE on by default | ||
x[2] = 123; | ||
println!("{}", x[2]); | ||
} | ||
|
||
fn main() { | ||
std::thread::Builder::new() | ||
.stack_size(3 * 1024 * 1024 * 1024) | ||
.spawn(func) | ||
.unwrap() | ||
.join() | ||
.unwrap(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
warning: allocation of size: 1 GiB exceeds most system architecture limits | ||
--> $DIR/large-stack-size-issue-83060.rs:7:9 | ||
| | ||
LL | let mut x: [u8; CAP>>1] = [0; CAP>>1]; | ||
| ^^^^^ | ||
| | ||
= note: `#[warn(dangerous_stack_allocation)]` on by default | ||
|
||
warning: 1 warning emitted | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the
ftl
change are no longer used, right?