-
Couldn't load subscription status.
- Fork 13.9k
Description
The proposal below was implemented in #76448, feature-gated under #![feature(default_alloc_error_handler)].
Issues to resolve before stabilization:
- Document the new behavior
- Get some usage experience beyond a synthetic test case Tracking issue for
handle_alloc_errordefaulting to panic (for no_std + liballoc) #66741 (comment) - The current implementation might have UB Implement Make
handle_alloc_errordefault to panic (for no_std + liballoc) #76448 (comment) Tracking issue forhandle_alloc_errordefaulting to panic (for no_std + liballoc) #66741 (comment)Removing that unwind attribute needs to be benchmarked as it could lead to many extra unwind edges
Initial proposal:
Summary
This issue is for getting consensus on a change initially proposed in the tracking issue for #[alloc_error_handler]: #51540 (comment)
When no #[alloc_error_handler] is defined (which implies that std is not linked, since it literally has such a handler), alloc::alloc::handle_alloc_error should default to calling core::panic! with a message identical to the one that std prints to stderr before aborting in that case.
Although #51540 (comment) suggested that a full RFC would not be necessary, this is loosely structured after the RFC template.
Background
See the Background section of the sibling issue proposing stabilization of the attribute.
Motivation
As of Rust 1.36, specifying an allocation error handler is the only requirement for using the alloc crate in no_std environments (i.e. without the std crate being also linked in the program) that cannot be fulfilled by users on the Stable release channel.
Removing this requirement by having a default behavior would allow:
no_std+liballocapplications to start running on the Stable channelno_stdapplications that run on Stable to start usingliballoc
Guide-level explanation
When std is linked in an application, alloc::alloc::handle_alloc_error defaults to printing an error message to stderr and aborting the process.
When std is not linked and no other #[alloc_error_handler] is defined, handle_alloc_error defaults to panicking as if the following handler were defined:
#[alloc_error_handler]
fn default_handler(layout: core::alloc::Layout) -> ! {
panic!("memory allocation of {} bytes failed", layout.size())
}Reference-level explanation
The implementation for this would be very similar to that of #[global_allocator]. (Links in the next two paragraphs go to that implementation.)
alloc::alloc::handle_alloc_error is modified to call an extern "Rust" { fn … } declaration.
The definition of this function does not exist in Rust source code. Instead, it is synthesized by the compiler for “top-level” compilations (executables, cdylibs, etc.) when alloc is in the crate dependency graph. If an #[alloc_error_handler] is defined, the synthesized function calls it. If not, the synthesized function calls alloc::alloc::default_error_handler which is a new lang item. (Or is it?)
In order to allow experimentation for this new default behavior, it should initially be gated behind the #![feature(default_alloc_error_handler)] feature flag. When no handler is defined, a call to the default is (at first) only synthesized if any of the crates in the dependency graph has that feature gate. If none of them do, the current compilation error continues to be emitted.
Alternatives
The status quo is that no_std + alloc requires Nightly.
Stabilizing #[alloc_error_handler] or some other mechanism for specifying this handler is another way to unlock the no_std + liballoc on Stable use case. This removes the initial motivation for coming up with this default behavior. However perhaps this default is still desirable? In a no_std environment where there is no process to abort, the allocation error handler will likely be very similar to the panic handler (which is already mandatory).