Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gstd) use stabilized panic_info_message feature from rust 1.81 #4098

Merged
merged 7 commits into from
Sep 9, 2024
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2021"
license = "GPL-3.0"
homepage = "https://gear-tech.io"
repository = "https://github.com/gear-tech/gear"
rust-version = "1.80"
rust-version = "1.81"

[workspace]
resolver = "2"
Expand Down
16 changes: 6 additions & 10 deletions gstd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,20 @@ panic-message = ["panic-handler", "arrayvec"]
## 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 program will be reduced and
#! `/home/username/...` information will not be included in the binary.

#! ## Nightly features
#!
#! The final binary gets additional optimizations when using the nightly compiler.

## 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.
## Relies on [`panic_info_message`][rust-66745].
panic-info-message = []
nightly = ["oom-handler"]
## When enabled, an OOM error handler is provided.
## Relies on [`alloc_error_handler`][rust-51540],
## Relies on [`alloc_error_handler`][rust-51540].
oom-handler = []

#! ## Additional features
Expand Down
132 changes: 2 additions & 130 deletions gstd/src/common/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,6 @@ pub fn oom(_: core::alloc::Layout) -> ! {
/// - `panic-handler`: it displays `panicked with '<unknown>'`
/// - `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
/// [`write!`] macro.
/// - In stable Rust, we need to modify the default panic handler message
/// format.
///
/// Default panic handler message format (according to <https://github.com/rust-lang/rust/pull/112849>):
/// `panicked at {location}:\n{message}`
///
/// We parse the output of `impl Display for PanicInfo<'_>` and
/// then convert it to custom format:
/// `panicked with '{message}'[ at '{location}']`.
#[cfg(target_arch = "wasm32")]
#[cfg(feature = "panic-handler")]
mod panic_handler {
Expand All @@ -61,11 +48,6 @@ mod panic_handler {
/// internal errors occur.
#[cfg(not(feature = "panic-message"))]
pub const UNKNOWN_REASON: &str = "<unknown>";

/// 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")]
Expand All @@ -87,8 +69,8 @@ mod panic_handler {
ext::panic(MESSAGE)
}

/// Panic handler for nightly Rust.
#[cfg(all(feature = "panic-info-message", feature = "panic-message"))]
/// Panic handler with extra information.
#[cfg(feature = "panic-message")]
#[panic_handler]
pub fn panic(panic_info: &PanicInfo) -> ! {
use crate::prelude::fmt::Write;
Expand All @@ -112,114 +94,4 @@ mod panic_handler {

ext::panic(&debug_msg)
}

/// Panic handler for stable Rust.
#[cfg(all(not(feature = "panic-info-message"), feature = "panic-message"))]
#[panic_handler]
pub fn panic(panic_info: &PanicInfo) -> ! {
use crate::prelude::fmt::{self, Write};
use arrayvec::ArrayString;

#[derive(Default)]
struct TempBuffer<const CAP: usize> {
overflowed: bool,
buffer: ArrayString<CAP>,
}

impl<const CAP: usize> TempBuffer<CAP> {
#[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,
#[cfg(feature = "panic-location")]
location: TempBuffer<TRIMMED_MAX_LEN>,
message: TempBuffer<TRIMMED_MAX_LEN>,
}

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(());
}
#[cfg(feature = "panic-location")]
self.location.write_str(s);
} else {
self.message.write_str(s);
}

Ok(())
}
}

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;

let mut debug_msg = ArrayString::<TRIMMED_MAX_LEN>::new();
let _ = debug_msg.try_push_str(PANIC_PREFIX);

#[cfg(feature = "panic-location")]
for s in ["'", message, "' at '", 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(feature = "debug")]
let _ = ext::debug(&debug_msg);

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());
}
}
2 changes: 1 addition & 1 deletion gstd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
//! 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
//! This crate requires **Rust >= 1.81** due to the implementation of the panic
//! handler in the stable version.
//!
//! # Crate features
Expand Down
1 change: 0 additions & 1 deletion utils/wasm-builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ log.workspace = true
pathdiff.workspace = true
which.workspace = true
colored.workspace = true
dirs.workspace = true
gmeta.workspace = true
gear-core.workspace = true
gear-wasm-instrument.workspace = true
Expand Down
25 changes: 0 additions & 25 deletions utils/wasm-builder/src/cargo_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ pub struct CargoCommand {
toolchain: Toolchain,
check_recommended_toolchain: bool,
force_recommended_toolchain: bool,
paths_to_remap: Vec<(PathBuf, &'static str)>,
}

impl CargoCommand {
Expand All @@ -50,7 +49,6 @@ impl CargoCommand {
toolchain: Toolchain::try_from_rustup().expect("Failed to get toolchain from rustup"),
check_recommended_toolchain: false,
force_recommended_toolchain: false,
paths_to_remap: vec![],
}
}
}
Expand Down Expand Up @@ -94,13 +92,6 @@ impl CargoCommand {
self.force_recommended_toolchain = force_recommended_toolchain;
}

