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_error
defaulting to panic (for no_std + liballoc) #66741 (comment) - The current implementation might have UB Implement Make
handle_alloc_error
default to panic (for no_std + liballoc) #76448 (comment) Tracking issue forhandle_alloc_error
defaulting 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
+liballoc
applications to start running on the Stable channelno_std
applications 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, cdylib
s, 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).