Skip to content

Commit 1cdb86c

Browse files
committed
Add span_bug for locals larger than 1GB
1 parent ef49365 commit 1cdb86c

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
2727
use self::operand::{OperandRef, OperandValue};
2828
use self::place::PlaceRef;
2929

30+
const MIN_DANGEROUS_SIZE: u64 = 1024 * 1024 * 1024 * 1; // 1 GB
31+
3032
// Used for tracking the state of generated basic blocks.
3133
enum CachedLlbb<T> {
3234
/// Nothing created yet.
@@ -227,6 +229,16 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
227229
let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
228230
assert!(!layout.ty.has_erasable_regions());
229231

232+
if layout.size.bytes() >= MIN_DANGEROUS_SIZE {
233+
let size_str = || {
234+
let (size_quantity, size_unit) = human_readable_bytes(layout.size.bytes());
235+
format!("{:.2} {}", size_quantity, size_unit)
236+
};
237+
span_bug!(decl.source_info.span, "Dangerous stack allocation, size: {:?} of local: {:?} exceeds typical limits on most architectures",
238+
size_str(), local);
239+
240+
}
241+
230242
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
231243
debug!("alloc: {:?} (return place) -> place", local);
232244
let llretptr = start_bx.get_param(0);
@@ -276,6 +288,18 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
276288
}
277289
}
278290

291+
/// Formats a number of bytes into a human readable SI-prefixed size.
292+
/// Returns a tuple of `(quantity, units)`.
293+
//
294+
// Taken from Cargo:
295+
// https://github.com/rust-lang/cargo/blob/2ce45605d9db521b5fd6c1211ce8de6055fdb24e/src/cargo/util/mod.rs#L88-L95
296+
pub fn human_readable_bytes(bytes: u64) -> (f32, &'static str) {
297+
static UNITS: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
298+
let bytes = bytes as f32;
299+
let i = ((bytes.log2() / 10.0) as usize).min(UNITS.len() - 1);
300+
(bytes / 1024_f32.powi(i as i32), UNITS[i])
301+
}
302+
279303
/// Produces, for each argument, a `Value` pointing at the
280304
/// argument's value. As arguments are places, these are always
281305
/// indirect.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// build-fail
2+
3+
fn func() {
4+
const CAP: usize = std::u32::MAX as usize;
5+
let mut x: [u8; CAP>>1] = [0; CAP>>1];
6+
x[2] = 123;
7+
println!("{}", x[2]);
8+
}
9+
10+
11+
12+
fn main() {
13+
std::thread::Builder::new()
14+
.stack_size(5 * 1024 * 1024 * 1024)
15+
.spawn(func)
16+
.unwrap()
17+
.join()
18+
.unwrap();
19+
}
20+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
WARN rustc_codegen_ssa::mir Dangerous stack allocation, size: "2.00 GiB" of local: _1 exceeds typical limits on most architectures

0 commit comments

Comments
 (0)