-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
no_std + liballoc can not compile with os based toolchain caused by eh_personality required #106864
Comments
Here's one potential solution for this:
This solves the issue here because:
This approach however does add some complexity to the codegen part. Any thoughts, @Amanieu? |
Alternatively (but likely of similar complexity), would it be possible to have I forget the exact unwinding ABI(s) atm, though, so I don't recall if it's necessary for an unwind terminating frame is still required to specify a personality even if it wants to catch all unwinds including foreign. (It'd be good to verify the behavior of |
The personality function is necessary to catch and abort. Any frame without a personality function is skipped entirely by the unwinder. The abort information is either in a landingpad, which execution is redirected to by the rust personality function or possibly in the future in the LSDA (language specific data area) which is interpreted by the personality function and is an opaque blob to the unwinder.
For rust panics we never call into the unwinder in case of |
So yes, it's not possible to catch/terminate an unwind without specifying a personality. I wasn't certain and thought a catch-all could be defined without, but apparently I misremembered. (It's also possible that's true in some unwind ABIs but not always in general e.g. as exposed by LLVM.) aside clarification, off-topic to OPAnd to be clear, I wasn't meaning to say to change anything about how unwinds are started, just how Footnotes
|
For C-unwind -> Rust, yes. For Rust -> C-unwind I believe we skip aborting as no panic/exception can reach it. Or at least we can do so in the future without too much effort I think. |
Ah, that's unfortunate. :/ Sorry for the breakage. We can also revert that PR for now. I won't have the time to do follow-on work here. |
It seems that there is no easy solution to this problem, Since #106045 does not introduce new features or fix any bugs, just behavioral optimization. Can we just revert it first as @RalfJung said, and discuss the consistency of no_std and std panic behavior later when @RalfJung has time to follow on it? |
I guess |
If revert #106045 alone is not an acceptable option, then it is better to continue to wait for someone to fix this problem, and keep these two merged PRs at least allow bare metal development to use the alloc in rust 1.68 stable :) |
FWIW I don't think I would do the follow-on in the future either. This was meant to be a "quick fix". I hope someone else can take over. :) |
I'm trying one approach right now :) |
The fundamental issue here is that the standard library (including core/alloc) is built with One possible solution would be to have rustc automatically insert a dummy implementation of the personality function (with weak linkage) when building without the standard library (which provides the personality function even with |
This specific issue happens even when libcore is compiled with panic=abort due to a call to |
This can result in UB if rust/library/std/src/personality/gcc.rs Lines 98 to 101 in 38a76f3
|
I've got a basic implementation in https://github.com/bjorn3/rust/tree/panic_handler_nounwind. Still has some failing tests though. However while working on this, I realized that we actually already correctly handle everything in the case of libcore compiled with
This is not what @gngshn got however despite not using |
For reference this is what worked for me: # Cargo.toml
[package]
name = "foo"
version = "0.1.0"
edition = "2021"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort" // src/main.rs
#![no_std]
#![no_main]
extern crate alloc;
#[link(name = "c")]
extern "C" {}
#[panic_handler]
fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { loop {} }
struct A;
unsafe impl alloc::alloc::GlobalAlloc for A {
unsafe fn alloc(&self, _: alloc::alloc::Layout) -> *mut u8 { todo!() }
unsafe fn dealloc(&self, _: *mut u8, _: alloc::alloc::Layout) { todo!() }
}
#[global_allocator]
static ALLOC: A = A;
#[no_mangle]
extern "C" fn main() {
alloc::alloc::handle_alloc_error(alloc::alloc::Layout::new::<()>());
} $ cargo +nightly build -Zbuild-std=core,alloc --target x86_64-unknown-linux-gnu
Compiling foo v0.1.0 (/tmp/foo)
Finished release [optimized] target(s) in 0.16s |
Hello @bjorn3
|
For me
and should have done so for years. Do you have any custom |
No, my project is fresh generated by [source.crates-io]
replace-with = 'ustc'
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc" If I delete all content in ${HOME}/.cargo/config.toml, it is still show:
Before I test this, I have executed |
By the way, my system is ubuntu 22.04 WSL. I also tested this case on MacOS with mbp and ubuntu 18.04 with PC, it got almost the same result.
|
I'm utterly confused how this didn't produce that |
I can get Maybe you can compare your verbose log with mine to find some difference?
|
I can now reproduce it too for some reason. I can also reproduce that it worked on stable (if I add I think @Amanieu's suggestion of creating a dummy personality function would be the proper solution. As I said in #106864 (comment) it will need to abort in all cases except when generating backtraces. |
Great, this is the magic of linker gc and my good luck~ I naively thought this would always compile properly :( |
Given Ralf's PR and the Do we need to revert Ralf's PR for beta, so would it be fine to leave this as is? |
I don't think we need revert Ralf's PR now! |
The solution for which I posted a branch in #106864 (comment) is not something I will finish I think given what I now know about what the actual issue is. I may implement the solution in #106864 (comment) at a later point, but it is probably a bit harder, so I don't think I have time for it right now. I have added it to my backlog, but it might take a while until I get to it. If someone else would like to pick it up that did be great. |
Hi @bjorn3 |
rust/compiler/rustc_middle/src/middle/lang_items.rs Lines 48 to 58 in c3efa51
apparently this logic thinks that |
If libcore is compiled as panic=abort and |
I have this issue too. [profile.release]
lto = "fat"
panic = "abort" Note: rustc: 1.74.1 (a28077b28 2023-12-04)
cargo: 1.74.1 (ecb9851af 2023-10-18)
host: x86_64-unknown-linux-gnu However, during development, I can not always enable #![allow(internal_features)]
#![cfg_attr(debug_assertions, feature(lang_items))]
#[cfg(debug_assertions)]
#[lang = "eh_personality"]
extern "C" fn rust_eh_personality() {} It requires nightly toolchain. As with It works: use ::alloc::boxed::Box;
let b = Box::new("Heap");
println!("{b}"); It does not work: use libc_print::std_name::println;
let up = "Hello world".to_uppercase();
println!("{up}"); To avoid using the nightly toolchain, and to solve the linking problem. #[no_mangle]
extern "C" fn rust_eh_personality() {}
#[allow(non_snake_case)]
#[no_mangle]
extern "C" fn _Unwind_Resume() {} After this, even stable toolchain + The complete demo code is below: #![no_std]
#![no_main]
//!
//! ```cargo
//! [dependencies]
//! libc = { version = "0.2.151", default-features = false }
//! libc-print = "0.1.22"
//! libc_alloc = "1.0.5"
//!
//! [profile.dev]
//! panic = "abort"
//!
//! [profile.release]
//! # lto = "thin"
//! panic = "abort"
//! opt-level = "s"
//! strip = true
//! ```
//!
#[no_mangle]
extern "C" fn rust_eh_personality() {}
#[allow(non_snake_case)]
#[no_mangle]
extern "C" fn _Unwind_Resume() {}
// ---------
extern crate alloc;
use ::alloc::boxed::Box;
use ::core::{ffi::c_int, panic::PanicInfo};
use libc_alloc::LibcAlloc;
use libc_print::std_name::{dbg, eprintln, println};
#[global_allocator]
static GLOBAL_ALLOC: LibcAlloc = LibcAlloc;
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
eprintln!("[FATAL]: {info}");
unsafe { libc::abort() }
}
#[no_mangle]
pub extern "C" fn main() -> c_int {
let upper = "ok".to_uppercase();
println!("{upper}");
let b = Box::new("heap");
dbg!(b);
0
} I don't know if it would be a problem to manually create a |
Thanks for your infomation. This seems another good way to test no_std + liballoc on stable toolchain. As you said, doing this seems to replace the default implementation of _Unwind_Resume and rust_eh_personality in rust static lib. This also can not be used in production environment. It maybe UB? And the naming _Unwind_Resume may be changed in the future? We also can use cargo build std with RUSTC_BOOTSTRAP=1, But I think this is also not a real safty way and can not be used in production environment. |
Nope, that is a stable interface of the itanium style unwinding that is used on almost all Unix systems.
If your program is linking in C++ code that wants to throw exceptions, yes. But in that case you would link against libunwind anyway and thus not have this undefined reference. As for By the way all targets that are meant exclusively for no_std usage don't have this issue as the standard library is already compiled with panic=abort. It is a real problem for the targets that are for running under a conventional OS though. |
Might be related to #56152 |
Update at 2023-01-20
The previous test that met the expected conditions was actually just a case of not testing enough to get the linker's GC optimizations out of the way. The problem is now updated to the fact that in the case of
default_alloc_error_handler
merged, the OS-based toolchain cannot compile the no_std + liballoc crate without using the unstable build-std feature, and the error shows up as a missingrust_eh_ personality
dependency. Using OS-based toolchain to compile no_std + liballoc is intended to compile small binaries for tiny embedded linux.I tried this code:
I expected to see this happen: This code build and run perfectly with panic=abort and non nightly features in nightly rust, and when rust 1.68 is comming, we can build this in stable rust.
We use no_std + liballoc to build small linux app in embedded linux, in production, we need stable rust.
Instead, this happened: The latest rust nightly can not build this code again(nightly-2022-12-29 is okay), it failed with this link error:
this seem caused by #106045
Meta
rustc --version --verbose
:Backtrace
The text was updated successfully, but these errors were encountered: