Clean way to patch the std

This commit is contained in:
2026-03-18 19:58:23 +01:00
parent a087bdd523
commit 9b8afd2c5c
7 changed files with 258 additions and 277 deletions

View File

@@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
backtrace_rs = { package = "backtrace", version = "0.3", default-features = false }
hashbrown = "0.16"
os-std-macros = { path = "../os-std-macros" }
shared = { path = "../shared", features = ["user"] }

View File

@@ -6,25 +6,13 @@ patch-std:
@echo "Start patching the std..."
@find {{ PATCH_DIR }} -type f | while read -r patch_file; do \
relative_path="${patch_file#{{ PATCH_DIR }}/}"; \
case "$patch_file" in \
*.rs) \
echo "📄 [COPY] $relative_path"; \
mkdir -p "{{ SRC_DIR }}/$(dirname "$relative_path")"; \
cp "$patch_file" "{{ SRC_DIR }}/$relative_path"; \
;; \
*.sed) \
target_file="${relative_path%.sed}.rs"; \
if [ -f "{{ SRC_DIR }}/$target_file" ]; then \
echo " [SED] $target_file"; \
sed -i -f "$patch_file" "{{ SRC_DIR }}/$target_file"; \
else \
echo "⚠️[WARN] target doesn't exist: $target_file"; \
fi \
;; \
*) \
echo "❓ [SKIP] Unknown file : $relative_path"; \
;; \
esac; \
target_file="${relative_path%.sed}.rs"; \
if [ -f "{{ SRC_DIR }}/$target_file" ]; then \
echo " [SED] $target_file"; \
sed -i -f "$patch_file" "{{ SRC_DIR }}/$target_file"; \
else \
echo "⚠ [WARN] target doesn't exist: $target_file"; \
fi; \
done
@echo "✅ Patching done."
@@ -167,13 +155,14 @@ setup-std:
@just cp_std "sys/io/is_terminal/unsupported.rs"
@just cp_std "sys/io/kernel_copy/mod.rs"
@just cp_std "sys/io/mod.rs"
@just cp_std "sys/io/error/mod.rs"
@just cp_std "sys/pipe/mod.rs"
@just cp_std "sys/pipe/unsupported.rs"
@just cp_std "sys/stdio/mod.rs"
@just cp_std "sys/stdio/unsupported.rs"
@just cp_std "sys/alloc/mod.rs"
@just cp_std "sys/backtrace.rs"
@just cp_std "alloc.rs"
@# Copied but edited for the moment
# @just cp_std "sys/process/unsupported.rs"
@just cp_std "sys/io/error/mod.rs"
# @just cp_std "alloc.rs"
# @just cp_std "path.rs"

View File

