-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Tracking issue for the OOM hook (alloc_error_hook
)
#51245
Comments
We have an accepted RFC #48043 that includes adding a way to opt into of panicking instead of aborting on OOM (so that |
Oh right, I had forgotten about that. And in fact, it works: #![feature(allocator_api)]
use std::alloc::set_oom_hook;
use std::alloc::Layout;
fn oom(layout: Layout) -> ! {
panic!("oom {}", layout.size());
}
fn main() {
set_oom_hook(oom);
let result = std::panic::catch_unwind(|| {
let v = Vec::<u8>::with_capacity(100000000000000);
println!("{:p}", &v[..]);
});
println!("{:?}", result);
}
|
(despite the |
Added item about interaction with unwinding. |
@glandium While this example works, the |
Picture me puzzled. #![feature(allocator_api)]
use std::alloc::set_oom_hook;
use std::alloc::Layout;
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo");
}
}
fn oom(layout: Layout) -> ! {
let f = Foo;
panic!("oom {}", layout.size());
}
fn main() {
set_oom_hook(oom);
let result = std::panic::catch_unwind(|| {
let f = Foo;
let v = Vec::<u8>::with_capacity(100000000000000);
println!("{:p}", &v[..]);
});
println!("{:?}", result);
}
|
Or #![feature(allocator_api)]
use std::alloc::set_oom_hook;
use std::alloc::Layout;
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo");
}
}
fn oom(layout: Layout) -> ! {
let f = Foo;
panic!("oom {}", layout.size());
}
fn main() {
set_oom_hook(oom);
let result = std::panic::catch_unwind(|| {
let f = Foo;
std::alloc::oom(Layout::new::<u8>());
println!("after oom");
});
println!("{:?}", result);
}
|
Ah, I forgot |
With panic hooks they notably return OOM hooks could always panic/abort themselves of course but the signature may just want to be that by default we don't require it and then the fallback of OOM is to abort as OOM does today |
|
Per discussion in rust-lang#51245 (comment) This allows more flexibility in what can be done with the API. This also splits `rtabort!` into `dumb_print` happening in the default hook and `abort_internal`, happening in the actual oom handler after calling the hook. Registering an empty function thus makes the oom handler not print anything but still abort. Cc: @alexcrichton
Make the OOM hook return `()` rather than `!` Per discussion in #51245 (comment) This allows more flexibility in what can be done with the API. This also splits `rtabort!` into `dumb_print` happening in the default hook and `abort_internal`, happening in the actual oom handler after calling the hook. Registering an empty function thus makes the oom handler not print anything but still abort. Cc: @alexcrichton
Why does |
This matches panic hooks, and while not exactly simple (because you can't use a closure as hook), it can be used to do whatever your hook does, while still printing the default message from libstd, whatever it is, without having to care about doing it properly yourself (which the current implementation doesn't do, since it can end up allocating aiui, which rather makes the point: one shouldn't try to replicate the code of the default handler) |
Or, if another hook was already set, it allows to fall back to that one. |
On accessing the current/default hook, sure. But why unregistering it in the process? |
Would you rather add a function to unregister the current hook and break the similarity with the panic hook? |
Why is the oom hook a function rather than a closure? |
Because a closure can't be stored in an Atomic afaict, and using an Atomic is necessary because RwLock or Mutex can be lazily initialized and allocate memory on some platforms. You don't want to be allocating memory when trying to retrieve the hook while you're handling an oom. |
Seems like we can avoid that problem with a flag tracking if set_hook has ever been called. If it hasn't, we just call the default hook directly and avoid touching the mutex. |
Well, another (new) reason is that we eventually want to move this to liballoc, which doesn't have access to any kind of locking primitive. |
It can (playground): #![feature(atomic_integers, const_fn)]
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
const unsafe fn transmute(x: *mut u8) -> usize {
union T {
a: *mut u8,
b: usize
}
T { a: x }.b
}
const BAR: *mut u8 = ((|| 3) as fn() -> i32) as *mut u8;
const FOO: AtomicUsize = AtomicUsize::new(unsafe { transmute(BAR) });
// static FOO: AtomicUsize = AtomicUsize::new(unsafe { transmute(BAR) }); // ALSO OK
fn main() {
let l = FOO.load(Ordering::Relaxed);
let l: fn() -> i32 = unsafe { std::mem::transmute(l) };
assert_eq!(l(), 3);
} |
Only closures that do not capture anything can be cast to function pointers, not arbitrary |
#51543 propose renaming the functions to |
Of course. I thought we were only talking about closures without any environment, since I don't see how panic hooks with state make much sense (maybe someone can elaborate on that). If you need to set a closure with an environment as a panic hook you just have to implement a struct representing the environment, implement the fn traits on that, and put the struct in a static in a properly synchronized way. Depending on how big the environment is, you might get away with a single extra atomic, or you might need a Mutex+Arc combo for it. Using a Mutex inside a panic hook sounds like a pretty bad idea to me though. |
About the open point 2 "Interaction with unwinding". It would be really nice if this could allow the hook to panic. Reason being that you can then catch such a panic at the C boundary. This would help cases like this: hyperium/hyper#2265 |
Besides the interaction with unwinding, which I would like to be able to rely on, I'm also interested in the timeline of stabilizing this. It looks fairly quiet, if we answer the unwinding question, is there anything else preventing stabilizing soon? |
I think |
Note this was modeled on the panic hook API https://doc.rust-lang.org/beta/std/panic/fn.set_hook.html https://doc.rust-lang.org/beta/std/panic/fn.take_hook.html |
The Is this implementation going to change to allow unwinding, or is |
The implementation itself doesn't prevent unwinding. What does is pre-existing code that marks oom functions as |
Now that #88098 has been merged, what's the status of this issue? |
There's one unresolved question:
|
Hi, I would love to see this feature stabilized. My use-case is handling out-of-memory errors in WebAssembly as panics to avoid aborting the process, as that results in an unhelpful "unreachable executed" message. As far as I know that cannot be achieved using stable Rust, as even the However I do have one concern. This API was modeled after So I am wondering if there is some easy way to avoid that problem here before the API is stabilized. I don't know if the use case of a library trying to temporarily set a different oom-handler is common enough to worry about it, or if it will even exist. The simplest solution I can think of is to make |
In #51540 (comment) I argue for the removal of special handling for OOMs in favor of just treating them as a panic. Comment copied below. After working on the OOM handler for a while, I think that the best way to move forward is to just treat OOM as a normal panic (so that it calls the normal panic handler/hooks). This is what already happens on I believe that we should do the same for the
|
FYI #51540 is under FCP for closing, which will also close this tracking issue. Please comment in that thread if you have any objections. |
…twco Report allocation errors as panics OOM is now reported as a panic but with a custom payload type (`AllocErrorPanicPayload`) which holds the layout that was passed to `handle_alloc_error`. This should be review one commit at a time: - The first commit adds `AllocErrorPanicPayload` and changes allocation errors to always be reported as panics. - The second commit removes `#[alloc_error_handler]` and the `alloc_error_hook` API. ACP: rust-lang/libs-team#192 Closes rust-lang#51540 Closes rust-lang#51245
Report allocation errors as panics OOM is now reported as a panic but with a custom payload type (`AllocErrorPanicPayload`) which holds the layout that was passed to `handle_alloc_error`. This should be review one commit at a time: - The first commit adds `AllocErrorPanicPayload` and changes allocation errors to always be reported as panics. - The second commit removes `#[alloc_error_handler]` and the `alloc_error_hook` API. ACP: rust-lang/libs-team#192 Closes rust-lang#51540 Closes rust-lang#51245
Report allocation errors as panics OOM is now reported as a panic but with a custom payload type (`AllocErrorPanicPayload`) which holds the layout that was passed to `handle_alloc_error`. This should be review one commit at a time: - The first commit adds `AllocErrorPanicPayload` and changes allocation errors to always be reported as panics. - The second commit removes `#[alloc_error_handler]` and the `alloc_error_hook` API. ACP: rust-lang/libs-team#192 Closes rust-lang#51540 Closes rust-lang#51245
Report allocation errors as panics OOM is now reported as a panic but with a custom payload type (`AllocErrorPanicPayload`) which holds the layout that was passed to `handle_alloc_error`. This should be review one commit at a time: - The first commit adds `AllocErrorPanicPayload` and changes allocation errors to always be reported as panics. - The second commit removes `#[alloc_error_handler]` and the `alloc_error_hook` API. ACP: rust-lang/libs-team#192 Closes rust-lang#51540 Closes rust-lang#51245
alloc_error_hook
)
PR #50880 added an API to override the std OOM handler, similarly to the panic hook. This was discussed previously in issue #49668, after PR #50144 moved OOM handling out of the
Alloc
/GlobalAlloc
traits. The API is somewhat similar to what existed before PR #42727 removed it without an explanation. This issue tracks the stabilization of this API.Defined in the
std::alloc
module:CC @rust-lang/libs, @SimonSapin
Unresolved questions
Name of the functions. The API before rustc: Implement the #[global_allocator] attribute #42727 usedMake the OOM hook return_handler
, I made it_hook
in OOM handling changes #50880 because that's the terminology used for the panic hook (OTOH, the panic hook returns, contrary to the OOM hook).()
rather than!
#51264std::alloc
?alloc::alloc::oom
is marked#[rustc_allocator_nounwind]
, so theoretically, the hook shouldn't panic (except when panic=abort). Yet if the hook does panic, unwinding seems to happen properly except it doesn't.The text was updated successfully, but these errors were encountered: