From 409e33b73146ee6ba5fb2e37e60e04ffd7ab6c64 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 27 Nov 2023 14:02:15 +0300 Subject: [PATCH 01/39] feat(gstd): get panic message without `panic_info_message` --- gstd/Cargo.toml | 6 +---- gstd/src/common/handlers.rs | 49 ++++++++++++++++++++++--------------- gstd/src/lib.rs | 4 --- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index ab8ddff724f..d11cce7b96d 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -32,10 +32,7 @@ panic-handler = [] ## Enables all features below. ## These features depend on unstable Rust API and require nightly toolchain. -nightly = ["panic-messages", "oom-handler"] -## When enabled, additional context information is available from -## panic messages in debug mode. Relies on [`panic_info_message`][rust-66745]. -panic-messages = [] +nightly = ["oom-handler"] ## When enabled, an OOM error handler is provided. ## Relies on [`alloc_error_handler`][rust-51540], oom-handler = [] @@ -46,7 +43,6 @@ oom-handler = [] ## and is therefore disabled by default. debug = ["galloc/debug", "gcore/debug"] -#! [rust-66745]: https://github.com/rust-lang/rust/issues/66745 #! [rust-51540]: https://github.com/rust-lang/rust/issues/51540 [package.metadata.docs.rs] diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index b13ea53f285..1a540286ebd 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -45,29 +45,38 @@ mod panic_handler { #[cfg(feature = "debug")] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::format; - #[cfg(not(feature = "panic-messages"))] - let message = None::<&core::fmt::Arguments<'_>>; - #[cfg(feature = "panic-messages")] - let message = panic_info.message(); + use crate::prelude::{borrow::Cow, format, ToString}; - let msg = match (message, panic_info.location()) { - (Some(msg), Some(loc)) => format!( - "'{:?}', {}:{}:{}", - msg, - loc.file(), - loc.line(), - loc.column() - ), - (Some(msg), None) => format!("'{msg:?}'"), - (None, Some(loc)) => { - format!("{}:{}:{}", loc.file(), loc.line(), loc.column()) - } - _ => ext::panic("no info"), + // Default panic handler message format: + // Rust <1.73: `panicked at '{message}', {location}` + // Rust >=1.73: `panicked at {location}:\n{message}` + // source: https://github.com/rust-lang/rust/pull/112849 + + const PANICKED_AT_LEN: usize = "panicked at ".len(); + + let default_panic_msg = panic_info.to_string(); + let is_old_panic_format = default_panic_msg.as_bytes().get(PANICKED_AT_LEN) == Some(&b'\''); + + let maybe_panic_msg = if is_old_panic_format { + default_panic_msg.get(PANICKED_AT_LEN..).map(Cow::Borrowed) + } else { + let mut iter = default_panic_msg.splitn(2, ":\n"); + iter.next().zip(iter.next()).and_then(|(line1, line2)| { + let msg = line2; + line1 + .get(PANICKED_AT_LEN..line1.len()) + .map(|location| Cow::Owned(format!("'{msg}', {location}"))) + }) }; - crate::debug!("panic occurred: {msg}"); - ext::panic(&msg) + if let Some(ref panic_msg) = maybe_panic_msg { + let msg = panic_msg.as_ref(); + + crate::debug!("panic occurred: {msg}"); + ext::panic(msg) + } else { + ext::panic("no info") + } } } #[cfg(feature = "panic-handler")] diff --git a/gstd/src/lib.rs b/gstd/src/lib.rs index 6749a219a01..2c40add327a 100644 --- a/gstd/src/lib.rs +++ b/gstd/src/lib.rs @@ -128,10 +128,6 @@ #![no_std] #![warn(missing_docs)] -#![cfg_attr( - all(target_arch = "wasm32", feature = "panic-messages",), - feature(panic_info_message) -)] #![cfg_attr( all(target_arch = "wasm32", feature = "oom-handler"), feature(alloc_error_handler) From bab3417ec44926cfdcdcc2d35568f7617d7017b1 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:34:48 +0300 Subject: [PATCH 02/39] keep feature --- Cargo.toml | 2 +- gstd/Cargo.toml | 6 +++++- gstd/src/common/handlers.rs | 25 +++++++++++++++++++++++++ gstd/src/lib.rs | 4 ++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2b8fad3ce2..abca77fd819 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -200,7 +200,7 @@ gcore = { path = "gcore" } gcli = { path = "gcli" } gclient = { path = "gclient" } gsdk = { path = "gsdk" } -gstd = { path = "gstd", features = [ "nightly" ] } +gstd = { path = "gstd", features = ["nightly"] } gsys = { path = "gsys" } gtest = { path = "gtest" } gmeta = { path = "gmeta" } diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index d11cce7b96d..ab8ddff724f 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -32,7 +32,10 @@ panic-handler = [] ## Enables all features below. ## These features depend on unstable Rust API and require nightly toolchain. -nightly = ["oom-handler"] +nightly = ["panic-messages", "oom-handler"] +## When enabled, additional context information is available from +## panic messages in debug mode. Relies on [`panic_info_message`][rust-66745]. +panic-messages = [] ## When enabled, an OOM error handler is provided. ## Relies on [`alloc_error_handler`][rust-51540], oom-handler = [] @@ -43,6 +46,7 @@ oom-handler = [] ## and is therefore disabled by default. debug = ["galloc/debug", "gcore/debug"] +#! [rust-66745]: https://github.com/rust-lang/rust/issues/66745 #! [rust-51540]: https://github.com/rust-lang/rust/issues/51540 [package.metadata.docs.rs] diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 1a540286ebd..9874ac7b3f7 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -42,7 +42,32 @@ mod panic_handler { ext::panic("no info") } + /// Panic handler for nightly Rust. #[cfg(feature = "debug")] + #[cfg(feature = "panic-messages")] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::format; + + let message = panic_info.message(); + let msg = match (message, panic_info.location()) { + (Some(msg), Some(loc)) => { + format!("'{msg}', {}:{}:{}", loc.file(), loc.line(), loc.column()) + } + (Some(msg), None) => format!("'{msg}'"), + (None, Some(loc)) => { + format!("{}:{}:{}", loc.file(), loc.line(), loc.column()) + } + _ => ext::panic("no info"), + }; + + crate::debug!("panic occurred: {msg}"); + ext::panic(&msg) + } + + /// Panic handler for stable Rust. + #[cfg(feature = "debug")] + #[cfg(not(feature = "panic-messages"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { use crate::prelude::{borrow::Cow, format, ToString}; diff --git a/gstd/src/lib.rs b/gstd/src/lib.rs index 2c40add327a..220d2449674 100644 --- a/gstd/src/lib.rs +++ b/gstd/src/lib.rs @@ -128,6 +128,10 @@ #![no_std] #![warn(missing_docs)] +#![cfg_attr( + all(target_arch = "wasm32", feature = "panic-messages"), + feature(panic_info_message) +)] #![cfg_attr( all(target_arch = "wasm32", feature = "oom-handler"), feature(alloc_error_handler) From 90dd7b8ca0c14398abcfa1798c16d2dc42580a27 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 27 Nov 2023 16:37:10 +0300 Subject: [PATCH 03/39] [ci-skip] inline var --- gstd/src/common/handlers.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 9874ac7b3f7..5e8a98fa9de 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -49,8 +49,7 @@ mod panic_handler { pub fn panic(panic_info: &PanicInfo) -> ! { use crate::prelude::format; - let message = panic_info.message(); - let msg = match (message, panic_info.location()) { + let msg = match (panic_info.message(), panic_info.location()) { (Some(msg), Some(loc)) => { format!("'{msg}', {}:{}:{}", loc.file(), loc.line(), loc.column()) } From b00d583bf05de9e2865c02c23ab78dfea3f21764 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:35:05 +0300 Subject: [PATCH 04/39] re-implement panic handler with arrayvec --- Cargo.lock | 2 + gstd/Cargo.toml | 4 +- gstd/src/common/handlers.rs | 133 ++++++++++++++++++++++++------------ 3 files changed, 96 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1dccf560b3c..ee4fba5bfbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4868,6 +4868,7 @@ dependencies = [ name = "gstd" version = "1.0.3" dependencies = [ + "arrayvec 0.7.4", "bs58 0.5.0", "document-features", "futures", @@ -4879,6 +4880,7 @@ dependencies = [ "hex", "parity-scale-codec", "primitive-types", + "rustversion", "scale-info", "static_assertions", ] diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index ab8ddff724f..d2256b4ebaf 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] +arrayvec = { version = "0.7.4", default-features = false, optional = true } document-features = { version = "0.2.7", optional = true } galloc.workspace = true gcore = { workspace = true, features = ["codec"] } @@ -16,6 +17,7 @@ bs58 = { workspace = true, features = ["alloc"] } hex = { workspace = true, features = ["alloc"] } parity-scale-codec = { workspace = true, features = ["derive"] } primitive-types = { workspace = true, features = ["scale-info"] } +rustversion = { version = "1.0", optional = true } scale-info = { workspace = true, features = ["derive"] } futures = { workspace = true, features = ["alloc"] } @@ -44,7 +46,7 @@ oom-handler = [] ## Enables debug logging; this heavily impacts gas cost ## and is therefore disabled by default. -debug = ["galloc/debug", "gcore/debug"] +debug = ["galloc/debug", "gcore/debug", "arrayvec", "rustversion"] #! [rust-66745]: https://github.com/rust-lang/rust/issues/66745 #! [rust-51540]: https://github.com/rust-lang/rust/issues/51540 diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 5e8a98fa9de..39626e4a161 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -42,65 +42,114 @@ mod panic_handler { ext::panic("no info") } + #[cfg(feature = "debug")] + mod constants { + pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: find better way to access it + pub const PANIC_OCCURRED: &str = "panic occurred: "; + #[cfg(not(feature = "panic-messages"))] + pub const PANICKED_AT: &str = "panicked at "; + } + + #[cfg(feature = "debug")] + use constants::*; + /// Panic handler for nightly Rust. #[cfg(feature = "debug")] #[cfg(feature = "panic-messages")] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::format; - - let msg = match (panic_info.message(), panic_info.location()) { - (Some(msg), Some(loc)) => { - format!("'{msg}', {}:{}:{}", loc.file(), loc.line(), loc.column()) - } - (Some(msg), None) => format!("'{msg}'"), - (None, Some(loc)) => { - format!("{}:{}:{}", loc.file(), loc.line(), loc.column()) - } - _ => ext::panic("no info"), - }; + use crate::prelude::fmt::Write; + use arrayvec::ArrayString; + + let option = panic_info.message().zip(panic_info.location()); + let (message, location) = unsafe { option.unwrap_unchecked() }; - crate::debug!("panic occurred: {msg}"); + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + let _ = write!(&mut debug_msg, "{PANIC_OCCURRED}'{message}', {location}"); + + let _ = ext::debug(&debug_msg); + + let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; ext::panic(&msg) } - /// Panic handler for stable Rust. + // Default panic handler message format: + // Rust <1.73: `panicked at '{message}', {location}` + // Rust >=1.73: `panicked at {location}:\n{message}` + // source: https://github.com/rust-lang/rust/pull/112849 + + /// Panic handler for stable Rust <1.73. + #[rustversion::before(1.73)] #[cfg(feature = "debug")] #[cfg(not(feature = "panic-messages"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::{borrow::Cow, format, ToString}; - - // Default panic handler message format: - // Rust <1.73: `panicked at '{message}', {location}` - // Rust >=1.73: `panicked at {location}:\n{message}` - // source: https://github.com/rust-lang/rust/pull/112849 - - const PANICKED_AT_LEN: usize = "panicked at ".len(); - - let default_panic_msg = panic_info.to_string(); - let is_old_panic_format = default_panic_msg.as_bytes().get(PANICKED_AT_LEN) == Some(&b'\''); - - let maybe_panic_msg = if is_old_panic_format { - default_panic_msg.get(PANICKED_AT_LEN..).map(Cow::Borrowed) - } else { - let mut iter = default_panic_msg.splitn(2, ":\n"); - iter.next().zip(iter.next()).and_then(|(line1, line2)| { - let msg = line2; - line1 - .get(PANICKED_AT_LEN..line1.len()) - .map(|location| Cow::Owned(format!("'{msg}', {location}"))) - }) + use crate::prelude::fmt::Write; + use arrayvec::ArrayString; + + static_assertions::const_assert!(PANICKED_AT.len() == (PANIC_OCCURRED.len() - 4)); + + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + + let _ = debug_msg.try_push_str(&PANIC_OCCURRED[..4]); + let _ = write!(&mut debug_msg, "{panic_info}"); + + let src = (&PANIC_OCCURRED[4..]).as_bytes(); + let dest = unsafe { + debug_msg + .as_bytes_mut() + .get_unchecked_mut(4..PANIC_OCCURRED.len()) }; + dest.copy_from_slice(src); - if let Some(ref panic_msg) = maybe_panic_msg { - let msg = panic_msg.as_ref(); + let _ = ext::debug(&debug_msg); - crate::debug!("panic occurred: {msg}"); - ext::panic(msg) - } else { - ext::panic("no info") + let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + ext::panic(&msg) + } + + /// Panic handler for stable Rust >=1.73. + #[rustversion::since(1.73)] + #[cfg(feature = "debug")] + #[cfg(not(feature = "panic-messages"))] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::{fmt::Write, str}; + use arrayvec::ArrayString; + + let mut default_panic_msg = ArrayString::<{ PANICKED_AT.len() + TRIMMED_MAX_LEN }>::new(); + let _ = write!(&mut default_panic_msg, "{panic_info}"); + + fn parse_panic_msg(msg: &str) -> Option<(&str, &str)> { + const NEEDLE: [u8; 2] = *b":\n"; + + let msg_bytes = msg.as_bytes(); + msg_bytes + .windows(NEEDLE.len()) + .position(|window| NEEDLE.eq(window)) + .map(|pos| unsafe { + ( + str::from_utf8_unchecked(msg_bytes.get_unchecked(PANICKED_AT.len()..pos)), + str::from_utf8_unchecked(msg_bytes.get_unchecked((pos + NEEDLE.len())..)), + ) + }) } + + let option = parse_panic_msg(&default_panic_msg); + let (location, message) = unsafe { option.unwrap_unchecked() }; + + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + + let _ = debug_msg.try_push_str(PANIC_OCCURRED); + let _ = debug_msg.try_push('\''); + let _ = debug_msg.try_push_str(message); + let _ = debug_msg.try_push_str("', "); + let _ = debug_msg.try_push_str(location); + + let _ = ext::debug(&debug_msg); + + let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + ext::panic(&msg) } } #[cfg(feature = "panic-handler")] From 388492c853f48c33eb2bda5fb284da73a23fed0c Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:36:00 +0300 Subject: [PATCH 05/39] add common-handlers feature and document panic_handler --- gstd/Cargo.toml | 9 +- gstd/src/common/handlers.rs | 255 +++++++++++++++++++++--------------- gstd/src/common/mod.rs | 2 +- 3 files changed, 157 insertions(+), 109 deletions(-) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index d2256b4ebaf..9ee930b17a6 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -23,12 +23,15 @@ futures = { workspace = true, features = ["alloc"] } static_assertions.workspace = true +[dev-dependencies] +rustversion = "1.0" + [features] #! ## Default features -default = ["panic-handler"] -## When enabled, a panic handler is provided by this crate. -panic-handler = [] +default = ["common-handlers"] +## When enabled, a panic handler and an OOM error handler are provided by this crate. +common-handlers = [] #! ## Nightly features diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 39626e4a161..8eb3efaaf7e 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -25,132 +25,177 @@ //! debug and non-debug mode, for programs built in `wasm32` architecture. //! For `debug` mode it provides more extensive logging. +#[cfg(target_arch = "wasm32")] #[cfg(feature = "oom-handler")] #[alloc_error_handler] pub fn oom(_: core::alloc::Layout) -> ! { crate::ext::oom_panic() } -#[cfg(feature = "panic-handler")] -mod panic_handler { - use crate::ext; - use core::panic::PanicInfo; - - #[cfg(not(feature = "debug"))] - #[panic_handler] - pub fn panic(_: &PanicInfo) -> ! { - ext::panic("no info") - } - - #[cfg(feature = "debug")] - mod constants { - pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: find better way to access it - pub const PANIC_OCCURRED: &str = "panic occurred: "; - #[cfg(not(feature = "panic-messages"))] - pub const PANICKED_AT: &str = "panicked at "; - } - - #[cfg(feature = "debug")] - use constants::*; +/// We currently support 2 panic handler modes: +/// - non-debug: it prints `no info` +/// - debug: it prints `'{message}', {location}` +/// - In nightly Rust, we use `#![feature(panic_info_message)]` and the [`write!`] macro. +/// - In stable Rust, we need to modify the default panic handler message format. +/// +/// Default panic handler message format (according to ): +/// - Rust <1.73: `panicked at '{message}', {location}` +/// - Rust >=1.73: `panicked at {location}:\n{message}` +/// +/// We parse the output of `impl Display for PanicInfo<'_>` and +/// then convert it to custom format: `'{message}', {location}`. +/// +/// Here is a test to verify that the default panic handler message format has not changed: +/// ``` +/// use std::panic::{self, PanicInfo}; +/// +/// const MESSAGE: &str = "message"; +/// +/// #[rustversion::before(1.73)] +/// fn expected_format(panic_info: &PanicInfo) -> String { +/// let location = panic_info.location().unwrap(); +/// format!("panicked at '{MESSAGE}', {location}") +/// } +/// +/// #[rustversion::since(1.73)] +/// fn expected_format(panic_info: &PanicInfo) -> String { +/// let location = panic_info.location().unwrap(); +/// format!("panicked at {location}:\n{MESSAGE}") +/// } +/// +/// panic::set_hook(Box::new(|panic_info| { +/// assert_eq!(panic_info.to_string(), expected_format(panic_info)); +/// })); +/// +/// let result = panic::catch_unwind(|| { +/// panic!("{MESSAGE}"); +/// }); +/// assert!(result.is_err()); +/// ``` +pub mod panic_handler { + #[cfg(target_arch = "wasm32")] + mod internal { + use crate::ext; + use core::panic::PanicInfo; + + /// Panic handler when debug feature is disabled. + #[cfg(not(feature = "debug"))] + #[panic_handler] + pub fn panic(_: &PanicInfo) -> ! { + ext::panic("no info") + } - /// Panic handler for nightly Rust. - #[cfg(feature = "debug")] - #[cfg(feature = "panic-messages")] - #[panic_handler] - pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::fmt::Write; - use arrayvec::ArrayString; + #[cfg(feature = "debug")] + mod constants { + /// Max amount of bytes allowed to be thrown as string explanation of the error. + pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` + /// This prefix is used to print debug message: `debug!("panic occurred: {msg}")`. + pub const PANIC_OCCURRED: &str = "panic occurred: "; + /// This prefix is used by `impl Display for PanicInfo<'_>`. + #[cfg(not(feature = "panic-messages"))] + pub const PANICKED_AT: &str = "panicked at "; + } - let option = panic_info.message().zip(panic_info.location()); - let (message, location) = unsafe { option.unwrap_unchecked() }; + #[cfg(feature = "debug")] + use constants::*; - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - let _ = write!(&mut debug_msg, "{PANIC_OCCURRED}'{message}', {location}"); + /// Panic handler for nightly Rust. + #[cfg(feature = "debug")] + #[cfg(feature = "panic-messages")] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::fmt::Write; + use arrayvec::ArrayString; - let _ = ext::debug(&debug_msg); + let option = panic_info.message().zip(panic_info.location()); + let (message, location) = unsafe { option.unwrap_unchecked() }; - let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; - ext::panic(&msg) - } + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + let _ = write!(&mut debug_msg, "{PANIC_OCCURRED}'{message}', {location}"); - // Default panic handler message format: - // Rust <1.73: `panicked at '{message}', {location}` - // Rust >=1.73: `panicked at {location}:\n{message}` - // source: https://github.com/rust-lang/rust/pull/112849 + let _ = ext::debug(&debug_msg); - /// Panic handler for stable Rust <1.73. - #[rustversion::before(1.73)] - #[cfg(feature = "debug")] - #[cfg(not(feature = "panic-messages"))] - #[panic_handler] - pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::fmt::Write; - use arrayvec::ArrayString; + let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + ext::panic(&msg) + } - static_assertions::const_assert!(PANICKED_AT.len() == (PANIC_OCCURRED.len() - 4)); + /// Panic handler for stable Rust <1.73. + #[rustversion::before(1.73)] + #[cfg(feature = "debug")] + #[cfg(not(feature = "panic-messages"))] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::fmt::Write; + use arrayvec::ArrayString; - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + static_assertions::const_assert!(PANICKED_AT.len() == (PANIC_OCCURRED.len() - 4)); - let _ = debug_msg.try_push_str(&PANIC_OCCURRED[..4]); - let _ = write!(&mut debug_msg, "{panic_info}"); + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - let src = (&PANIC_OCCURRED[4..]).as_bytes(); - let dest = unsafe { - debug_msg - .as_bytes_mut() - .get_unchecked_mut(4..PANIC_OCCURRED.len()) - }; - dest.copy_from_slice(src); + let _ = debug_msg.try_push_str(&PANIC_OCCURRED[..4]); + let _ = write!(&mut debug_msg, "{panic_info}"); - let _ = ext::debug(&debug_msg); + let src = (&PANIC_OCCURRED[4..]).as_bytes(); + let dest = unsafe { + debug_msg + .as_bytes_mut() + .get_unchecked_mut(4..PANIC_OCCURRED.len()) + }; + dest.copy_from_slice(src); - let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; - ext::panic(&msg) - } + let _ = ext::debug(&debug_msg); - /// Panic handler for stable Rust >=1.73. - #[rustversion::since(1.73)] - #[cfg(feature = "debug")] - #[cfg(not(feature = "panic-messages"))] - #[panic_handler] - pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::{fmt::Write, str}; - use arrayvec::ArrayString; - - let mut default_panic_msg = ArrayString::<{ PANICKED_AT.len() + TRIMMED_MAX_LEN }>::new(); - let _ = write!(&mut default_panic_msg, "{panic_info}"); - - fn parse_panic_msg(msg: &str) -> Option<(&str, &str)> { - const NEEDLE: [u8; 2] = *b":\n"; - - let msg_bytes = msg.as_bytes(); - msg_bytes - .windows(NEEDLE.len()) - .position(|window| NEEDLE.eq(window)) - .map(|pos| unsafe { - ( - str::from_utf8_unchecked(msg_bytes.get_unchecked(PANICKED_AT.len()..pos)), - str::from_utf8_unchecked(msg_bytes.get_unchecked((pos + NEEDLE.len())..)), - ) - }) + let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + ext::panic(&msg) } - let option = parse_panic_msg(&default_panic_msg); - let (location, message) = unsafe { option.unwrap_unchecked() }; - - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - - let _ = debug_msg.try_push_str(PANIC_OCCURRED); - let _ = debug_msg.try_push('\''); - let _ = debug_msg.try_push_str(message); - let _ = debug_msg.try_push_str("', "); - let _ = debug_msg.try_push_str(location); - - let _ = ext::debug(&debug_msg); - - let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; - ext::panic(&msg) + /// Panic handler for stable Rust >=1.73. + #[rustversion::since(1.73)] + #[cfg(feature = "debug")] + #[cfg(not(feature = "panic-messages"))] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::{fmt::Write, str}; + use arrayvec::ArrayString; + + let mut default_panic_msg = + ArrayString::<{ PANICKED_AT.len() + TRIMMED_MAX_LEN }>::new(); + let _ = write!(&mut default_panic_msg, "{panic_info}"); + + fn parse_panic_msg(msg: &str) -> Option<(&str, &str)> { + const NEEDLE: [u8; 2] = *b":\n"; + + let msg_bytes = msg.as_bytes(); + msg_bytes + .windows(NEEDLE.len()) + .position(|window| NEEDLE.eq(window)) + .map(|pos| unsafe { + ( + str::from_utf8_unchecked( + msg_bytes.get_unchecked(PANICKED_AT.len()..pos), + ), + str::from_utf8_unchecked( + msg_bytes.get_unchecked((pos + NEEDLE.len())..), + ), + ) + }) + } + + let option = parse_panic_msg(&default_panic_msg); + let (location, message) = unsafe { option.unwrap_unchecked() }; + + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + + let _ = debug_msg.try_push_str(PANIC_OCCURRED); + let _ = debug_msg.try_push('\''); + let _ = debug_msg.try_push_str(message); + let _ = debug_msg.try_push_str("', "); + let _ = debug_msg.try_push_str(location); + + let _ = ext::debug(&debug_msg); + + let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + ext::panic(&msg) + } } } -#[cfg(feature = "panic-handler")] -pub use panic_handler::*; diff --git a/gstd/src/common/mod.rs b/gstd/src/common/mod.rs index 4ffb4ad9ebe..dd5babe02ec 100644 --- a/gstd/src/common/mod.rs +++ b/gstd/src/common/mod.rs @@ -19,6 +19,6 @@ //! Common modules for each Gear smart contract. pub mod errors; -#[cfg(target_arch = "wasm32")] +#[cfg(feature = "common-handlers")] mod handlers; pub mod primitives; From 76ba81bf88a1ab14542bafb54c34e9cf81c8b0e0 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:45:16 +0300 Subject: [PATCH 06/39] fix fmt --- gstd/src/common/handlers.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 8eb3efaaf7e..ce01498982d 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -35,8 +35,10 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// We currently support 2 panic handler modes: /// - non-debug: it prints `no info` /// - debug: it prints `'{message}', {location}` -/// - In nightly Rust, we use `#![feature(panic_info_message)]` and the [`write!`] macro. -/// - In stable Rust, we need to modify the default panic handler message format. +/// - In nightly Rust, we use `#![feature(panic_info_message)]` and the +/// [`write!`] macro. +/// - In stable Rust, we need to modify the default panic handler message +/// format. /// /// Default panic handler message format (according to ): /// - Rust <1.73: `panicked at '{message}', {location}` @@ -45,7 +47,8 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// We parse the output of `impl Display for PanicInfo<'_>` and /// then convert it to custom format: `'{message}', {location}`. /// -/// Here is a test to verify that the default panic handler message format has not changed: +/// Here is a test to verify that the default panic handler message format +/// has not changed: /// ``` /// use std::panic::{self, PanicInfo}; /// @@ -87,9 +90,11 @@ pub mod panic_handler { #[cfg(feature = "debug")] mod constants { - /// Max amount of bytes allowed to be thrown as string explanation of the error. + /// Max amount of bytes allowed to be thrown as string explanation + /// of the error. pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` - /// This prefix is used to print debug message: `debug!("panic occurred: {msg}")`. + /// This prefix is used to print debug message: + /// `debug!("panic occurred: {msg}")`. pub const PANIC_OCCURRED: &str = "panic occurred: "; /// This prefix is used by `impl Display for PanicInfo<'_>`. #[cfg(not(feature = "panic-messages"))] From bdd77ae00226c6e976028590a552c1d85e31c0f9 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:48:04 +0300 Subject: [PATCH 07/39] add some notes --- gstd/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index 9ee930b17a6..80ef664ccbf 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -31,6 +31,7 @@ rustversion = "1.0" default = ["common-handlers"] ## When enabled, a panic handler and an OOM error handler are provided by this crate. +## Note that the OOM error handler is provided when "nightly" feature is enabled. common-handlers = [] #! ## Nightly features From 89dbf0f6022ab22ccbededcf15556e967b572981 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 1 Dec 2023 19:18:48 +0300 Subject: [PATCH 08/39] [skip-ci] use try_push_str bcz it doesn't encodes char as utf8 --- gstd/src/common/handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index ce01498982d..ea3f64997fb 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -192,7 +192,7 @@ pub mod panic_handler { let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); let _ = debug_msg.try_push_str(PANIC_OCCURRED); - let _ = debug_msg.try_push('\''); + let _ = debug_msg.try_push_str("'"); let _ = debug_msg.try_push_str(message); let _ = debug_msg.try_push_str("', "); let _ = debug_msg.try_push_str(location); From 4aa5f528d42b63b6020aa312297ceaa6435b334a Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 8 Dec 2023 20:01:50 +0300 Subject: [PATCH 09/39] make binary x2.2 smaller on nightly --- gstd/src/common/handlers.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index ea3f64997fb..18de835cacd 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -109,14 +109,41 @@ pub mod panic_handler { #[cfg(feature = "panic-messages")] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::fmt::Write; + use crate::prelude::{fmt::Write, mem::MaybeUninit, str}; use arrayvec::ArrayString; let option = panic_info.message().zip(panic_info.location()); let (message, location) = unsafe { option.unwrap_unchecked() }; + fn itoa_u32(buffer: &mut [MaybeUninit; 10], mut n: u32) -> &str { + let mut idx = buffer.len(); + loop { + idx -= 1; + unsafe { buffer.get_unchecked_mut(idx) }.write((n % 10) as u8 + b'0'); + n /= 10; + if n == 0 { + break; + } + } + unsafe { + core::str::from_utf8_unchecked( + &*(buffer.get_unchecked(idx..) as *const [_] as *const _), + ) + } + } + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - let _ = write!(&mut debug_msg, "{PANIC_OCCURRED}'{message}', {location}"); + let mut buffer = unsafe { MaybeUninit::uninit().assume_init() }; + + let _ = debug_msg.try_push_str(PANIC_OCCURRED); + let _ = debug_msg.try_push_str("'"); + let _ = write!(&mut debug_msg, "{message}"); + let _ = debug_msg.try_push_str("', "); + let _ = debug_msg.try_push_str(location.file()); + let _ = debug_msg.try_push_str(":"); + let _ = debug_msg.try_push_str(itoa_u32(&mut buffer, location.line())); + let _ = debug_msg.try_push_str(":"); + let _ = debug_msg.try_push_str(itoa_u32(&mut buffer, location.column())); let _ = ext::debug(&debug_msg); From 61cb641fdf2ab567705b5ec51caa1788eecd03f6 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 8 Dec 2023 20:54:24 +0300 Subject: [PATCH 10/39] [skip-ci] remove core:: --- gstd/src/common/handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 18de835cacd..1b16c87c357 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -126,7 +126,7 @@ pub mod panic_handler { } } unsafe { - core::str::from_utf8_unchecked( + str::from_utf8_unchecked( &*(buffer.get_unchecked(idx..) as *const [_] as *const _), ) } From e09cc5f466870f2600db3bc8e6ee017d2db5b126 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:33:27 +0300 Subject: [PATCH 11/39] [skip-ci] use array syntax for MaybeUninit Co-authored-by: Arsenii Lyashenko --- gstd/src/common/handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 1b16c87c357..aa3136e17b2 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -133,7 +133,7 @@ pub mod panic_handler { } let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - let mut buffer = unsafe { MaybeUninit::uninit().assume_init() }; + let mut buffer = [MaybeUninit::uninit(); 10]; let _ = debug_msg.try_push_str(PANIC_OCCURRED); let _ = debug_msg.try_push_str("'"); From b23ab7b7ae9cf6f4d3eb68e6215a88f72a526243 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:54:40 +0300 Subject: [PATCH 12/39] apply suggestion --- gstd/src/common/handlers.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index aa3136e17b2..f13d972b388 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -167,13 +167,12 @@ pub mod panic_handler { let _ = debug_msg.try_push_str(&PANIC_OCCURRED[..4]); let _ = write!(&mut debug_msg, "{panic_info}"); - let src = (&PANIC_OCCURRED[4..]).as_bytes(); - let dest = unsafe { + unsafe { debug_msg .as_bytes_mut() .get_unchecked_mut(4..PANIC_OCCURRED.len()) - }; - dest.copy_from_slice(src); + .copy_from_slice(&PANIC_OCCURRED[4..].as_bytes()); + } let _ = ext::debug(&debug_msg); From 9b2b9adf1263c4378f1bfe24de0b264f602e9846 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:09:31 +0300 Subject: [PATCH 13/39] add safety comments --- examples/out-of-memory/src/wasm.rs | 8 +------ gstd/src/common/handlers.rs | 37 ++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/examples/out-of-memory/src/wasm.rs b/examples/out-of-memory/src/wasm.rs index 6ac5382b67a..6c213091d43 100644 --- a/examples/out-of-memory/src/wasm.rs +++ b/examples/out-of-memory/src/wasm.rs @@ -16,13 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use alloc::alloc::Layout; - #[no_mangle] extern "C" fn init() { - unsafe { - // Force rustc not to remove memory import - *(10usize as *mut u8) = 10; - } - alloc::alloc::handle_alloc_error(Layout::new::<[u8; 64 * 1024]>()); + panic!("msg"); } diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index f13d972b388..4d94088718b 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -112,12 +112,24 @@ pub mod panic_handler { use crate::prelude::{fmt::Write, mem::MaybeUninit, str}; use arrayvec::ArrayString; + // SAFETY: The current implementation always returns Some. + // https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/library/std/src/panicking.rs#L643-L644 let option = panic_info.message().zip(panic_info.location()); let (message, location) = unsafe { option.unwrap_unchecked() }; - fn itoa_u32(buffer: &mut [MaybeUninit; 10], mut n: u32) -> &str { + /// Maximum number of digits in `u32`. + const ITOA_U32_BUF_SIZE: usize = 10; + + /// Converts `u32` to `&str`, `&str` is written to temp buffer. + /// + /// We use our own function because `impl Display for u32` is very + /// large in WASM binary format (~2.5 KiB). + fn itoa_u32(buffer: &mut [MaybeUninit; ITOA_U32_BUF_SIZE], mut n: u32) -> &str { let mut idx = buffer.len(); loop { + // SAFETY: The bounds are always correct because this loop iterates over each + // digit in `u32`, and the maximum number of digits is defined in + // `ITOA_U32_BUF_SIZE` constant. idx -= 1; unsafe { buffer.get_unchecked_mut(idx) }.write((n % 10) as u8 + b'0'); n /= 10; @@ -125,6 +137,13 @@ pub mod panic_handler { break; } } + // SAFETY: Since we are using a loop with a postcondition, the boundaries will + // always be: `idx < buffer.len()`, i.e. we can do `get_unchecked(idx)`. + // The expression `&*(buffer as *const [_] as *const _)` is equivalent to + // `MaybeUninit::slice_assume_init_ref(&buffer[..idx])` and it gets the + // initialized part of `buffer`. + // Since the initialized part is filled with ascii digits, we can do + // `str::from_utf8_unchecked`. unsafe { str::from_utf8_unchecked( &*(buffer.get_unchecked(idx..) as *const [_] as *const _), @@ -133,7 +152,7 @@ pub mod panic_handler { } let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - let mut buffer = [MaybeUninit::uninit(); 10]; + let mut buffer = [MaybeUninit::uninit(); ITOA_U32_BUF_SIZE]; let _ = debug_msg.try_push_str(PANIC_OCCURRED); let _ = debug_msg.try_push_str("'"); @@ -147,6 +166,9 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); + // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does + // `memcpy`. If `memcpy` fails (e.g. isn't enough stack), the program will be + // aborted by the executor with unreachable instruction. let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; ext::panic(&msg) } @@ -167,6 +189,9 @@ pub mod panic_handler { let _ = debug_msg.try_push_str(&PANIC_OCCURRED[..4]); let _ = write!(&mut debug_msg, "{panic_info}"); + // SAFETY: `debug_msg.len() >= PANIC_OCCURRED.len()` because `try_push_str` + // pushes string `"pani"` and `write!()` pushes string `"panicked at "`. + // The capacity of `debug_msg` is always enough to do this. unsafe { debug_msg .as_bytes_mut() @@ -176,6 +201,8 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); + // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does + // `memcpy` (see panic handler for nightly rust for more details). let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; ext::panic(&msg) } @@ -196,6 +223,9 @@ pub mod panic_handler { fn parse_panic_msg(msg: &str) -> Option<(&str, &str)> { const NEEDLE: [u8; 2] = *b":\n"; + // SAFETY: We can use `str::from_utf8_unchecked` because the delimiter is ascii + // characters. Therefore, the strings between the delimiter will be a valid + // UTF-8 sequence (see https://en.wikipedia.org/wiki/UTF-8#Encoding). let msg_bytes = msg.as_bytes(); msg_bytes .windows(NEEDLE.len()) @@ -212,6 +242,7 @@ pub mod panic_handler { }) } + // FIXME let option = parse_panic_msg(&default_panic_msg); let (location, message) = unsafe { option.unwrap_unchecked() }; @@ -225,6 +256,8 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); + // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does + // `memcpy` (see panic handler for nightly rust for more details). let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; ext::panic(&msg) } From 66be25db10710945d5eb639e0b7a9089a8ce8647 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:24:57 +0300 Subject: [PATCH 14/39] simulate write! macro with for loop --- gstd/src/common/handlers.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 4d94088718b..ffefc15a7ec 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -152,17 +152,27 @@ pub mod panic_handler { } let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); - let mut buffer = [MaybeUninit::uninit(); ITOA_U32_BUF_SIZE]; let _ = debug_msg.try_push_str(PANIC_OCCURRED); - let _ = debug_msg.try_push_str("'"); - let _ = write!(&mut debug_msg, "{message}"); - let _ = debug_msg.try_push_str("', "); - let _ = debug_msg.try_push_str(location.file()); - let _ = debug_msg.try_push_str(":"); - let _ = debug_msg.try_push_str(itoa_u32(&mut buffer, location.line())); - let _ = debug_msg.try_push_str(":"); - let _ = debug_msg.try_push_str(itoa_u32(&mut buffer, location.column())); + if write!(&mut debug_msg, "'{message}', ").is_ok() { + for s in [ + location.file(), + ":", + itoa_u32( + &mut [MaybeUninit::uninit(); ITOA_U32_BUF_SIZE], + location.line(), + ), + ":", + itoa_u32( + &mut [MaybeUninit::uninit(); ITOA_U32_BUF_SIZE], + location.column(), + ), + ] { + if debug_msg.try_push_str(s).is_err() { + break; + } + } + } let _ = ext::debug(&debug_msg); From 14ab4d5abb5fbfbdc5bf5d29a5333bc9fea9a01f Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:52:16 +0300 Subject: [PATCH 15/39] add extra space for single quotes --- gstd/src/common/handlers.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index ffefc15a7ec..775bf27567c 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -256,7 +256,10 @@ pub mod panic_handler { let option = parse_panic_msg(&default_panic_msg); let (location, message) = unsafe { option.unwrap_unchecked() }; - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + // Add 2 byte difference between panic message formats (for single quotes). + const EXTRA_SPACE: usize = 2; + let mut debug_msg = + ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN + EXTRA_SPACE }>::new(); let _ = debug_msg.try_push_str(PANIC_OCCURRED); let _ = debug_msg.try_push_str("'"); From 8e354c4ab3c2b471e58fe1d53710701bee3b0a20 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:30:32 +0300 Subject: [PATCH 16/39] trying to fix ci --- examples/out-of-memory/src/wasm.rs | 8 +++++++- gstd/src/common/handlers.rs | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/out-of-memory/src/wasm.rs b/examples/out-of-memory/src/wasm.rs index 6c213091d43..6ac5382b67a 100644 --- a/examples/out-of-memory/src/wasm.rs +++ b/examples/out-of-memory/src/wasm.rs @@ -16,7 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use alloc::alloc::Layout; + #[no_mangle] extern "C" fn init() { - panic!("msg"); + unsafe { + // Force rustc not to remove memory import + *(10usize as *mut u8) = 10; + } + alloc::alloc::handle_alloc_error(Layout::new::<[u8; 64 * 1024]>()); } diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 775bf27567c..9b9f4fc0657 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -252,7 +252,6 @@ pub mod panic_handler { }) } - // FIXME let option = parse_panic_msg(&default_panic_msg); let (location, message) = unsafe { option.unwrap_unchecked() }; From f7e459bfe94c07abde45616da15d993728a6dd99 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 15 Dec 2023 12:25:46 +0300 Subject: [PATCH 17/39] fix some clippy lint and use other approach for rust >=1.73 --- gstd/src/common/handlers.rs | 97 ++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 9b9f4fc0657..4bcd1a76760 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -180,7 +180,7 @@ pub mod panic_handler { // `memcpy`. If `memcpy` fails (e.g. isn't enough stack), the program will be // aborted by the executor with unreachable instruction. let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; - ext::panic(&msg) + ext::panic(msg) } /// Panic handler for stable Rust <1.73. @@ -206,7 +206,7 @@ pub mod panic_handler { debug_msg .as_bytes_mut() .get_unchecked_mut(4..PANIC_OCCURRED.len()) - .copy_from_slice(&PANIC_OCCURRED[4..].as_bytes()); + .copy_from_slice(PANIC_OCCURRED[4..].as_bytes()); } let _ = ext::debug(&debug_msg); @@ -214,7 +214,7 @@ pub mod panic_handler { // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does // `memcpy` (see panic handler for nightly rust for more details). let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; - ext::panic(&msg) + ext::panic(msg) } /// Panic handler for stable Rust >=1.73. @@ -223,55 +223,74 @@ pub mod panic_handler { #[cfg(not(feature = "panic-messages"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::{fmt::Write, str}; + use crate::prelude::fmt::{self, Write}; use arrayvec::ArrayString; - let mut default_panic_msg = - ArrayString::<{ PANICKED_AT.len() + TRIMMED_MAX_LEN }>::new(); - let _ = write!(&mut default_panic_msg, "{panic_info}"); - - fn parse_panic_msg(msg: &str) -> Option<(&str, &str)> { - const NEEDLE: [u8; 2] = *b":\n"; - - // SAFETY: We can use `str::from_utf8_unchecked` because the delimiter is ascii - // characters. Therefore, the strings between the delimiter will be a valid - // UTF-8 sequence (see https://en.wikipedia.org/wiki/UTF-8#Encoding). - let msg_bytes = msg.as_bytes(); - msg_bytes - .windows(NEEDLE.len()) - .position(|window| NEEDLE.eq(window)) - .map(|pos| unsafe { - ( - str::from_utf8_unchecked( - msg_bytes.get_unchecked(PANICKED_AT.len()..pos), - ), - str::from_utf8_unchecked( - msg_bytes.get_unchecked((pos + NEEDLE.len())..), - ), - ) - }) + #[derive(Default)] + struct TempBuffer { + overflowed: bool, + buffer: ArrayString, } - let option = parse_panic_msg(&default_panic_msg); - let (location, message) = unsafe { option.unwrap_unchecked() }; + impl TempBuffer { + #[inline] + fn write_str(&mut self, s: &str) { + if !self.overflowed && self.buffer.write_str(s).is_err() { + self.overflowed = true; + } + } + } - // Add 2 byte difference between panic message formats (for single quotes). - const EXTRA_SPACE: usize = 2; - let mut debug_msg = - ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN + EXTRA_SPACE }>::new(); + #[derive(Default)] + struct TempOutput { + found_prefix: bool, + found_delimiter: bool, + location: TempBuffer, + message: TempBuffer, + } + + impl fmt::Write for TempOutput { + fn write_str(&mut self, s: &str) -> fmt::Result { + if !self.found_prefix && s.len() == PANICKED_AT.len() { + self.found_prefix = true; + return Ok(()); + } + + if !self.found_delimiter { + if s == ":\n" { + self.found_delimiter = true; + return Ok(()); + } + self.location.write_str(s); + } else { + self.message.write_str(s); + } + + Ok(()) + } + } + + let mut output = TempOutput::default(); + let _ = write!(&mut output, "{panic_info}"); + + let location = &*output.location.buffer; + let message = &*output.message.buffer; + + let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); let _ = debug_msg.try_push_str(PANIC_OCCURRED); - let _ = debug_msg.try_push_str("'"); - let _ = debug_msg.try_push_str(message); - let _ = debug_msg.try_push_str("', "); - let _ = debug_msg.try_push_str(location); + for s in ["'", message, "', ", location] { + if debug_msg.try_push_str(s).is_err() { + break; + } + } let _ = ext::debug(&debug_msg); // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does // `memcpy` (see panic handler for nightly rust for more details). let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; - ext::panic(&msg) + ext::panic(msg) } } } From 9420d8f65a5678cb5c1315bea56a080f57d1fa18 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 26 Dec 2023 16:33:38 +0300 Subject: [PATCH 18/39] remove most unsafe code --- gstd/src/common/handlers.rs | 79 +++++-------------------------------- 1 file changed, 10 insertions(+), 69 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 4bcd1a76760..12782c39838 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -109,77 +109,22 @@ pub mod panic_handler { #[cfg(feature = "panic-messages")] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::{fmt::Write, mem::MaybeUninit, str}; + use crate::prelude::fmt::Write; use arrayvec::ArrayString; - // SAFETY: The current implementation always returns Some. - // https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/library/std/src/panicking.rs#L643-L644 - let option = panic_info.message().zip(panic_info.location()); - let (message, location) = unsafe { option.unwrap_unchecked() }; - - /// Maximum number of digits in `u32`. - const ITOA_U32_BUF_SIZE: usize = 10; - - /// Converts `u32` to `&str`, `&str` is written to temp buffer. - /// - /// We use our own function because `impl Display for u32` is very - /// large in WASM binary format (~2.5 KiB). - fn itoa_u32(buffer: &mut [MaybeUninit; ITOA_U32_BUF_SIZE], mut n: u32) -> &str { - let mut idx = buffer.len(); - loop { - // SAFETY: The bounds are always correct because this loop iterates over each - // digit in `u32`, and the maximum number of digits is defined in - // `ITOA_U32_BUF_SIZE` constant. - idx -= 1; - unsafe { buffer.get_unchecked_mut(idx) }.write((n % 10) as u8 + b'0'); - n /= 10; - if n == 0 { - break; - } - } - // SAFETY: Since we are using a loop with a postcondition, the boundaries will - // always be: `idx < buffer.len()`, i.e. we can do `get_unchecked(idx)`. - // The expression `&*(buffer as *const [_] as *const _)` is equivalent to - // `MaybeUninit::slice_assume_init_ref(&buffer[..idx])` and it gets the - // initialized part of `buffer`. - // Since the initialized part is filled with ascii digits, we can do - // `str::from_utf8_unchecked`. - unsafe { - str::from_utf8_unchecked( - &*(buffer.get_unchecked(idx..) as *const [_] as *const _), - ) - } - } - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); let _ = debug_msg.try_push_str(PANIC_OCCURRED); - if write!(&mut debug_msg, "'{message}', ").is_ok() { - for s in [ - location.file(), - ":", - itoa_u32( - &mut [MaybeUninit::uninit(); ITOA_U32_BUF_SIZE], - location.line(), - ), - ":", - itoa_u32( - &mut [MaybeUninit::uninit(); ITOA_U32_BUF_SIZE], - location.column(), - ), - ] { - if debug_msg.try_push_str(s).is_err() { - break; - } - } - } + match (panic_info.message(), panic_info.location()) { + (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), + (Some(msg), None) => write!(&mut debug_msg, "'{msg}'"), + (None, Some(loc)) => write!(&mut debug_msg, "{loc}"), + _ => ext::panic("no info"), + }; let _ = ext::debug(&debug_msg); - // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does - // `memcpy`. If `memcpy` fails (e.g. isn't enough stack), the program will be - // aborted by the executor with unreachable instruction. - let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + let msg = &debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); ext::panic(msg) } @@ -211,9 +156,7 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does - // `memcpy` (see panic handler for nightly rust for more details). - let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + let msg = &debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); ext::panic(msg) } @@ -287,9 +230,7 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - // SAFETY: `debug_msg` is guaranteed to be initialized since `try_push_str` does - // `memcpy` (see panic handler for nightly rust for more details). - let msg = unsafe { debug_msg.get_unchecked(PANIC_OCCURRED.len()..) }; + let msg = &debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); ext::panic(msg) } } From c1608f0c05205d00a8b3274b370b4a3dfd8e672b Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 26 Dec 2023 19:53:59 +0300 Subject: [PATCH 19/39] completely get rid of unsafe code --- gstd/src/common/handlers.rs | 47 ++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 12782c39838..e2342df7f0c 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -124,7 +124,7 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - let msg = &debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); + let msg = debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); ext::panic(msg) } @@ -134,29 +134,44 @@ pub mod panic_handler { #[cfg(not(feature = "panic-messages"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::fmt::Write; + use crate::prelude::{ + fmt::{self, Write}, + ops::Deref, + }; use arrayvec::ArrayString; - static_assertions::const_assert!(PANICKED_AT.len() == (PANIC_OCCURRED.len() - 4)); + #[derive(Default)] + struct TempBuffer { + found_prefix: bool, + buffer: ArrayString, + } - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + impl Deref for TempBuffer { + type Target = str; - let _ = debug_msg.try_push_str(&PANIC_OCCURRED[..4]); - let _ = write!(&mut debug_msg, "{panic_info}"); + #[inline] + fn deref(&self) -> &str { + &self.buffer + } + } - // SAFETY: `debug_msg.len() >= PANIC_OCCURRED.len()` because `try_push_str` - // pushes string `"pani"` and `write!()` pushes string `"panicked at "`. - // The capacity of `debug_msg` is always enough to do this. - unsafe { - debug_msg - .as_bytes_mut() - .get_unchecked_mut(4..PANIC_OCCURRED.len()) - .copy_from_slice(PANIC_OCCURRED[4..].as_bytes()); + impl fmt::Write for TempBuffer { + fn write_str(&mut self, s: &str) -> fmt::Result { + if !self.found_prefix && s.len() == PANICKED_AT.len() { + self.found_prefix = true; + self.buffer.write_str(PANIC_OCCURRED) + } else { + self.buffer.write_str(s) + } + } } + let mut debug_msg = TempBuffer::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::default(); + let _ = write!(&mut debug_msg, "{panic_info}"); + let _ = ext::debug(&debug_msg); - let msg = &debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); + let msg = debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); ext::panic(msg) } @@ -230,7 +245,7 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - let msg = &debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); + let msg = debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); ext::panic(msg) } } From 3297392468a7c061358f6ab1486a83c4e2ab769d Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:24:19 +0300 Subject: [PATCH 20/39] match result of get --- gstd/src/common/handlers.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index e2342df7f0c..89a9425c325 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -124,8 +124,10 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - let msg = debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); - ext::panic(msg) + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic("no info"), + } } /// Panic handler for stable Rust <1.73. @@ -171,8 +173,10 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - let msg = debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); - ext::panic(msg) + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic("no info"), + } } /// Panic handler for stable Rust >=1.73. @@ -245,8 +249,10 @@ pub mod panic_handler { let _ = ext::debug(&debug_msg); - let msg = debug_msg.get(PANIC_OCCURRED.len()..).unwrap(); - ext::panic(msg) + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic("no info"), + } } } } From eab5a5d7e7c93df3bddebcf3d27a62a992f209ce Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Thu, 11 Jan 2024 22:45:36 +0300 Subject: [PATCH 21/39] split debug and panic handler --- Cargo.lock | 1 - gstd/Cargo.toml | 29 ++++---- gstd/src/common/handlers.rs | 127 ++++++++++-------------------------- gstd/src/common/mod.rs | 2 +- gstd/src/lib.rs | 6 +- 5 files changed, 57 insertions(+), 108 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05d862c156c..b776f7d3ef4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4670,7 +4670,6 @@ dependencies = [ "hex", "parity-scale-codec", "primitive-types", - "rustversion", "scale-info", ] diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index a76dc0e3940..531eed40d86 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -22,29 +22,32 @@ bs58 = { workspace = true, features = ["alloc"] } hex = { workspace = true, features = ["alloc"] } parity-scale-codec = { workspace = true, features = ["derive"] } primitive-types = { workspace = true, features = ["scale-info"] } -rustversion = { version = "1.0", optional = true } scale-info = { workspace = true, features = ["derive"] } futures = { workspace = true, features = ["alloc"] } -[dev-dependencies] -rustversion = "1.0" - [features] #! ## Default features -default = ["common-handlers"] -## When enabled, a panic handler and an OOM error handler are provided by this crate. -## Note that the OOM error handler is provided when "nightly" feature is enabled. -common-handlers = [] +default = ["panic-message"] + +#! ## Panic handler profiles + +## When enabled, a minimal panic handler is provided by this crate. +## Instead of a panic message, "no info" is displayed. +panic-handler = [] +## When enabled, a panic handler will also display a panic message. +panic-message = ["panic-handler", "arrayvec"] +## When enabled, a panic handler will also display a panic message and location. +panic-location = ["panic-message"] #! ## Nightly features ## Enables all features below. ## These features depend on unstable Rust API and require nightly toolchain. -nightly = ["panic-messages", "oom-handler"] -## When enabled, additional context information is available from -## panic messages in debug mode. Relies on [`panic_info_message`][rust-66745]. -panic-messages = [] +nightly = ["panic-info-message", "oom-handler"] +## When enabled, a panic handler will use a more efficient implementation +## Relies on [`panic_info_message`][rust-66745]. +panic-info-message = [] ## When enabled, an OOM error handler is provided. ## Relies on [`alloc_error_handler`][rust-51540], oom-handler = [] @@ -53,7 +56,7 @@ oom-handler = [] ## Enables debug logging; this heavily impacts gas cost ## and is therefore disabled by default. -debug = ["galloc/debug", "gcore/debug", "arrayvec", "rustversion"] +debug = ["galloc/debug", "gcore/debug"] #! [rust-66745]: https://github.com/rust-lang/rust/issues/66745 #! [rust-51540]: https://github.com/rust-lang/rust/issues/51540 diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 89a9425c325..9b2b8ed9cd5 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -32,13 +32,14 @@ pub fn oom(_: core::alloc::Layout) -> ! { crate::ext::oom_panic() } -/// We currently support 2 panic handler modes: -/// - non-debug: it prints `no info` -/// - debug: it prints `'{message}', {location}` +/// We currently support 3 panic handler profiles: +/// - `panic-handler`: it displays `no info` +/// - `panic-message`: it displays `panic: '{message}'` /// - In nightly Rust, we use `#![feature(panic_info_message)]` and the /// [`write!`] macro. /// - In stable Rust, we need to modify the default panic handler message /// format. +/// - `panic-location`: it displays `panic: '{message}' at {location}` /// /// Default panic handler message format (according to ): /// - Rust <1.73: `panicked at '{message}', {location}` @@ -54,13 +55,6 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// /// const MESSAGE: &str = "message"; /// -/// #[rustversion::before(1.73)] -/// fn expected_format(panic_info: &PanicInfo) -> String { -/// let location = panic_info.location().unwrap(); -/// format!("panicked at '{MESSAGE}', {location}") -/// } -/// -/// #[rustversion::since(1.73)] /// fn expected_format(panic_info: &PanicInfo) -> String { /// let location = panic_info.location().unwrap(); /// format!("panicked at {location}:\n{MESSAGE}") @@ -81,108 +75,52 @@ pub mod panic_handler { use crate::ext; use core::panic::PanicInfo; - /// Panic handler when debug feature is disabled. - #[cfg(not(feature = "debug"))] + /// Minimal panic handler. + #[cfg(not(any(feature = "panic-message", feature = "panic-location")))] #[panic_handler] pub fn panic(_: &PanicInfo) -> ! { ext::panic("no info") } - #[cfg(feature = "debug")] + #[cfg(any(feature = "panic-message", feature = "panic-location"))] mod constants { /// Max amount of bytes allowed to be thrown as string explanation /// of the error. pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` - /// This prefix is used to print debug message: - /// `debug!("panic occurred: {msg}")`. - pub const PANIC_OCCURRED: &str = "panic occurred: "; + /// This prefix is used to display panic message. + pub const PANIC_PREFIX: &str = "panic: "; /// This prefix is used by `impl Display for PanicInfo<'_>`. - #[cfg(not(feature = "panic-messages"))] pub const PANICKED_AT: &str = "panicked at "; } - #[cfg(feature = "debug")] + #[cfg(any(feature = "panic-message", feature = "panic-location"))] use constants::*; /// Panic handler for nightly Rust. - #[cfg(feature = "debug")] - #[cfg(feature = "panic-messages")] + #[cfg(feature = "nightly")] + #[cfg(any(feature = "panic-message", feature = "panic-location"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { use crate::prelude::fmt::Write; use arrayvec::ArrayString; - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + let mut debug_msg = ArrayString::<{ PANIC_PREFIX.len() + TRIMMED_MAX_LEN }>::new(); - let _ = debug_msg.try_push_str(PANIC_OCCURRED); - match (panic_info.message(), panic_info.location()) { - (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), - (Some(msg), None) => write!(&mut debug_msg, "'{msg}'"), - (None, Some(loc)) => write!(&mut debug_msg, "{loc}"), + let _ = debug_msg.try_push_str(PANIC_PREFIX); + let _ = match (panic_info.message(), panic_info.location()) { + #[cfg(all(feature = "panic-message", feature = "panic-location"))] + (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}' at {loc}"), + #[cfg(all(feature = "panic-message", not(feature = "panic-location")))] + (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), _ => ext::panic("no info"), }; - let _ = ext::debug(&debug_msg); - - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic("no info"), - } - } - - /// Panic handler for stable Rust <1.73. - #[rustversion::before(1.73)] - #[cfg(feature = "debug")] - #[cfg(not(feature = "panic-messages"))] - #[panic_handler] - pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::{ - fmt::{self, Write}, - ops::Deref, - }; - use arrayvec::ArrayString; - - #[derive(Default)] - struct TempBuffer { - found_prefix: bool, - buffer: ArrayString, - } - - impl Deref for TempBuffer { - type Target = str; - - #[inline] - fn deref(&self) -> &str { - &self.buffer - } - } - - impl fmt::Write for TempBuffer { - fn write_str(&mut self, s: &str) -> fmt::Result { - if !self.found_prefix && s.len() == PANICKED_AT.len() { - self.found_prefix = true; - self.buffer.write_str(PANIC_OCCURRED) - } else { - self.buffer.write_str(s) - } - } - } - - let mut debug_msg = TempBuffer::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::default(); - let _ = write!(&mut debug_msg, "{panic_info}"); - - let _ = ext::debug(&debug_msg); - - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic("no info"), - } + ext::panic(&debug_msg) } /// Panic handler for stable Rust >=1.73. - #[rustversion::since(1.73)] - #[cfg(feature = "debug")] - #[cfg(not(feature = "panic-messages"))] + #[cfg(not(feature = "nightly"))] + #[cfg(any(feature = "panic-message", feature = "panic-location"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { use crate::prelude::fmt::{self, Write}; @@ -235,24 +173,29 @@ pub mod panic_handler { let mut output = TempOutput::default(); let _ = write!(&mut output, "{panic_info}"); + #[cfg(all(feature = "panic-message", feature = "panic-location"))] let location = &*output.location.buffer; let message = &*output.message.buffer; - let mut debug_msg = ArrayString::<{ PANIC_OCCURRED.len() + TRIMMED_MAX_LEN }>::new(); + let mut debug_msg = ArrayString::<{ PANIC_PREFIX.len() + TRIMMED_MAX_LEN }>::new(); + + let _ = debug_msg.try_push_str(PANIC_PREFIX); - let _ = debug_msg.try_push_str(PANIC_OCCURRED); - for s in ["'", message, "', ", location] { + #[cfg(all(feature = "panic-message", feature = "panic-location"))] + for s in ["'", message, "' at ", location] { if debug_msg.try_push_str(s).is_err() { break; } } - let _ = ext::debug(&debug_msg); - - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic("no info"), + #[cfg(all(feature = "panic-message", not(feature = "panic-location")))] + for s in ["'", message, "'"] { + if debug_msg.try_push_str(s).is_err() { + break; + } } + + ext::panic(&debug_msg) } } } diff --git a/gstd/src/common/mod.rs b/gstd/src/common/mod.rs index dd5babe02ec..ce7c1985428 100644 --- a/gstd/src/common/mod.rs +++ b/gstd/src/common/mod.rs @@ -19,6 +19,6 @@ //! Common modules for each Gear smart contract. pub mod errors; -#[cfg(feature = "common-handlers")] +#[cfg(feature = "panic-handler")] mod handlers; pub mod primitives; diff --git a/gstd/src/lib.rs b/gstd/src/lib.rs index 2de85ceb1e8..9db883b2504 100644 --- a/gstd/src/lib.rs +++ b/gstd/src/lib.rs @@ -129,7 +129,11 @@ #![no_std] #![warn(missing_docs)] #![cfg_attr( - all(target_arch = "wasm32", feature = "panic-messages"), + all( + target_arch = "wasm32", + feature = "panic-info-message", + feature = "panic-message" + ), feature(panic_info_message) )] #![cfg_attr( From 6a4f82b50a2cea9ed28315395045fe6cc0391956 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:26:56 +0300 Subject: [PATCH 22/39] keep old msg format --- gstd/src/common/handlers.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 9b2b8ed9cd5..f81f6da4fa1 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -34,12 +34,12 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// We currently support 3 panic handler profiles: /// - `panic-handler`: it displays `no info` -/// - `panic-message`: it displays `panic: '{message}'` +/// - `panic-message`: it displays `'{message}'` /// - In nightly Rust, we use `#![feature(panic_info_message)]` and the /// [`write!`] macro. /// - In stable Rust, we need to modify the default panic handler message /// format. -/// - `panic-location`: it displays `panic: '{message}' at {location}` +/// - `panic-location`: it displays `'{message}', {location}` /// /// Default panic handler message format (according to ): /// - Rust <1.73: `panicked at '{message}', {location}` @@ -87,9 +87,8 @@ pub mod panic_handler { /// Max amount of bytes allowed to be thrown as string explanation /// of the error. pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` - /// This prefix is used to display panic message. - pub const PANIC_PREFIX: &str = "panic: "; /// This prefix is used by `impl Display for PanicInfo<'_>`. + #[cfg(not(feature = "nightly"))] pub const PANICKED_AT: &str = "panicked at "; } @@ -104,12 +103,11 @@ pub mod panic_handler { use crate::prelude::fmt::Write; use arrayvec::ArrayString; - let mut debug_msg = ArrayString::<{ PANIC_PREFIX.len() + TRIMMED_MAX_LEN }>::new(); + let mut debug_msg = ArrayString::::new(); - let _ = debug_msg.try_push_str(PANIC_PREFIX); let _ = match (panic_info.message(), panic_info.location()) { #[cfg(all(feature = "panic-message", feature = "panic-location"))] - (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}' at {loc}"), + (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), #[cfg(all(feature = "panic-message", not(feature = "panic-location")))] (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), _ => ext::panic("no info"), @@ -177,12 +175,10 @@ pub mod panic_handler { let location = &*output.location.buffer; let message = &*output.message.buffer; - let mut debug_msg = ArrayString::<{ PANIC_PREFIX.len() + TRIMMED_MAX_LEN }>::new(); - - let _ = debug_msg.try_push_str(PANIC_PREFIX); + let mut debug_msg = ArrayString::::new(); #[cfg(all(feature = "panic-message", feature = "panic-location"))] - for s in ["'", message, "' at ", location] { + for s in ["'", message, "', ", location] { if debug_msg.try_push_str(s).is_err() { break; } From f14edfe5f817112e25e5c662b5210a34a5edd629 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:23:14 +0300 Subject: [PATCH 23/39] gr_debug is still needed for gtest --- gstd/src/common/handlers.rs | 39 +++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index f81f6da4fa1..6938404b4d4 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -87,6 +87,15 @@ pub mod panic_handler { /// Max amount of bytes allowed to be thrown as string explanation /// of the error. pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` + /// This prefix is used to print debug message: + /// `debug!("panic occurred: {msg}")`. + pub const PANIC_OCCURRED: &str = "panic occurred: "; + /// TODO. + pub const ARRAY_STRING_MAX_LEN: usize = if cfg!(feature = "debug") { + PANIC_OCCURRED.len() + } else { + 0 + } + TRIMMED_MAX_LEN; /// This prefix is used by `impl Display for PanicInfo<'_>`. #[cfg(not(feature = "nightly"))] pub const PANICKED_AT: &str = "panicked at "; @@ -103,7 +112,10 @@ pub mod panic_handler { use crate::prelude::fmt::Write; use arrayvec::ArrayString; - let mut debug_msg = ArrayString::::new(); + let mut debug_msg = ArrayString::::new(); + + #[cfg(feature = "debug")] + let _ = debug_msg.try_push_str(PANIC_OCCURRED); let _ = match (panic_info.message(), panic_info.location()) { #[cfg(all(feature = "panic-message", feature = "panic-location"))] @@ -113,6 +125,16 @@ pub mod panic_handler { _ => ext::panic("no info"), }; + #[cfg(feature = "debug")] + let _ = ext::debug(&debug_msg); + + #[cfg(feature = "debug")] + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic("no info"), + } + + #[cfg(not(feature = "debug"))] ext::panic(&debug_msg) } @@ -175,7 +197,10 @@ pub mod panic_handler { let location = &*output.location.buffer; let message = &*output.message.buffer; - let mut debug_msg = ArrayString::::new(); + let mut debug_msg = ArrayString::::new(); + + #[cfg(feature = "debug")] + let _ = debug_msg.try_push_str(PANIC_OCCURRED); #[cfg(all(feature = "panic-message", feature = "panic-location"))] for s in ["'", message, "', ", location] { @@ -191,6 +216,16 @@ pub mod panic_handler { } } + #[cfg(feature = "debug")] + let _ = ext::debug(&debug_msg); + + #[cfg(feature = "debug")] + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic("no info"), + } + + #[cfg(not(feature = "debug"))] ext::panic(&debug_msg) } } From e236195b01e29eadd5f316d484b8a98af7c57399 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Fri, 12 Jan 2024 16:25:23 +0300 Subject: [PATCH 24/39] [skip-ci] fix doc --- gstd/src/common/handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 6938404b4d4..26a02a5a349 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -90,7 +90,7 @@ pub mod panic_handler { /// This prefix is used to print debug message: /// `debug!("panic occurred: {msg}")`. pub const PANIC_OCCURRED: &str = "panic occurred: "; - /// TODO. + /// Size of array string that will be allocated on the stack. pub const ARRAY_STRING_MAX_LEN: usize = if cfg!(feature = "debug") { PANIC_OCCURRED.len() } else { From 9d99503e38b4d15e7f77d27eff6da71ec6013f86 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sat, 13 Jan 2024 02:46:34 +0300 Subject: [PATCH 25/39] simplify location/not location --- gstd/src/common/handlers.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 26a02a5a349..f9aebd4d030 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -118,9 +118,9 @@ pub mod panic_handler { let _ = debug_msg.try_push_str(PANIC_OCCURRED); let _ = match (panic_info.message(), panic_info.location()) { - #[cfg(all(feature = "panic-message", feature = "panic-location"))] + #[cfg(feature = "panic-location")] (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), - #[cfg(all(feature = "panic-message", not(feature = "panic-location")))] + #[cfg(not(feature = "panic-location"))] (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), _ => ext::panic("no info"), }; @@ -193,7 +193,7 @@ pub mod panic_handler { let mut output = TempOutput::default(); let _ = write!(&mut output, "{panic_info}"); - #[cfg(all(feature = "panic-message", feature = "panic-location"))] + #[cfg(feature = "panic-location")] let location = &*output.location.buffer; let message = &*output.message.buffer; @@ -202,14 +202,14 @@ pub mod panic_handler { #[cfg(feature = "debug")] let _ = debug_msg.try_push_str(PANIC_OCCURRED); - #[cfg(all(feature = "panic-message", feature = "panic-location"))] + #[cfg(feature = "panic-location")] for s in ["'", message, "', ", location] { if debug_msg.try_push_str(s).is_err() { break; } } - #[cfg(all(feature = "panic-message", not(feature = "panic-location")))] + #[cfg(not(feature = "panic-location"))] for s in ["'", message, "'"] { if debug_msg.try_push_str(s).is_err() { break; From 63a341bba9b0b32f6fdf76d767af17a22003f606 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sat, 13 Jan 2024 02:53:46 +0300 Subject: [PATCH 26/39] nightly -> panic-info-message --- gstd/src/common/handlers.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index f9aebd4d030..a01b69e6498 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -97,7 +97,7 @@ pub mod panic_handler { 0 } + TRIMMED_MAX_LEN; /// This prefix is used by `impl Display for PanicInfo<'_>`. - #[cfg(not(feature = "nightly"))] + #[cfg(not(feature = "panic-info-message"))] pub const PANICKED_AT: &str = "panicked at "; } @@ -105,7 +105,7 @@ pub mod panic_handler { use constants::*; /// Panic handler for nightly Rust. - #[cfg(feature = "nightly")] + #[cfg(feature = "panic-info-message")] #[cfg(any(feature = "panic-message", feature = "panic-location"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { @@ -139,7 +139,7 @@ pub mod panic_handler { } /// Panic handler for stable Rust >=1.73. - #[cfg(not(feature = "nightly"))] + #[cfg(not(feature = "panic-info-message"))] #[cfg(any(feature = "panic-message", feature = "panic-location"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { From 2036f5b56ef744fba5f32f73f7eb7d910aed3375 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sat, 13 Jan 2024 02:56:01 +0300 Subject: [PATCH 27/39] move cfg(feature = panic-handler) near the it's module --- gstd/src/common/handlers.rs | 1 + gstd/src/common/mod.rs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index a01b69e6498..e93238883cc 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -69,6 +69,7 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// }); /// assert!(result.is_err()); /// ``` +#[cfg(feature = "panic-handler")] pub mod panic_handler { #[cfg(target_arch = "wasm32")] mod internal { diff --git a/gstd/src/common/mod.rs b/gstd/src/common/mod.rs index ce7c1985428..562a2167cd2 100644 --- a/gstd/src/common/mod.rs +++ b/gstd/src/common/mod.rs @@ -19,6 +19,5 @@ //! Common modules for each Gear smart contract. pub mod errors; -#[cfg(feature = "panic-handler")] mod handlers; pub mod primitives; From fbeaefc20735744ce8f60bd42132c9a67f0cab7d Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sat, 13 Jan 2024 03:00:15 +0300 Subject: [PATCH 28/39] no info -> --- gstd/Cargo.toml | 2 +- gstd/src/common/handlers.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index 531eed40d86..9234942421d 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -33,7 +33,7 @@ default = ["panic-message"] #! ## Panic handler profiles ## When enabled, a minimal panic handler is provided by this crate. -## Instead of a panic message, "no info" is displayed. +## Instead of a panic message, "" is displayed. panic-handler = [] ## When enabled, a panic handler will also display a panic message. panic-message = ["panic-handler", "arrayvec"] diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index e93238883cc..95f2277f5fc 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -33,7 +33,7 @@ pub fn oom(_: core::alloc::Layout) -> ! { } /// We currently support 3 panic handler profiles: -/// - `panic-handler`: it displays `no info` +/// - `panic-handler`: it displays `` /// - `panic-message`: it displays `'{message}'` /// - In nightly Rust, we use `#![feature(panic_info_message)]` and the /// [`write!`] macro. @@ -80,7 +80,7 @@ pub mod panic_handler { #[cfg(not(any(feature = "panic-message", feature = "panic-location")))] #[panic_handler] pub fn panic(_: &PanicInfo) -> ! { - ext::panic("no info") + ext::panic("") } #[cfg(any(feature = "panic-message", feature = "panic-location"))] @@ -123,7 +123,7 @@ pub mod panic_handler { (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), #[cfg(not(feature = "panic-location"))] (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), - _ => ext::panic("no info"), + _ => ext::panic(""), }; #[cfg(feature = "debug")] @@ -132,7 +132,7 @@ pub mod panic_handler { #[cfg(feature = "debug")] match debug_msg.get(PANIC_OCCURRED.len()..) { Some(msg) => ext::panic(msg), - _ => ext::panic("no info"), + _ => ext::panic(""), } #[cfg(not(feature = "debug"))] @@ -223,7 +223,7 @@ pub mod panic_handler { #[cfg(feature = "debug")] match debug_msg.get(PANIC_OCCURRED.len()..) { Some(msg) => ext::panic(msg), - _ => ext::panic("no info"), + _ => ext::panic(""), } #[cfg(not(feature = "debug"))] From 4320ac0da00ab41c859a1e7f2ea2bb7e11ac8269 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sat, 13 Jan 2024 03:16:11 +0300 Subject: [PATCH 29/39] [skip-ci] add dot --- gstd/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index 9234942421d..d8bd82083f6 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -45,7 +45,7 @@ panic-location = ["panic-message"] ## Enables all features below. ## These features depend on unstable Rust API and require nightly toolchain. nightly = ["panic-info-message", "oom-handler"] -## When enabled, a panic handler will use a more efficient implementation +## When enabled, a panic handler will use a more efficient implementation. ## Relies on [`panic_info_message`][rust-66745]. panic-info-message = [] ## When enabled, an OOM error handler is provided. From ed7741062e067677412d4bd8f6c7103251f718ab Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sat, 13 Jan 2024 03:31:47 +0300 Subject: [PATCH 30/39] [skip-ci] move doc comment below --- gstd/src/common/handlers.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 95f2277f5fc..489d7ed78a8 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -35,12 +35,14 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// We currently support 3 panic handler profiles: /// - `panic-handler`: it displays `` /// - `panic-message`: it displays `'{message}'` -/// - In nightly Rust, we use `#![feature(panic_info_message)]` and the -/// [`write!`] macro. -/// - In stable Rust, we need to modify the default panic handler message -/// format. /// - `panic-location`: it displays `'{message}', {location}` /// +/// How we get the panic message in different versions of Rust: +/// - In nightly Rust, we use `#![feature(panic_info_message)]` and the +/// [`write!`] macro. +/// - In stable Rust, we need to modify the default panic handler message +/// format. +/// /// Default panic handler message format (according to ): /// - Rust <1.73: `panicked at '{message}', {location}` /// - Rust >=1.73: `panicked at {location}:\n{message}` From c4a42f9675e015bff7895cda0eca14c3d588b717 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Sun, 14 Jan 2024 19:16:20 +0300 Subject: [PATCH 31/39] doc test -> #[test] --- gstd/src/common/handlers.rs | 313 ++++++++++++++++++------------------ 1 file changed, 158 insertions(+), 155 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 489d7ed78a8..142d2b49b54 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -49,187 +49,190 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// /// We parse the output of `impl Display for PanicInfo<'_>` and /// then convert it to custom format: `'{message}', {location}`. -/// -/// Here is a test to verify that the default panic handler message format -/// has not changed: -/// ``` -/// use std::panic::{self, PanicInfo}; -/// -/// const MESSAGE: &str = "message"; -/// -/// fn expected_format(panic_info: &PanicInfo) -> String { -/// let location = panic_info.location().unwrap(); -/// format!("panicked at {location}:\n{MESSAGE}") -/// } -/// -/// panic::set_hook(Box::new(|panic_info| { -/// assert_eq!(panic_info.to_string(), expected_format(panic_info)); -/// })); -/// -/// let result = panic::catch_unwind(|| { -/// panic!("{MESSAGE}"); -/// }); -/// assert!(result.is_err()); -/// ``` +#[cfg(target_arch = "wasm32")] #[cfg(feature = "panic-handler")] pub mod panic_handler { - #[cfg(target_arch = "wasm32")] - mod internal { - use crate::ext; - use core::panic::PanicInfo; - - /// Minimal panic handler. - #[cfg(not(any(feature = "panic-message", feature = "panic-location")))] - #[panic_handler] - pub fn panic(_: &PanicInfo) -> ! { - ext::panic("") - } + use crate::ext; + use core::panic::PanicInfo; + + /// Minimal panic handler. + #[cfg(not(any(feature = "panic-message", feature = "panic-location")))] + #[panic_handler] + pub fn panic(_: &PanicInfo) -> ! { + ext::panic("") + } - #[cfg(any(feature = "panic-message", feature = "panic-location"))] - mod constants { - /// Max amount of bytes allowed to be thrown as string explanation - /// of the error. - pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` - /// This prefix is used to print debug message: - /// `debug!("panic occurred: {msg}")`. - pub const PANIC_OCCURRED: &str = "panic occurred: "; - /// Size of array string that will be allocated on the stack. - pub const ARRAY_STRING_MAX_LEN: usize = if cfg!(feature = "debug") { - PANIC_OCCURRED.len() - } else { - 0 - } + TRIMMED_MAX_LEN; - /// This prefix is used by `impl Display for PanicInfo<'_>`. - #[cfg(not(feature = "panic-info-message"))] - pub const PANICKED_AT: &str = "panicked at "; - } + #[cfg(any(feature = "panic-message", feature = "panic-location"))] + mod constants { + /// Max amount of bytes allowed to be thrown as string explanation + /// of the error. + pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` + /// This prefix is used to print debug message: + /// `debug!("panic occurred: {msg}")`. + pub const PANIC_OCCURRED: &str = "panic occurred: "; + /// Size of array string that will be allocated on the stack. + pub const ARRAY_STRING_MAX_LEN: usize = if cfg!(feature = "debug") { + PANIC_OCCURRED.len() + } else { + 0 + } + TRIMMED_MAX_LEN; + /// This prefix is used by `impl Display for PanicInfo<'_>`. + #[cfg(not(feature = "panic-info-message"))] + pub const PANICKED_AT: &str = "panicked at "; + } - #[cfg(any(feature = "panic-message", feature = "panic-location"))] - use constants::*; - - /// Panic handler for nightly Rust. - #[cfg(feature = "panic-info-message")] - #[cfg(any(feature = "panic-message", feature = "panic-location"))] - #[panic_handler] - pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::fmt::Write; - use arrayvec::ArrayString; - - let mut debug_msg = ArrayString::::new(); - - #[cfg(feature = "debug")] - let _ = debug_msg.try_push_str(PANIC_OCCURRED); - - let _ = match (panic_info.message(), panic_info.location()) { - #[cfg(feature = "panic-location")] - (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), - #[cfg(not(feature = "panic-location"))] - (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), - _ => ext::panic(""), - }; - - #[cfg(feature = "debug")] - let _ = ext::debug(&debug_msg); - - #[cfg(feature = "debug")] - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic(""), - } + #[cfg(any(feature = "panic-message", feature = "panic-location"))] + use constants::*; - #[cfg(not(feature = "debug"))] - ext::panic(&debug_msg) + /// Panic handler for nightly Rust. + #[cfg(feature = "panic-info-message")] + #[cfg(any(feature = "panic-message", feature = "panic-location"))] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::fmt::Write; + use arrayvec::ArrayString; + + let mut debug_msg = ArrayString::::new(); + + #[cfg(feature = "debug")] + let _ = debug_msg.try_push_str(PANIC_OCCURRED); + + let _ = match (panic_info.message(), panic_info.location()) { + #[cfg(feature = "panic-location")] + (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), + #[cfg(not(feature = "panic-location"))] + (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), + _ => ext::panic(""), + }; + + #[cfg(feature = "debug")] + let _ = ext::debug(&debug_msg); + + #[cfg(feature = "debug")] + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic(""), } - /// Panic handler for stable Rust >=1.73. - #[cfg(not(feature = "panic-info-message"))] - #[cfg(any(feature = "panic-message", feature = "panic-location"))] - #[panic_handler] - pub fn panic(panic_info: &PanicInfo) -> ! { - use crate::prelude::fmt::{self, Write}; - use arrayvec::ArrayString; - - #[derive(Default)] - struct TempBuffer { - overflowed: bool, - buffer: ArrayString, - } + #[cfg(not(feature = "debug"))] + ext::panic(&debug_msg) + } - impl TempBuffer { - #[inline] - fn write_str(&mut self, s: &str) { - if !self.overflowed && self.buffer.write_str(s).is_err() { - self.overflowed = true; - } + /// Panic handler for stable Rust >=1.73. + #[cfg(not(feature = "panic-info-message"))] + #[cfg(any(feature = "panic-message", feature = "panic-location"))] + #[panic_handler] + pub fn panic(panic_info: &PanicInfo) -> ! { + use crate::prelude::fmt::{self, Write}; + use arrayvec::ArrayString; + + #[derive(Default)] + struct TempBuffer { + overflowed: bool, + buffer: ArrayString, + } + + impl TempBuffer { + #[inline] + fn write_str(&mut self, s: &str) { + if !self.overflowed && self.buffer.write_str(s).is_err() { + self.overflowed = true; } } + } - #[derive(Default)] - struct TempOutput { - found_prefix: bool, - found_delimiter: bool, - location: TempBuffer, - message: TempBuffer, - } + #[derive(Default)] + struct TempOutput { + found_prefix: bool, + found_delimiter: bool, + location: TempBuffer, + message: TempBuffer, + } - impl fmt::Write for TempOutput { - fn write_str(&mut self, s: &str) -> fmt::Result { - if !self.found_prefix && s.len() == PANICKED_AT.len() { - self.found_prefix = true; - return Ok(()); - } + impl fmt::Write for TempOutput { + fn write_str(&mut self, s: &str) -> fmt::Result { + if !self.found_prefix && s.len() == PANICKED_AT.len() { + self.found_prefix = true; + return Ok(()); + } - if !self.found_delimiter { - if s == ":\n" { - self.found_delimiter = true; - return Ok(()); - } - self.location.write_str(s); - } else { - self.message.write_str(s); + if !self.found_delimiter { + if s == ":\n" { + self.found_delimiter = true; + return Ok(()); } - - Ok(()) + self.location.write_str(s); + } else { + self.message.write_str(s); } + + Ok(()) } + } - let mut output = TempOutput::default(); - let _ = write!(&mut output, "{panic_info}"); + let mut output = TempOutput::default(); + let _ = write!(&mut output, "{panic_info}"); - #[cfg(feature = "panic-location")] - let location = &*output.location.buffer; - let message = &*output.message.buffer; + #[cfg(feature = "panic-location")] + let location = &*output.location.buffer; + let message = &*output.message.buffer; - let mut debug_msg = ArrayString::::new(); + let mut debug_msg = ArrayString::::new(); - #[cfg(feature = "debug")] - let _ = debug_msg.try_push_str(PANIC_OCCURRED); + #[cfg(feature = "debug")] + let _ = debug_msg.try_push_str(PANIC_OCCURRED); - #[cfg(feature = "panic-location")] - for s in ["'", message, "', ", location] { - if debug_msg.try_push_str(s).is_err() { - break; - } + #[cfg(feature = "panic-location")] + for s in ["'", message, "', ", location] { + if debug_msg.try_push_str(s).is_err() { + break; } + } - #[cfg(not(feature = "panic-location"))] - for s in ["'", message, "'"] { - if debug_msg.try_push_str(s).is_err() { - break; - } + #[cfg(not(feature = "panic-location"))] + for s in ["'", message, "'"] { + if debug_msg.try_push_str(s).is_err() { + break; } + } - #[cfg(feature = "debug")] - let _ = ext::debug(&debug_msg); - - #[cfg(feature = "debug")] - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic(""), - } + #[cfg(feature = "debug")] + let _ = ext::debug(&debug_msg); - #[cfg(not(feature = "debug"))] - ext::panic(&debug_msg) + #[cfg(feature = "debug")] + match debug_msg.get(PANIC_OCCURRED.len()..) { + Some(msg) => ext::panic(msg), + _ => ext::panic(""), } + + #[cfg(not(feature = "debug"))] + ext::panic(&debug_msg) + } +} + +#[cfg(test)] +mod tests { + extern crate std; + + use std::{format, panic, prelude::v1::*}; + + /// Here is a test to verify that the default panic handler message + /// format has not changed. + #[test] + fn panic_msg_format_not_changed() { + const MESSAGE: &str = "message"; + + panic::set_hook(Box::new(|panic_info| { + let location = panic_info.location().unwrap(); + assert_eq!( + panic_info.to_string(), + format!("panicked at {location}:\n{MESSAGE}") + ); + })); + + let result = panic::catch_unwind(|| { + panic!("{MESSAGE}"); + }); + assert!(result.is_err()); } } From 2df80952f8a2ceab0bf5e0272c15689efb186339 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 15 Jan 2024 14:51:09 +0300 Subject: [PATCH 32/39] rework panic handler --- Cargo.lock | 21 +++++++++ core-backend/src/error.rs | 2 +- gstd/Cargo.toml | 4 +- gstd/src/common/handlers.rs | 93 +++++++++++++++++-------------------- 4 files changed, 68 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95ff39947ef..30f5b3d8ef4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1234,6 +1234,26 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aca749d3d3f5b87a0d6100509879f9cf486ab510803a4a4e1001da1ff61c2bd6" +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -4645,6 +4665,7 @@ version = "1.0.5" dependencies = [ "arrayvec 0.7.4", "bs58 0.5.0", + "const_format", "document-features", "futures", "galloc", diff --git a/core-backend/src/error.rs b/core-backend/src/error.rs index 2678f8d9be4..03a520aed9a 100644 --- a/core-backend/src/error.rs +++ b/core-backend/src/error.rs @@ -225,7 +225,7 @@ pub enum TrapExplanation { ProgramAllocOutOfBounds, #[display(fmt = "Syscall unrecoverable error: {_0}")] UnrecoverableExt(UnrecoverableExtError), - #[display(fmt = "{_0}")] + #[display(fmt = "Panic occurred: {_0}")] Panic(LimitedStr<'static>), #[display(fmt = "Stack limit exceeded")] StackLimitExceeded, diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index d8bd82083f6..c095e00e215 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -3,6 +3,7 @@ name = "gstd" description = "Gear programs standard library" keywords = ["gear", "std", "no-std", "wasm", "smart-contracts"] categories = ["api-bindings"] +rust-version = "1.73" version.workspace = true edition.workspace = true authors.workspace = true @@ -12,6 +13,7 @@ repository.workspace = true [dependencies] arrayvec = { version = "0.7.4", default-features = false, optional = true } +const_format = { version = "0.2.32", optional = true } document-features = { version = "0.2.7", optional = true } galloc.workspace = true gcore = { workspace = true, features = ["codec"] } @@ -34,7 +36,7 @@ default = ["panic-message"] ## When enabled, a minimal panic handler is provided by this crate. ## Instead of a panic message, "" is displayed. -panic-handler = [] +panic-handler = ["const_format"] ## When enabled, a panic handler will also display a panic message. panic-message = ["panic-handler", "arrayvec"] ## When enabled, a panic handler will also display a panic message and location. diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index 142d2b49b54..7e1de1e54ee 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -31,7 +31,6 @@ pub fn oom(_: core::alloc::Layout) -> ! { crate::ext::oom_panic() } - /// We currently support 3 panic handler profiles: /// - `panic-handler`: it displays `` /// - `panic-message`: it displays `'{message}'` @@ -55,72 +54,73 @@ pub mod panic_handler { use crate::ext; use core::panic::PanicInfo; - /// Minimal panic handler. - #[cfg(not(any(feature = "panic-message", feature = "panic-location")))] - #[panic_handler] - pub fn panic(_: &PanicInfo) -> ! { - ext::panic("") - } - - #[cfg(any(feature = "panic-message", feature = "panic-location"))] mod constants { + /// This prefix is used before the panic message. + pub const PANIC_PREFIX: &str = "panicked with "; + /// This panic message is used in the minimal panic handler and when + /// internal errors occur. + #[cfg(any(feature = "panic-info-message", not(feature = "panic-message")))] + pub const UNKNOWN_REASON: &str = ""; + + /// This prefix is used by `impl Display for PanicInfo<'_>`. + #[cfg(all(not(feature = "panic-info-message"), feature = "panic-message"))] + pub const PANICKED_AT: &str = "panicked at "; + /// Max amount of bytes allowed to be thrown as string explanation /// of the error. + #[cfg(feature = "panic-message")] pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` - /// This prefix is used to print debug message: - /// `debug!("panic occurred: {msg}")`. - pub const PANIC_OCCURRED: &str = "panic occurred: "; /// Size of array string that will be allocated on the stack. - pub const ARRAY_STRING_MAX_LEN: usize = if cfg!(feature = "debug") { - PANIC_OCCURRED.len() - } else { - 0 - } + TRIMMED_MAX_LEN; - /// This prefix is used by `impl Display for PanicInfo<'_>`. - #[cfg(not(feature = "panic-info-message"))] - pub const PANICKED_AT: &str = "panicked at "; + #[cfg(feature = "panic-message")] + pub const ARRAY_STRING_MAX_LEN: usize = PANIC_PREFIX.len() + TRIMMED_MAX_LEN; } - #[cfg(any(feature = "panic-message", feature = "panic-location"))] use constants::*; + /// Minimal panic handler. + #[cfg(not(feature = "panic-message"))] + #[panic_handler] + pub fn panic(_: &PanicInfo) -> ! { + const MESSAGE: &str = const_format::formatcp!("{PANIC_PREFIX}'{UNKNOWN_REASON}'"); + + #[cfg(feature = "debug")] + let _ = ext::debug(MESSAGE); + + ext::panic(MESSAGE) + } + /// Panic handler for nightly Rust. - #[cfg(feature = "panic-info-message")] - #[cfg(any(feature = "panic-message", feature = "panic-location"))] + #[cfg(all(feature = "panic-info-message", feature = "panic-message"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { use crate::prelude::fmt::Write; use arrayvec::ArrayString; let mut debug_msg = ArrayString::::new(); + let _ = debug_msg.try_push_str(PANIC_PREFIX); - #[cfg(feature = "debug")] - let _ = debug_msg.try_push_str(PANIC_OCCURRED); - - let _ = match (panic_info.message(), panic_info.location()) { + match (panic_info.message(), panic_info.location()) { #[cfg(feature = "panic-location")] - (Some(msg), Some(loc)) => write!(&mut debug_msg, "'{msg}', {loc}"), + (Some(msg), Some(loc)) => { + let _ = write!(&mut debug_msg, "'{msg}' at '{loc}'"); + } #[cfg(not(feature = "panic-location"))] - (Some(msg), _) => write!(&mut debug_msg, "'{msg}'"), - _ => ext::panic(""), + (Some(msg), _) => { + let _ = write!(&mut debug_msg, "'{msg}'"); + } + _ => { + let _ = debug_msg.try_push_str(const_format::formatcp!("'{UNKNOWN_REASON}'")); + } }; #[cfg(feature = "debug")] let _ = ext::debug(&debug_msg); - #[cfg(feature = "debug")] - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic(""), - } - - #[cfg(not(feature = "debug"))] ext::panic(&debug_msg) } /// Panic handler for stable Rust >=1.73. - #[cfg(not(feature = "panic-info-message"))] - #[cfg(any(feature = "panic-message", feature = "panic-location"))] + #[cfg(all(not(feature = "panic-info-message"), feature = "panic-message"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { use crate::prelude::fmt::{self, Write}; @@ -145,6 +145,7 @@ pub mod panic_handler { struct TempOutput { found_prefix: bool, found_delimiter: bool, + #[cfg(feature = "panic-location")] location: TempBuffer, message: TempBuffer, } @@ -161,6 +162,7 @@ pub mod panic_handler { self.found_delimiter = true; return Ok(()); } + #[cfg(feature = "panic-location")] self.location.write_str(s); } else { self.message.write_str(s); @@ -178,12 +180,10 @@ pub mod panic_handler { let message = &*output.message.buffer; let mut debug_msg = ArrayString::::new(); - - #[cfg(feature = "debug")] - let _ = debug_msg.try_push_str(PANIC_OCCURRED); + let _ = debug_msg.try_push_str(PANIC_PREFIX); #[cfg(feature = "panic-location")] - for s in ["'", message, "', ", location] { + for s in ["'", message, "' at '", location, "'"] { if debug_msg.try_push_str(s).is_err() { break; } @@ -199,13 +199,6 @@ pub mod panic_handler { #[cfg(feature = "debug")] let _ = ext::debug(&debug_msg); - #[cfg(feature = "debug")] - match debug_msg.get(PANIC_OCCURRED.len()..) { - Some(msg) => ext::panic(msg), - _ => ext::panic(""), - } - - #[cfg(not(feature = "debug"))] ext::panic(&debug_msg) } } From 63a178bc542bdc180180921e18aa249cb57611f3 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:59:41 +0300 Subject: [PATCH 33/39] fix ci --- examples/waiter/tests/mx_lock_access.rs | 2 +- examples/waiter/tests/rw_lock_access.rs | 2 +- gstd/src/common/handlers.rs | 11 ++++++----- gtest/src/program.rs | 4 +++- pallets/gear/src/tests.rs | 14 +++++++------- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/examples/waiter/tests/mx_lock_access.rs b/examples/waiter/tests/mx_lock_access.rs index 5defc4daf9f..9aa9b9d6581 100644 --- a/examples/waiter/tests/mx_lock_access.rs +++ b/examples/waiter/tests/mx_lock_access.rs @@ -42,7 +42,7 @@ fn access_mx_lock_guard_from_different_msg_fails( assert_panicked( &lock_access_result, &format!( - "Mutex guard held by message {} is being accessed by message {}", + "Panic occurred: panicked with 'Mutex guard held by message {} is being accessed by message {}'", lock_msg_id, lock_access_result.sent_message_id() ), diff --git a/examples/waiter/tests/rw_lock_access.rs b/examples/waiter/tests/rw_lock_access.rs index f64f7d6a948..58d1360b0d9 100644 --- a/examples/waiter/tests/rw_lock_access.rs +++ b/examples/waiter/tests/rw_lock_access.rs @@ -86,7 +86,7 @@ fn access_rw_lock_guard_from_different_msg_fails( assert_panicked( &lock_access_result, &format!( - "{:?} lock guard held by message {} is being accessed by message {}", + "Panic occurred: panicked with '{:?} lock guard held by message {} is being accessed by message {}'", lock_type, lock_msg_id, lock_access_result.sent_message_id() diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index df246b10f26..eea4d2b4cf1 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -32,9 +32,9 @@ pub fn oom(_: core::alloc::Layout) -> ! { crate::ext::oom_panic() } /// We currently support 3 panic handler profiles: -/// - `panic-handler`: it displays `` -/// - `panic-message`: it displays `'{message}'` -/// - `panic-location`: it displays `'{message}', {location}` +/// - `panic-handler`: it displays `panicked with ''` +/// - `panic-message`: it displays `panicked with '{message}'` +/// - `panic-location`: it displays `panicked with '{message}' at '{location}'` /// /// How we get the panic message in different versions of Rust: /// - In nightly Rust, we use `#![feature(panic_info_message)]` and the @@ -47,10 +47,11 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// - Rust >=1.73: `panicked at {location}:\n{message}` /// /// We parse the output of `impl Display for PanicInfo<'_>` and -/// then convert it to custom format: `'{message}', {location}`. +/// then convert it to custom format: +/// `panicked with '{message}'[ at '{location}']`. #[cfg(target_arch = "wasm32")] #[cfg(feature = "panic-handler")] -pub mod panic_handler { +mod panic_handler { use crate::ext; use core::panic::PanicInfo; diff --git a/gtest/src/program.rs b/gtest/src/program.rs index d25d0250cce..d3ca1ea645e 100644 --- a/gtest/src/program.rs +++ b/gtest/src/program.rs @@ -856,7 +856,9 @@ mod tests { assert!(run_result.main_failed()); let log = run_result.log(); - assert!(log[0].payload().starts_with(b"'Failed to load destination")); + assert!(log[0] + .payload() + .starts_with(b"Panic occurred: panicked with 'Failed to load destination")); let run_result = prog.send(user_id, String::from("should_be_skipped")); diff --git a/pallets/gear/src/tests.rs b/pallets/gear/src/tests.rs index 0479247ef88..fcb7ce182ec 100644 --- a/pallets/gear/src/tests.rs +++ b/pallets/gear/src/tests.rs @@ -365,7 +365,7 @@ fn delayed_reservations_sending_validation() { run_to_next_block(None); let error_text = format!( - "{SENDING_EXPECT}: {:?}", + "panicked with '{SENDING_EXPECT}: {:?}'", GstdError::Core( ExtError::Message(MessageError::InsufficientGasForDelayedSending).into() ) @@ -402,7 +402,7 @@ fn delayed_reservations_sending_validation() { run_for_blocks(wait_for as u64 + 1, None); let error_text = format!( - "{SENDING_EXPECT}: {:?}", + "panicked with '{SENDING_EXPECT}: {:?}'", GstdError::Core( ExtError::Message(MessageError::InsufficientGasForDelayedSending).into() ) @@ -513,7 +513,7 @@ fn default_wait_lock_timeout() { run_to_block(expiration_block, None); let error_text = format!( - "ran into error-reply: {:?}", + "panicked with 'ran into error-reply: {:?}'", GstdError::Timeout( expiration_block.unique_saturated_into(), expiration_block.unique_saturated_into() @@ -7545,7 +7545,7 @@ fn test_create_program_with_value_lt_ed() { assert_total_dequeued(1); let error_text = format!( - "Failed to create program: {:?}", + "panicked with 'Failed to create program: {:?}'", GstdError::Core(ExtError::Message(MessageError::InsufficientValue).into()) ); @@ -7595,7 +7595,7 @@ fn test_create_program_with_exceeding_value() { assert_total_dequeued(1); let error_text = format!( - "Failed to create program: {:?}", + "panicked with 'Failed to create program: {:?}'", GstdError::Core(ExtError::Execution(ExecutionError::NotEnoughValue).into()) ); assert_failed( @@ -7681,7 +7681,7 @@ fn demo_constructor_works() { run_to_next_block(None); - let error_text = "I just panic every time".to_owned(); + let error_text = "panicked with 'I just panic every time'".to_owned(); assert_failed( message_id, @@ -8668,7 +8668,7 @@ fn mx_lock_ownership_exceedance() { let get_lock_ownership_exceeded_trap = |command_msg_id| { ActorExecutionErrorReplyReason::Trap(TrapExplanation::Panic( format!( - "Message 0x{} has exceeded lock ownership time", + "panicked with 'Message 0x{} has exceeded lock ownership time'", hex::encode(command_msg_id) ) .into(), From 9bb352590104afb1965d5f16b4538d5616d7ac4e Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:36:50 +0300 Subject: [PATCH 34/39] fix assert_panicked --- examples/waiter/tests/mx_lock_access.rs | 2 +- examples/waiter/tests/rw_lock_access.rs | 2 +- examples/waiter/tests/utils.rs | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/waiter/tests/mx_lock_access.rs b/examples/waiter/tests/mx_lock_access.rs index 9aa9b9d6581..5defc4daf9f 100644 --- a/examples/waiter/tests/mx_lock_access.rs +++ b/examples/waiter/tests/mx_lock_access.rs @@ -42,7 +42,7 @@ fn access_mx_lock_guard_from_different_msg_fails( assert_panicked( &lock_access_result, &format!( - "Panic occurred: panicked with 'Mutex guard held by message {} is being accessed by message {}'", + "Mutex guard held by message {} is being accessed by message {}", lock_msg_id, lock_access_result.sent_message_id() ), diff --git a/examples/waiter/tests/rw_lock_access.rs b/examples/waiter/tests/rw_lock_access.rs index 58d1360b0d9..f64f7d6a948 100644 --- a/examples/waiter/tests/rw_lock_access.rs +++ b/examples/waiter/tests/rw_lock_access.rs @@ -86,7 +86,7 @@ fn access_rw_lock_guard_from_different_msg_fails( assert_panicked( &lock_access_result, &format!( - "Panic occurred: panicked with '{:?} lock guard held by message {} is being accessed by message {}'", + "{:?} lock guard held by message {} is being accessed by message {}", lock_type, lock_msg_id, lock_access_result.sent_message_id() diff --git a/examples/waiter/tests/utils.rs b/examples/waiter/tests/utils.rs index 108f36fa700..ba695ea6505 100644 --- a/examples/waiter/tests/utils.rs +++ b/examples/waiter/tests/utils.rs @@ -13,10 +13,6 @@ pub fn assert_panicked(result: &RunResult, panic_msg: &str) { ))) )); let payload = String::from_utf8(result.log()[0].payload().into()) - .expect("Unable to decode panic message") - .split(',') - .map(String::from) - .next() - .expect("Unable to split panic message"); - assert_eq!(payload, format!("'{}'", panic_msg)); + .expect("Unable to decode panic message"); + assert!(payload.contains(&format!("panicked with '{panic_msg}'"))); } From f2759d14328d8eb6eef1b7c4e5074e99d7abea97 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:05:23 +0300 Subject: [PATCH 35/39] [skip-ci] replace .starts_with with .contains in gtest::tests --- gtest/src/program.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtest/src/program.rs b/gtest/src/program.rs index d3ca1ea645e..9e2e978df43 100644 --- a/gtest/src/program.rs +++ b/gtest/src/program.rs @@ -856,9 +856,9 @@ mod tests { assert!(run_result.main_failed()); let log = run_result.log(); - assert!(log[0] - .payload() - .starts_with(b"Panic occurred: panicked with 'Failed to load destination")); + let panic_msg_payload = + String::from_utf8(log[0].payload().into()).expect("Unable to decode panic message"); + assert!(panic_msg_payload.contains("panicked with 'Failed to load destination")); let run_result = prog.send(user_id, String::from("should_be_skipped")); From 70495481800a37322237e63b39e58e5489a3ddc0 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 15 Jan 2024 19:23:53 +0300 Subject: [PATCH 36/39] just use TRIMMED_MAX_LEN --- gstd/src/common/handlers.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index eea4d2b4cf1..c395899ed10 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -71,9 +71,6 @@ mod panic_handler { /// of the error. #[cfg(feature = "panic-message")] pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` - /// Size of array string that will be allocated on the stack. - #[cfg(feature = "panic-message")] - pub const ARRAY_STRING_MAX_LEN: usize = PANIC_PREFIX.len() + TRIMMED_MAX_LEN; } use constants::*; @@ -97,7 +94,7 @@ mod panic_handler { use crate::prelude::fmt::Write; use arrayvec::ArrayString; - let mut debug_msg = ArrayString::::new(); + let mut debug_msg = ArrayString::::new(); let _ = debug_msg.try_push_str(PANIC_PREFIX); match (panic_info.message(), panic_info.location()) { @@ -180,7 +177,7 @@ mod panic_handler { let location = &*output.location.buffer; let message = &*output.message.buffer; - let mut debug_msg = ArrayString::::new(); + let mut debug_msg = ArrayString::::new(); let _ = debug_msg.try_push_str(PANIC_PREFIX); #[cfg(feature = "panic-location")] From a9d9c3f0355447368dfe31c670d053387de10248 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Mon, 15 Jan 2024 22:12:03 +0300 Subject: [PATCH 37/39] better docs --- gstd/Cargo.toml | 12 +++++++++++- gstd/src/common/handlers.rs | 3 ++- gstd/src/lib.rs | 4 ++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index 2596389c182..39f6ec2ad7b 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -3,6 +3,7 @@ name = "gstd" description = "Gear programs standard library" keywords = ["gear", "std", "no-std", "wasm", "smart-contracts"] categories = ["api-bindings"] +# Stable version of Rust >=1.73 is required due to new format of panic message. rust-version = "1.73" version.workspace = true edition.workspace = true @@ -33,9 +34,18 @@ futures = { workspace = true, features = ["alloc"] } default = ["panic-message"] #! ## Panic handler profiles +#! We currently use the following format for panic messages from Rust code: +#! `panicked with '{message}'[ at '{location}']`. Also `Panic occurred: ` +#! will be added to the beginning of the panic message by our core-backend. +#! +#! So the final panic message looks like this: +#! `Panic occurred: panicked with '{message}'[ at '{location}']`. +#! +#! You can configure which panic handler profile you need +#! by specifying one of the following functions: ## When enabled, a minimal panic handler is provided by this crate. -## Instead of a panic message, "" is displayed. +## Instead of a panic message, `` is displayed. panic-handler = ["const_format"] ## When enabled, a panic handler will also display a panic message. panic-message = ["panic-handler", "arrayvec"] diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index c395899ed10..c9a4b961bbe 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -70,7 +70,8 @@ mod panic_handler { /// Max amount of bytes allowed to be thrown as string explanation /// of the error. #[cfg(feature = "panic-message")] - pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate `gear_core::str::TRIMMED_MAX_LEN` + pub const TRIMMED_MAX_LEN: usize = 1024; //TODO: do not duplicate + // `gear_core::str::TRIMMED_MAX_LEN` } use constants::*; diff --git a/gstd/src/lib.rs b/gstd/src/lib.rs index 1db4cd638b7..448ff67e71d 100644 --- a/gstd/src/lib.rs +++ b/gstd/src/lib.rs @@ -28,6 +28,10 @@ //! asynchronous programming primitives, arbitrary types encoding/decoding, //! providing convenient instruments for creating programs from programs, etc. //! +//! # Minimum supported Rust version +//! This crate requires **Rust >= 1.73** due to the implementation of the panic +//! handler in the stable version. +//! //! # Crate features #![cfg_attr( feature = "document-features", From ced5651c1fb99bbcbd6335584f8f01f01ef7dd97 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 16 Jan 2024 00:04:21 +0300 Subject: [PATCH 38/39] resolve some conversations --- gstd/src/common/handlers.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gstd/src/common/handlers.rs b/gstd/src/common/handlers.rs index c9a4b961bbe..04b0bf0463a 100644 --- a/gstd/src/common/handlers.rs +++ b/gstd/src/common/handlers.rs @@ -43,8 +43,7 @@ pub fn oom(_: core::alloc::Layout) -> ! { /// format. /// /// Default panic handler message format (according to ): -/// - Rust <1.73: `panicked at '{message}', {location}` -/// - Rust >=1.73: `panicked at {location}:\n{message}` +/// `panicked at {location}:\n{message}` /// /// We parse the output of `impl Display for PanicInfo<'_>` and /// then convert it to custom format: @@ -118,7 +117,7 @@ mod panic_handler { ext::panic(&debug_msg) } - /// Panic handler for stable Rust >=1.73. + /// Panic handler for stable Rust. #[cfg(all(not(feature = "panic-info-message"), feature = "panic-message"))] #[panic_handler] pub fn panic(panic_info: &PanicInfo) -> ! { From 20521e71ee2590399b487ca37b8cb13d40235042 Mon Sep 17 00:00:00 2001 From: StackOverflowExcept1on <109800286+StackOverflowExcept1on@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:05:04 +0300 Subject: [PATCH 39/39] [skip-ci] add doc about `panic-location` --- gstd/Cargo.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gstd/Cargo.toml b/gstd/Cargo.toml index 39f6ec2ad7b..be7b500a68b 100644 --- a/gstd/Cargo.toml +++ b/gstd/Cargo.toml @@ -50,9 +50,19 @@ panic-handler = ["const_format"] ## When enabled, a panic handler will also display a panic message. panic-message = ["panic-handler", "arrayvec"] ## When enabled, a panic handler will also display a panic message and location. +## This function is not recommended for use in production environment +## because it displays the code path. panic-location = ["panic-message"] #! ## Nightly features +#! +#! The `panic-message` and `panic-location` features gets additional +#! optimizations when using the nightly compiler. +#! +#! For example, if you don't use the `panic-location` feature, the compiler +#! will remove all locations such as `/home/username/dapp/src/lib.rs:1:2` +#! from the binary. The size of smart contract will be reduced and +#! `/home/username/...` information will not be included in the binary. ## Enables all features below. ## These features depend on unstable Rust API and require nightly toolchain.