From fbb56200ab6cf389da114e6c0cd3a75b8e44e989 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 6 Jul 2026 16:08:59 +0700 Subject: [PATCH 1/2] Handle panic without TCB --- generic-rt/src/lib.rs | 11 ++--------- redox-rt/src/signal.rs | 2 +- src/ld_so/mod.rs | 4 ++-- src/lib.rs | 32 ++++++-------------------------- src/panic.rs | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 38 deletions(-) create mode 100644 src/panic.rs diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs index dca94521f0..a9f33c6cd4 100644 --- a/generic-rt/src/lib.rs +++ b/generic-rt/src/lib.rs @@ -98,11 +98,6 @@ impl GenericTcb { unsafe { Some(&mut *Self::current_ptr()?) } } } -pub fn panic_notls(_msg: impl core::fmt::Display) -> ! { - // TODO: actually print _msg, perhaps by having panic_notls take a `T: DebugBackend` that can - // propagate until called by e.g. relibc start - core::intrinsics::abort(); -} pub trait ExpectTlsFree { type Unwrapped; @@ -115,9 +110,7 @@ impl ExpectTlsFree for Result { fn expect_notls(self, msg: &str) -> T { match self { Ok(t) => t, - Err(err) => panic_notls(format_args!( - "{msg}: expect failed for Result with err: {err:?}", - )), + Err(err) => panic!("{msg}: expect failed for Result with err: {err:?}",), } } } @@ -127,7 +120,7 @@ impl ExpectTlsFree for Option { fn expect_notls(self, msg: &str) -> T { match self { Some(t) => t, - None => panic_notls(format_args!("{msg}: expect failed for Option")), + None => panic!("{msg}: expect failed for Option"), } } } diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index a06eaae227..5f58da26bf 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -541,7 +541,7 @@ pub struct TmpDisableSignalsGuard { active: bool, } -/// Used to prevent EINTR from appearing across all syscall +/// Used to disable jumping to signal handler while the guard active pub fn tmp_disable_signals() -> TmpDisableSignalsGuard { if !crate::TLS_ACTIVATED.load(Ordering::Relaxed) { return TmpDisableSignalsGuard { active: false }; diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index ffd21c4604..3d0e29c413 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -28,7 +28,7 @@ pub mod linker; pub mod start; pub mod tcb; -pub use generic_rt::{ExpectTlsFree, panic_notls}; +pub use generic_rt::ExpectTlsFree; static mut STATIC_TCB_MASTER: Master = Master { ptr: ptr::null_mut(), @@ -95,7 +95,7 @@ fn static_init( ph.p_vaddr(endian) as usize, ) }, - _ => panic_notls(format_args!("unknown AT_PHENT size {}", phent)), + _ => panic!("unknown AT_PHENT size {}", phent), }; let page_size = Sys::getpagesize(); diff --git a/src/lib.rs b/src/lib.rs index d9fcffe841..d25a597df9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,7 @@ pub mod io; pub mod iter; pub mod ld_so; pub mod out; +pub mod panic; pub mod platform; pub mod pthread; pub mod raw_cell; @@ -59,21 +60,11 @@ use crate::platform::{Allocator, NEWALLOCATOR}; #[global_allocator] static ALLOCATOR: Allocator = NEWALLOCATOR; -#[unsafe(no_mangle)] -pub extern "C" fn relibc_panic(pi: &::core::panic::PanicInfo) -> ! { - use core::fmt::Write; - - let mut w = platform::FileWriter::new(2); - let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi)); - - core::intrinsics::abort(); -} - #[cfg(not(test))] #[panic_handler] #[linkage = "weak"] pub fn rust_begin_unwind(pi: &::core::panic::PanicInfo) -> ! { - relibc_panic(pi) + crate::panic::relibc_panic(pi) } #[cfg(not(test))] @@ -87,17 +78,11 @@ pub extern "C" fn rust_eh_personality() {} #[allow(improper_ctypes_definitions)] #[unsafe(no_mangle)] pub extern "C" fn rust_oom(layout: ::core::alloc::Layout) -> ! { - // Layout not FFI-safe? - use core::fmt::Write; - - let mut w = platform::FileWriter::new(2); - let _ = w.write_fmt(format_args!( - "RELIBC OOM: {} bytes aligned to {} bytes\n", + panic!( + "RELIBC OOM: {} bytes aligned to {} bytes", layout.size(), layout.align() - )); - - core::intrinsics::abort(); + ); } #[cfg(not(test))] @@ -105,10 +90,5 @@ pub extern "C" fn rust_oom(layout: ::core::alloc::Layout) -> ! { #[linkage = "weak"] #[unsafe(no_mangle)] pub extern "C" fn _Unwind_Resume() -> ! { - use core::fmt::Write; - - let mut w = platform::FileWriter::new(2); - let _ = w.write_str("_Unwind_Resume\n"); - - core::intrinsics::abort(); + panic!("_Unwind_Resume") } diff --git a/src/panic.rs b/src/panic.rs new file mode 100644 index 0000000000..d376cde9a4 --- /dev/null +++ b/src/panic.rs @@ -0,0 +1,37 @@ +use core::fmt::Write; + +#[unsafe(no_mangle)] +pub extern "C" fn relibc_panic(pi: &::core::panic::PanicInfo) -> ! { + use core::fmt::Write; + + let mut w = PanicWriter::new(); + let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi)); + + core::intrinsics::abort(); +} + +struct PanicWriter; + +impl PanicWriter { + pub fn new() -> Self { + Self + } +} + +impl Write for PanicWriter { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + // Cannot use Sys::write, Tcb might not be available + #[cfg(target_os = "redox")] + { + // TODO: init stderr ourself if it not ready. + // Workaround: If stderr is not being prepared, + // add debugging log at kernel write() syscall + let _ = syscall::write(2, s.as_bytes()); + return Ok(()); + } + + // Non-redox platforms can directly write to stderr + let mut w = crate::platform::FileWriter::new(2); + w.write_str(s) + } +} From 9a03f5f9c44840b861cbba3de3d8ae67687426b2 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 6 Jul 2026 16:31:47 +0700 Subject: [PATCH 2/2] Remove ExpectTlsFree --- generic-rt/src/lib.rs | 26 -------------------------- redox-rt/src/lib.rs | 14 ++++++-------- src/ld_so/mod.rs | 21 +++++++++------------ src/ld_so/start.rs | 30 ++++++++++++++---------------- src/pthread/mod.rs | 6 +++--- src/start.rs | 13 +++++-------- 6 files changed, 37 insertions(+), 73 deletions(-) diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs index a9f33c6cd4..064444afee 100644 --- a/generic-rt/src/lib.rs +++ b/generic-rt/src/lib.rs @@ -98,29 +98,3 @@ impl GenericTcb { unsafe { Some(&mut *Self::current_ptr()?) } } } - -pub trait ExpectTlsFree { - type Unwrapped; - - fn expect_notls(self, msg: &str) -> Self::Unwrapped; -} -impl ExpectTlsFree for Result { - type Unwrapped = T; - - fn expect_notls(self, msg: &str) -> T { - match self { - Ok(t) => t, - Err(err) => panic!("{msg}: expect failed for Result with err: {err:?}",), - } - } -} -impl ExpectTlsFree for Option { - type Unwrapped = T; - - fn expect_notls(self, msg: &str) -> T { - match self { - Some(t) => t, - None => panic!("{msg}: expect failed for Option"), - } - } -} diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index 224aca415b..76ed579a63 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -6,8 +6,6 @@ use core::cell::UnsafeCell; -#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] -use generic_rt::ExpectTlsFree; // not used on aarch64 or riscv64 use generic_rt::GenericTcb; use redox_protocols::protocol::ProcMeta; use syscall::Sigcontrol; @@ -94,13 +92,13 @@ pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end: usize, _tls_len: usize) { let mut env = syscall::EnvRegisters::default(); let file_fd = crate::sys::dup_into_upper_raw(tcb.thread_fd().as_raw_fd(), b"regs/env") - .expect_notls("failed to open handle for process registers"); + .expect("failed to open handle for process registers"); - syscall::read(file_fd, &mut env).expect_notls("failed to read gsbase"); + syscall::read(file_fd, &mut env).expect("failed to read gsbase"); env.gsbase = tls_end as u32; - syscall::write(file_fd, &env).expect_notls("failed to write gsbase"); + syscall::write(file_fd, &env).expect("failed to write gsbase"); let _ = crate::sys::close_raw(file_fd); @@ -114,13 +112,13 @@ pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end_and_tcb_start: usize, _tls_len: let mut env = syscall::EnvRegisters::default(); let file_fd = crate::sys::dup_into_upper_raw(tcb.thread_fd().as_raw_fd(), b"regs/env") - .expect_notls("failed to open handle for process registers"); + .expect("failed to open handle for process registers"); - syscall::read(file_fd, &mut env).expect_notls("failed to read fsbase"); + syscall::read(file_fd, &mut env).expect("failed to read fsbase"); env.fsbase = tls_end_and_tcb_start as u64; - syscall::write(file_fd, &env).expect_notls("failed to write fsbase"); + syscall::write(file_fd, &env).expect("failed to write fsbase"); let _ = crate::sys::close_raw(file_fd); diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 3d0e29c413..f8b90af0f6 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -28,8 +28,6 @@ pub mod linker; pub mod start; pub mod tcb; -pub use generic_rt::ExpectTlsFree; - static mut STATIC_TCB_MASTER: Master = Master { ptr: ptr::null_mut(), image_size: 0, @@ -66,9 +64,9 @@ fn static_init( auxv = unsafe { auxv.add(1) }; } - let phdr = phdr_opt.expect_notls("failed to find AT_PHDR"); - let phent = phent_opt.expect_notls("failed to find AT_PHENT"); - let phnum = phnum_opt.expect_notls("failed to find AT_PHNUM"); + let phdr = phdr_opt.expect("failed to find AT_PHDR"); + let phent = phent_opt.expect("failed to find AT_PHENT"); + let phnum = phnum_opt.expect("failed to find AT_PHNUM"); for i in 0..phnum { let ph_addr = phdr + phent * i; @@ -115,11 +113,10 @@ fn static_init( STATIC_TCB_MASTER.image_size = p_filesz; STATIC_TCB_MASTER.offset = valign; - let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB"); + let tcb = Tcb::new(vsize).expect("failed to allocate TCB"); tcb.masters_ptr = ptr::addr_of_mut!(STATIC_TCB_MASTER); tcb.masters_len = mem::size_of::(); - tcb.copy_masters() - .expect_notls("failed to copy TLS master data"); + tcb.copy_masters().expect("failed to copy TLS master data"); tcb.activate( #[cfg(target_os = "redox")] Some(thr_fd), @@ -160,9 +157,9 @@ pub unsafe fn init( { let file = thr_fd .dup_into_upper(b"regs/env") - .expect_notls("failed to open handle for process registers"); + .expect("failed to open handle for process registers"); - file.read(&mut env).expect_notls("failed to read gsbase"); + file.read(&mut env).expect("failed to read gsbase"); } tp = env.gsbase as usize; @@ -174,9 +171,9 @@ pub unsafe fn init( { let file = thr_fd .dup_into_upper(b"regs/env") - .expect_notls("failed to open handle for process registers"); + .expect("failed to open handle for process registers"); - file.read(&mut env).expect_notls("failed to read fsbase"); + file.read(&mut env).expect("failed to read fsbase"); } tp = env.fsbase as usize; diff --git a/src/ld_so/start.rs b/src/ld_so/start.rs index b366d6b9b3..92cc89bf09 100644 --- a/src/ld_so/start.rs +++ b/src/ld_so/start.rs @@ -41,8 +41,6 @@ use super::{ tcb::Tcb, }; -use generic_rt::ExpectTlsFree; - #[cfg(target_pointer_width = "32")] pub const SIZEOF_EHDR: usize = 52; @@ -192,13 +190,13 @@ pub unsafe extern "C" fn relibc_ld_so_start( } } - let at_phdr = at_phdr.expect_notls("`AT_PHDR` must be present"); - let at_phnum = at_phnum.expect_notls("`AT_PHNUM` must be present if `AT_PHDR` is"); - let at_phent = at_phent.expect_notls("`AT_PHENT` must be present if `AT_PHDR` is"); + let at_phdr = at_phdr.expect("`AT_PHDR` must be present"); + let at_phnum = at_phnum.expect("`AT_PHNUM` must be present if `AT_PHDR` is"); + let at_phent = at_phent.expect("`AT_PHENT` must be present if `AT_PHDR` is"); assert!(!at_phdr.is_null() && at_phnum != 0 && at_phent == size_of::()); let phdrs = unsafe { slice::from_raw_parts(at_phdr, at_phnum) }; - let at_entry = at_entry.expect_notls("`AT_ENTRY` must be present"); + let at_entry = at_entry.expect("`AT_ENTRY` must be present"); let at_base = at_base.unwrap_or_default(); let self_base = if at_base != 0 { @@ -252,7 +250,7 @@ pub unsafe extern "C" fn relibc_ld_so_start( base_addr: usize, ) -> &'a [T] { if let Some(ptr) = ptr { - let len = len.expect_notls("dynamic entry was present without it's corresponding size"); + let len = len.expect("dynamic entry was present without it's corresponding size"); unsafe { core::slice::from_raw_parts(ptr.byte_add(base_addr), len) } } else { &[] @@ -315,7 +313,7 @@ fn stage2( let auxv = sp.auxv().cast(); #[cfg(target_os = "redox")] let thr_fd = crate::platform::get_auxv_raw(auxv, redox_rt::auxv_defs::AT_REDOX_THR_FD) - .expect_notls("no thread fd present"); + .expect("no thread fd present"); #[cfg(target_os = "redox")] { @@ -324,43 +322,43 @@ fn stage2( sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_FILETABLE_FD, ) - .expect_notls("no filetable fd present"); + .expect("no filetable fd present"); let filetable_guard = redox_rt::proc::FdGuard::new(filetable_fd) .to_upper() - .expect_notls("failed to move filetable fd to upper table"); + .expect("failed to move filetable fd to upper table"); *redox_rt::current_filetable() = redox_rt::sys::FdTbl::from_binary_fd(filetable_guard) - .expect_notls("failed to initialize FILETABLE"); + .expect("failed to initialize FILETABLE"); } } - let tcb = Tcb::new(0).expect_notls("[ld.so]: failed to allocate bootstrap TCB"); + let tcb = Tcb::new(0).expect("[ld.so]: failed to allocate bootstrap TCB"); tcb.activate( #[cfg(target_os = "redox")] Some( redox_rt::proc::FdGuard::new(thr_fd) .to_upper() - .expect_notls("failed to move thread fd to upper table"), + .expect("failed to move thread fd to upper table"), ), ); #[cfg(target_os = "redox")] { let proc_fd = crate::platform::get_auxv_raw(auxv, redox_rt::auxv_defs::AT_REDOX_PROC_FD) - .expect_notls("no proc fd present"); + .expect("no proc fd present"); let ns_fd = crate::platform::get_auxv_raw(auxv, redox_rt::auxv_defs::AT_REDOX_NS_FD) .filter(|&fd| fd != usize::MAX) .map(|fd| { redox_rt::proc::FdGuard::new(fd) .to_upper() - .expect_notls("failed to move ns fd to upper table") + .expect("failed to move ns fd to upper table") }); redox_rt::initialize( redox_rt::proc::FdGuard::new(proc_fd) .to_upper() - .expect_notls("failed to move proc fd to upper table"), + .expect("failed to move proc fd to upper table"), ns_fd, ); redox_rt::signal::setup_sighandler(&tcb.os_specific, true); diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index 6efae108ef..f0a016b5e4 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -13,7 +13,7 @@ use redox_rt::RtTcb; use crate::{ error::Errno, header::{errno::*, pthread as header, sched::sched_param, sys_mman}, - ld_so::{ExpectTlsFree, tcb::Tcb}, + ld_so::tcb::Tcb, platform::{Pal, Sys, types::*}, }; @@ -47,7 +47,7 @@ pub unsafe fn init() { thread.stack_size = STACK_SIZE; } - let current_tcb = unsafe { Tcb::current() }.expect_notls("no TCB present for main thread"); + let current_tcb = unsafe { Tcb::current() }.expect("no TCB present for main thread"); current_tcb.pthread = thread; unsafe { current_tcb.pthread.tcb_selfref.get().write(current_tcb); @@ -221,7 +221,7 @@ unsafe extern "C" fn new_thread_shim( tcb: *mut Tcb, synchronization_mutex: *const Mutex, ) -> ! { - let tcb = unsafe { tcb.as_mut() }.expect_notls("non-null TLS is required"); + let tcb = unsafe { tcb.as_mut() }.expect("non-null TLS is required"); #[cfg(not(target_os = "redox"))] { diff --git a/src/start.rs b/src/start.rs index 41e0754881..52eb9b1f1b 100644 --- a/src/start.rs +++ b/src/start.rs @@ -3,9 +3,6 @@ use alloc::{boxed::Box, vec::Vec}; use core::{intrinsics, ptr}; -#[cfg(target_os = "redox")] -use generic_rt::ExpectTlsFree; - use crate::{ ALLOCATOR, header::{libgen, stdio, stdlib}, @@ -169,10 +166,10 @@ pub unsafe extern "C" fn relibc_start_v1( unsafe { crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD) } - .expect_notls("no thread fd present"), + .expect("no thread fd present"), ) .to_upper() - .expect_notls("failed to move thread fd to upper table"); + .expect("failed to move thread fd to upper table"); #[cfg(target_os = "redox")] { @@ -183,12 +180,12 @@ pub unsafe extern "C" fn relibc_start_v1( redox_rt::auxv_defs::AT_REDOX_FILETABLE_FD, ) } - .expect_notls("no filetable fd present"); + .expect("no filetable fd present"); let filetable_guard = redox_rt::proc::FdGuard::new(filetable_fd) .to_upper() - .expect_notls("failed to move filetable fd to upper table"); + .expect("failed to move filetable fd to upper table"); *redox_rt::current_filetable() = redox_rt::sys::FdTbl::from_binary_fd(filetable_guard) - .expect_notls("failed to initialize FILETABLE"); + .expect("failed to initialize FILETABLE"); } }