From fdef3848a01c4567abd326043b797f6bdc3f3e76 Mon Sep 17 00:00:00 2001 From: Vitaly _Vi Shukela Date: Fri, 30 Nov 2018 00:06:10 +0300 Subject: [PATCH 1/3] Add libstd and libcore Cargo features "panic_immediate_abort" It stop asserts and panics from libstd to automatically include string output and formatting code. Use case: developing static executables smaller than 50 kilobytes, where usual formatting code is excessive while keeping debuggability in debug mode. May resolve #54981. --- src/libcore/Cargo.toml | 4 ++++ src/libcore/panicking.rs | 24 +++++++++++++++++++++--- src/libstd/Cargo.toml | 3 +++ src/libstd/panicking.rs | 17 +++++++++++++++-- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 0b01cfc488bba..7fd61f07d5e7f 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -21,3 +21,7 @@ path = "../libcore/benches/lib.rs" [dev-dependencies] rand = "0.5" + +[features] +# Make panics and failed asserts immediately abort without formatting any message +panic_immediate_abort = [] diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 58407de9566e9..67c0b6ada9055 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -39,9 +39,15 @@ use fmt; use panic::{Location, PanicInfo}; -#[cold] #[inline(never)] // this is the slow path, always +#[cold] +// inline(never) is required even in panic_immediate_abort mode, lest linker error +#[inline(never)] #[lang = "panic"] pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { super::intrinsics::abort() } + }; + // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially // reduce size overhead. The format_args! macro uses str's Display trait to // write expr, which calls Formatter::pad, which must accommodate string @@ -52,16 +58,28 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col)) } -#[cold] #[inline(never)] +#[cold] +// inline(never) is required even in panic_immediate_abort mode, lest linker error +#[inline(never)] #[lang = "panic_bounds_check"] fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), index: usize, len: usize) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { super::intrinsics::abort() } + }; + panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", len, index), file_line_col) } -#[cold] #[inline(never)] +#[cold] +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] +#[cfg_attr( feature="panic_immediate_abort" ,inline)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { super::intrinsics::abort() } + }; + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe extern "Rust" { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 2b1d515c83b75..c1446218367e4 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -47,6 +47,9 @@ backtrace = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] +# Make panics and failed asserts immediately abort without formatting any message +panic_immediate_abort = ["core/panic_immediate_abort"] + # An off-by-default feature which enables a linux-syscall-like ABI for libstd to # interoperate with the host environment. Currently not well documented and # requires rebuilding the standard library to use it. diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index a0590a800d3cc..29a0b3feefdfa 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -334,9 +334,15 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "0")] -#[inline(never)] #[cold] +#[cold] +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] +#[cfg_attr( feature="panic_immediate_abort" ,inline)] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { intrinsics::abort() } + }; + let (file, line, col) = *file_line_col; let info = PanicInfo::internal_constructor( Some(msg), @@ -398,8 +404,15 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[cfg_attr(not(test), lang = "begin_panic")] -#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible +// avoid code bloat at the call sites as much as possible +// inline(never) is required even in panic_immediate_abort mode, lest linker error +#[inline(never)] +#[cold] pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { + if cfg!(feature = "panic_immediate_abort") { + unsafe { intrinsics::abort() } + }; + // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If From d3f9788e596f9b7f07c165e0f382dbe2cdb02b6e Mon Sep 17 00:00:00 2001 From: Vitaly _Vi Shukela Date: Fri, 30 Nov 2018 02:17:05 +0300 Subject: [PATCH 2/3] panic_immediate_abort: Fix issues from review --- src/libcore/panicking.rs | 13 ++++++------- src/libstd/panicking.rs | 11 ++++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 67c0b6ada9055..834fcd246c532 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -40,13 +40,13 @@ use fmt; use panic::{Location, PanicInfo}; #[cold] -// inline(never) is required even in panic_immediate_abort mode, lest linker error -#[inline(never)] +// never inline unless panic_immediate_abort to avoid code bloat at the call sites as much as possible +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[lang = "panic"] pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { super::intrinsics::abort() } - }; + } // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially // reduce size overhead. The format_args! macro uses str's Display trait to @@ -59,14 +59,13 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { } #[cold] -// inline(never) is required even in panic_immediate_abort mode, lest linker error -#[inline(never)] +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[lang = "panic_bounds_check"] fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), index: usize, len: usize) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { super::intrinsics::abort() } - }; + } panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", len, index), file_line_col) @@ -78,7 +77,7 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { super::intrinsics::abort() } - }; + } // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 29a0b3feefdfa..82ceec62f357a 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -335,13 +335,15 @@ pub fn rust_begin_panic(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[cold] +// If panic_immediate_abort, inline the abort call, +// otherwise avoid inlining because of it is cold path. #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[cfg_attr( feature="panic_immediate_abort" ,inline)] pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { intrinsics::abort() } - }; + } let (file, line, col) = *file_line_col; let info = PanicInfo::internal_constructor( @@ -404,14 +406,13 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[cfg_attr(not(test), lang = "begin_panic")] -// avoid code bloat at the call sites as much as possible -// inline(never) is required even in panic_immediate_abort mode, lest linker error -#[inline(never)] +// never inline unless panic_immediate_abort to avoid code bloat at the call sites as much as possible +#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[cold] pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { if cfg!(feature = "panic_immediate_abort") { unsafe { intrinsics::abort() } - }; + } // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, From f18a8c6163fa3b1eef5aabd1baf1eef2b9789c46 Mon Sep 17 00:00:00 2001 From: Vitaly _Vi Shukela Date: Fri, 30 Nov 2018 02:37:04 +0300 Subject: [PATCH 3/3] Fix exceeding line width limit --- src/libcore/panicking.rs | 3 ++- src/libstd/panicking.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 834fcd246c532..aa18a60fc0f6d 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -40,7 +40,8 @@ use fmt; use panic::{Location, PanicInfo}; #[cold] -// never inline unless panic_immediate_abort to avoid code bloat at the call sites as much as possible +// never inline unless panic_immediate_abort to avoid code +// bloat at the call sites as much as possible #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[lang = "panic"] pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 82ceec62f357a..4930d35660814 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -406,7 +406,8 @@ fn continue_panic_fmt(info: &PanicInfo) -> ! { reason = "used by the panic! macro", issue = "0")] #[cfg_attr(not(test), lang = "begin_panic")] -// never inline unless panic_immediate_abort to avoid code bloat at the call sites as much as possible +// never inline unless panic_immediate_abort to avoid code +// bloat at the call sites as much as possible #[cfg_attr(not(feature="panic_immediate_abort"),inline(never))] #[cold] pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! {