@@ -5,11 +5,5 @@ s|alloc::slice::Join|alloc_crate::slice::Join|g
s|alloc::bstr|alloc_crate::bstr|g
s|alloc::collections::TryReserveError|alloc_crate::collections::TryReserveError|g
s|crate::collections::VecDeque|alloc_crate::collections::VecDeque|g
# s|collections::HashMap|hashbrown::HashMap|g
/crate::backtrace_rs/c \ todo!()
/crate::sys::os::getpid/c \ todo!()
/\[doc = include_str!/c \ // todo retreive docs
# /target_os = "xous",/a \ target_os = "survos",
# Ajouter d'autres modifications facilement ici :
# s|ancien_texte|nouveau_texte|g

View File

@@ -340,95 +340,95 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::Release);
}
// /// Unregisters the current allocation error hook, returning it.
// ///
// /// *See also the function [`set_alloc_error_hook`].*
// ///
// /// If no custom hook is registered, the default hook will be returned.
// #[unstable(feature = "alloc_error_hook", issue = "51245")]
// pub fn take_alloc_error_hook() -> fn(Layout) {
// let hook = HOOK.swap(ptr::null_mut(), Ordering::Acquire);
// if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
// }
/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
let hook = HOOK.swap(ptr::null_mut(), Ordering::Acquire);
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
}
// #[optimize(size)]
// fn default_alloc_error_hook(layout: Layout) {
// if cfg!(panic = "immediate-abort") {
// return;
// }
#[optimize(size)]
fn default_alloc_error_hook(layout: Layout) {
if cfg!(panic = "immediate-abort") {
return;
}
// // This is the default path taken on OOM, and the only path taken on stable with std.
// // Crucially, it does *not* call any user-defined code, and therefore users do not have to
// // worry about allocation failure causing reentrancy issues. That makes it different from
// // the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error
// // handler that is called when there is no `#[alloc_error_handler]`), which triggers a
// // regular panic and thus can invoke a user-defined panic hook, executing arbitrary
// // user-defined code.
// This is the default path taken on OOM, and the only path taken on stable with std.
// Crucially, it does *not* call any user-defined code, and therefore users do not have to
// worry about allocation failure causing reentrancy issues. That makes it different from
// the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error
// handler that is called when there is no `#[alloc_error_handler]`), which triggers a
// regular panic and thus can invoke a user-defined panic hook, executing arbitrary
// user-defined code.
// static PREV_ALLOC_FAILURE: AtomicBool = AtomicBool::new(false);
// if PREV_ALLOC_FAILURE.swap(true, Ordering::Relaxed) {
// // Don't try to print a backtrace if a previous alloc error happened. This likely means
// // there is not enough memory to print a backtrace, although it could also mean that two
// // threads concurrently run out of memory.
// rtprintpanic!(
// "memory allocation of {} bytes failed\nskipping backtrace printing to avoid potential recursion\n",
// layout.size()
// );
// return;
// } else {
// rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
// }
static PREV_ALLOC_FAILURE: AtomicBool = AtomicBool::new(false);
if PREV_ALLOC_FAILURE.swap(true, Ordering::Relaxed) {
// Don't try to print a backtrace if a previous alloc error happened. This likely means
// there is not enough memory to print a backtrace, although it could also mean that two
// threads concurrently run out of memory.
rtprintpanic!(
"memory allocation of {} bytes failed\nskipping backtrace printing to avoid potential recursion\n",
layout.size()
);
return;
} else {
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
}
// let Some(mut out) = crate::sys::stdio::panic_output() else {
// return;
// };
let Some(mut out) = crate::sys::stdio::panic_output() else {
return;
};
// // Use a lock to prevent mixed output in multithreading context.
// // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows.
// // Make sure to not take this lock until after checking PREV_ALLOC_FAILURE to avoid deadlocks
// // when there is too little memory to print a backtrace.
// let mut lock = crate::sys::backtrace::lock();
// Use a lock to prevent mixed output in multithreading context.
// Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows.
// Make sure to not take this lock until after checking PREV_ALLOC_FAILURE to avoid deadlocks
// when there is too little memory to print a backtrace.
let mut lock = crate::sys::backtrace::lock();
// match crate::panic::get_backtrace_style() {
// Some(crate::panic::BacktraceStyle::Short) => {
// drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Short))
// }
// Some(crate::panic::BacktraceStyle::Full) => {
// drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Full))
// }
// Some(crate::panic::BacktraceStyle::Off) => {
// use crate::io::Write;
// let _ = writeln!(
// out,
// "note: run with `RUST_BACKTRACE=1` environment variable to display a \
// backtrace"
// );
// if cfg!(miri) {
// let _ = writeln!(
// out,
// "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \
// for the environment variable to have an effect"
// );
// }
// }
// // If backtraces aren't supported or are forced-off, do nothing.
// None => {}
// }
// }
match crate::panic::get_backtrace_style() {
Some(crate::panic::BacktraceStyle::Short) => {
drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Short))
}
Some(crate::panic::BacktraceStyle::Full) => {
drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Full))
}
Some(crate::panic::BacktraceStyle::Off) => {
use crate::io::Write;
let _ = writeln!(
out,
"note: run with `RUST_BACKTRACE=1` environment variable to display a \
backtrace"
);
if cfg!(miri) {
let _ = writeln!(
out,
"note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \
for the environment variable to have an effect"
);
}
}
// If backtraces aren't supported or are forced-off, do nothing.
None => {}
}
}
// #[cfg(not(test))]
// #[doc(hidden)]
// #[alloc_error_handler]
// #[unstable(feature = "alloc_internals", issue = "none")]
// pub fn rust_oom(layout: Layout) -> ! {
// crate::sys::backtrace::__rust_end_short_backtrace(|| {
// let hook = HOOK.load(Ordering::Acquire);
// let hook: fn(Layout) =
// if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
// hook(layout);
// crate::process::abort()
// })
// }
#[cfg(not(test))]
#[doc(hidden)]
#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "none")]
pub fn rust_oom(layout: Layout) -> ! {
crate::sys::backtrace::__rust_end_short_backtrace(|| {
let hook = HOOK.load(Ordering::Acquire);
let hook: fn(Layout) =
if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
hook(layout);
crate::process::abort()
})
}
#[cfg(not(test))]
#[doc(hidden)]

View File

@@ -295,6 +295,7 @@ pub mod sync;
pub mod sys;
pub mod thread;
pub mod time;
pub use backtrace_rs;
#[prelude_import]
#[allow(unused_imports)]

View File