/// Set paths to remap.
///
/// Used to hide the username from the panic message.
pub fn set_paths_to_remap(&mut self, paths_to_remap: &[(PathBuf, &'static str)]) {
self.paths_to_remap = paths_to_remap.into();
}

/// Execute the `cargo` command with invoking supplied arguments.
pub fn run(&self) -> Result<()> {
if self.check_recommended_toolchain {
Expand Down Expand Up @@ -141,22 +132,6 @@ impl CargoCommand {

self.remove_cargo_encoded_rustflags(&mut cargo);

if !self.paths_to_remap.is_empty() {
// `--remap-path-prefix` is used to remove username from panic messages
// https://doc.rust-lang.org/rustc/command-line-arguments.html#--remap-path-prefix-remap-source-names-in-output
let global_encoded_rustflags = self
.paths_to_remap
.iter()
.map(|(from, to)| format!("--remap-path-prefix={from}={to}", from = from.display()))
.collect::<Vec<_>>()
.join("\x1f");

// The environment variable `CARGO_ENCODED_RUSTFLAGS` is used to globally remap path prefix.
// It is also separated by `\x1f` to support folders with spaces or any unusual characters.
// Unlike `cargo rust`, this is useful for passing flags to all dependencies (i.e. globally).
cargo.env("CARGO_ENCODED_RUSTFLAGS", global_encoded_rustflags);
}

let status = cargo.status().context("unable to execute cargo command")?;
ensure!(
status.success(),
Expand Down
26 changes: 2 additions & 24 deletions utils/wasm-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ pub use cargo_command::CargoCommand;
pub use wasm_project::{PreProcessor, PreProcessorResult, PreProcessorTarget};

use crate::wasm_project::WasmProject;
use anyhow::{Context, Result};
use anyhow::Result;
use gmeta::{Metadata, MetadataRepr};
use regex::Regex;
use std::{env, path::PathBuf, process};
use std::{env, process};
use wasm_project::ProjectType;

mod builder_error;
Expand Down Expand Up @@ -128,9 +128,6 @@ impl WasmBuilder {
let profile = if profile == "debug" { "dev" } else { profile };
self.cargo.set_profile(profile.to_string());
self.cargo.set_features(&self.enabled_features()?);
if env::var("GEAR_WASM_BUILDER_PATH_REMAPPING").is_ok() {
self.cargo.set_paths_to_remap(&self.paths_to_remap()?);
}

self.cargo.run()?;
self.wasm_project.postprocess()
Expand Down Expand Up @@ -199,25 +196,6 @@ impl WasmBuilder {
.filter(|feature| feature != "gcli")
.collect())
}

fn paths_to_remap(&self) -> Result<Vec<(PathBuf, &'static str)>> {
let home_dir = dirs::home_dir().context("unable to get home directory")?;

let project_dir = self.wasm_project.original_dir();

let cargo_dir = std::env::var_os("CARGO_HOME")
.map(PathBuf::from)
.context("unable to get cargo home directory")?;

let cargo_checkouts_dir = cargo_dir.join("git").join("checkouts");

Ok(vec![
(home_dir, "/home"),
(project_dir, "/code"),
(cargo_dir, "/cargo"),
(cargo_checkouts_dir, "/deps"),
])
}
}

impl Default for WasmBuilder {
Expand Down
5 changes: 0 additions & 5 deletions utils/wasm-builder/src/wasm_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,6 @@ impl WasmProject {
self.out_dir.join("Cargo.toml")
}

/// Return the path to the original project directory.
pub fn original_dir(&self) -> PathBuf {
self.original_dir.clone()
}

/// Return the path to the target directory.
pub fn target_dir(&self) -> PathBuf {
self.target_dir.clone()
Expand Down
Loading