@@ -286,10 +286,10 @@ fn default_hook(info: &PanicHookInfo<'_>) {
match backtrace {
Some(BacktraceStyle::Short) => {
todo!()
drop(lock.print(err, crate::backtrace_rs::PrintFmt::Short))
}
Some(BacktraceStyle::Full) => {
todo!()
drop(lock.print(err, crate::backtrace_rs::PrintFmt::Full))
}
Some(BacktraceStyle::Off) => {
if FIRST_PANIC.swap(false, Ordering::Relaxed) {

View File

@@ -1,7 +1,7 @@
//! Common code for printing backtraces.
#![forbid(unsafe_op_in_unsafe_fn)]
// use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
use crate::borrow::Cow;
use crate::io::prelude::*;
use crate::path::{self, Path, PathBuf};
@@ -24,140 +24,136 @@ pub(crate) fn lock<'a>() -> BacktraceLock<'a> {
BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner))
}
// impl BacktraceLock<'_> {
// /// Prints the current backtrace.
// pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
// // There are issues currently linking libbacktrace into tests, and in
// // general during std's own unit tests we're not testing this path. In
// // test mode immediately return here to optimize away any references to the
// // libbacktrace symbols
// if cfg!(test) {
// return Ok(());
// }
impl BacktraceLock<'_> {
/// Prints the current backtrace.
pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
// There are issues currently linking libbacktrace into tests, and in
// general during std's own unit tests we're not testing this path. In
// test mode immediately return here to optimize away any references to the
// libbacktrace symbols
if cfg!(test) {
return Ok(());
}
// struct DisplayBacktrace {
// format: PrintFmt,
// }
// impl fmt::Display for DisplayBacktrace {
// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// // SAFETY: the backtrace lock is held
// unsafe { _print_fmt(fmt, self.format) }
// }
// }
// write!(w, "{}", DisplayBacktrace { format })
// }
// }
struct DisplayBacktrace {
format: PrintFmt,
}
impl fmt::Display for DisplayBacktrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// SAFETY: the backtrace lock is held
unsafe { _print_fmt(fmt, self.format) }
}
}
write!(w, "{}", DisplayBacktrace { format })
}
}
// /// # Safety
// ///
// /// This function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program.
// unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
// // Always 'fail' to get the cwd when running under Miri -
// // this allows Miri to display backtraces in isolation mode
// let cwd = if !cfg!(miri) {
// env::current_dir().ok()
// } else {
// None
// };
/// # Safety
///
/// This function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program.
unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
// Always 'fail' to get the cwd when running under Miri -
// this allows Miri to display backtraces in isolation mode
let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None };
// let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
// output_filename(fmt, bows, print_fmt, cwd.as_ref())
// };
// writeln!(fmt, "stack backtrace:")?;
// let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
// bt_fmt.add_context()?;
// let mut idx = 0;
// let mut res = Ok(());
// let mut omitted_count: usize = 0;
// let mut first_omit = true;
// // If we're using a short backtrace, ignore all frames until we're told to start printing.
// let mut print = print_fmt != PrintFmt::Short;
// set_image_base();
// // SAFETY: we roll our own locking in this town
// unsafe {
// backtrace_rs::trace_unsynchronized(|frame| {
// if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
// return false;
// }
let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
output_filename(fmt, bows, print_fmt, cwd.as_ref())
};
writeln!(fmt, "stack backtrace:")?;
let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
bt_fmt.add_context()?;
let mut idx = 0;
let mut res = Ok(());
let mut omitted_count: usize = 0;
let mut first_omit = true;
// If we're using a short backtrace, ignore all frames until we're told to start printing.
let mut print = print_fmt != PrintFmt::Short;
set_image_base();
// SAFETY: we roll our own locking in this town
unsafe {
backtrace_rs::trace_unsynchronized(|frame| {
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
return false;
}
// if cfg!(feature = "backtrace-trace-only") {
// const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>();
// let frame_ip = frame.ip();
// res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
// } else {
// let mut hit = false;
// backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
// hit = true;
if cfg!(feature = "backtrace-trace-only") {
const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>();
let frame_ip = frame.ip();
res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
} else {
let mut hit = false;
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
hit = true;
// // `__rust_end_short_backtrace` means we are done hiding symbols
// // for now. Print until we see `__rust_begin_short_backtrace`.
// if print_fmt == PrintFmt::Short {
// if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
// if sym.contains("__rust_end_short_backtrace") {
// print = true;
// return;
// }
// if print && sym.contains("__rust_begin_short_backtrace") {
// print = false;
// return;
// }
// if !print {
// omitted_count += 1;
// }
// }
// }
// `__rust_end_short_backtrace` means we are done hiding symbols
// for now. Print until we see `__rust_begin_short_backtrace`.
if print_fmt == PrintFmt::Short {
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
if sym.contains("__rust_end_short_backtrace") {
print = true;
return;
}
if print && sym.contains("__rust_begin_short_backtrace") {
print = false;
return;
}
if !print {
omitted_count += 1;
}
}
}
// if print {
// if omitted_count > 0 {
// debug_assert!(print_fmt == PrintFmt::Short);
// // only print the message between the middle of frames
// if !first_omit {
// let _ = writeln!(
// bt_fmt.formatter(),
// " [... omitted {} frame{} ...]",
// omitted_count,
// if omitted_count > 1 { "s" } else { "" }
// );
// }
// first_omit = false;
// omitted_count = 0;
// }
// res = bt_fmt.frame().symbol(frame, symbol);
// }
// });
// #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))]
// if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
// if !hit && print {
// use crate::backtrace_rs::SymbolName;
// res = bt_fmt.frame().print_raw(
// frame.ip(),
// Some(SymbolName::new("__my_thread_exit".as_bytes())),
// None,
// None,
// );
// }
// return false;
// }
// if !hit && print {
// res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
// }
// }
if print {
if omitted_count > 0 {
debug_assert!(print_fmt == PrintFmt::Short);
// only print the message between the middle of frames
if !first_omit {
let _ = writeln!(
bt_fmt.formatter(),
" [... omitted {} frame{} ...]",
omitted_count,
if omitted_count > 1 { "s" } else { "" }
);
}
first_omit = false;
omitted_count = 0;
}
res = bt_fmt.frame().symbol(frame, symbol);
}
});
#[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))]
if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
if !hit && print {
use crate::backtrace_rs::SymbolName;
res = bt_fmt.frame().print_raw(
frame.ip(),
Some(SymbolName::new("__my_thread_exit".as_bytes())),
None,
None,
);
}
return false;
}
if !hit && print {
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
}
}
// idx += 1;
// res.is_ok()
// })
// };
// res?;
// bt_fmt.finish()?;
// if print_fmt == PrintFmt::Short {
// writeln!(
// fmt,
// "note: Some details are omitted, \
// run with `RUST_BACKTRACE=full` for a verbose backtrace."
// )?;
// }
// Ok(())
// }
idx += 1;
res.is_ok()
})
};
res?;
bt_fmt.finish()?;
if print_fmt == PrintFmt::Short {
writeln!(
fmt,
"note: Some details are omitted, \
run with `RUST_BACKTRACE=full` for a verbose backtrace."
)?;
}
Ok(())
}
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
/// this is only inline(never) when backtraces in std are enabled, otherwise
@@ -191,44 +187,44 @@ where
result
}
// /// Prints the filename of the backtrace frame.
// ///
// /// See also `output`.
// pub fn output_filename(
// fmt: &mut fmt::Formatter<'_>,
// bows: BytesOrWideString<'_>,
// print_fmt: PrintFmt,
// cwd: Option<&PathBuf>,
// ) -> fmt::Result {
// let file: Cow<'_, Path> = match bows {
// #[cfg(unix)]
// BytesOrWideString::Bytes(bytes) => {
// use crate::os::unix::prelude::*;
// Path::new(crate::ffi::OsStr::from_bytes(bytes)).into()
// }
// #[cfg(not(unix))]
// BytesOrWideString::Bytes(bytes) => {
// Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
// }
// #[cfg(windows)]
// BytesOrWideString::Wide(wide) => {
// use crate::os::windows::prelude::*;
// Cow::Owned(crate::ffi::OsString::from_wide(wide).into())
// }
// #[cfg(not(windows))]
// BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
// };
// if print_fmt == PrintFmt::Short && file.is_absolute() {
// if let Some(cwd) = cwd {
// if let Ok(stripped) = file.strip_prefix(&cwd) {
// if let Some(s) = stripped.to_str() {
// return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
// }
// }
// }
// }
// fmt::Display::fmt(&file.display(), fmt)
// }
/// Prints the filename of the backtrace frame.
///
/// See also `output`.
pub fn output_filename(
fmt: &mut fmt::Formatter<'_>,
bows: BytesOrWideString<'_>,
print_fmt: PrintFmt,
cwd: Option<&PathBuf>,
) -> fmt::Result {
let file: Cow<'_, Path> = match bows {
#[cfg(unix)]
BytesOrWideString::Bytes(bytes) => {
use crate::os::unix::prelude::*;
Path::new(crate::ffi::OsStr::from_bytes(bytes)).into()
}
#[cfg(not(unix))]
BytesOrWideString::Bytes(bytes) => {
Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>")).into()
}
#[cfg(windows)]
BytesOrWideString::Wide(wide) => {
use crate::os::windows::prelude::*;
Cow::Owned(crate::ffi::OsString::from_wide(wide).into())
}
#[cfg(not(windows))]
BytesOrWideString::Wide(_wide) => Path::new("<unknown>").into(),
};
if print_fmt == PrintFmt::Short && file.is_absolute() {
if let Some(cwd) = cwd {
if let Ok(stripped) = file.strip_prefix(&cwd) {
if let Some(s) = stripped.to_str() {
return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR);
}
}
}
}
fmt::Display::fmt(&file.display(), fmt)
}
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
pub fn set_image_base() {