No one does this. The best you can hope for is that a rare few especially error prone allocations (perhaps they are huge, or user controlled) are handled. Someone might I suppose also wrap all malloc calls in a function that shows a dialog or error message and only then exits. But returning all the way to the top, yeah.. no..
I think this is fair the majority of time, but I'd like to mention Zig, since Zig has a convention of all allocations being fallible and handled. It's a pain at first to handle error.OutOfMemory at each allocating site, but I feel like I'm much more conscious of where allocation can fail and how to gracefully handle it. I've also gotten a lot better at transactions since pretty much every operation has failure points now.
In fact I've written a whole interpreter that can recover from OOM by raising a recoverable exception to the user. It's really only because Zig made recovering idiomatic, and I'm not sure I could've done it in another language (maybe Rust but I'd have to rewrite large parts of stdlib to both return an error and take a custom allocator).
The Rust stdlib has added those functions that return errors, and the types are parameterized by the allocator trait. The trait is coming to stable in the next release!
Oh that's exciting! I knew about the allocator work, but I hadn't heard about error reporting for failed allocations, or that it was about to be stabilized.
In userspace/application code this isn't giving you all the value you hope for - because of overcommit and fork/exec, you can OOM on simply modifying a variable (in a non-file-backed page).
What Zig does is great, but it is not actually comprehensively checking that all allocations are fallible and handled. That's not possible on Linux.
So it is a good advice for beginners.
In fact I've written a whole interpreter that can recover from OOM by raising a recoverable exception to the user. It's really only because Zig made recovering idiomatic, and I'm not sure I could've done it in another language (maybe Rust but I'd have to rewrite large parts of stdlib to both return an error and take a custom allocator).
I’m not sure when those are becoming stable, but Rust for Linux has been driving a bunch of this work, in my understanding, so that’s helped a lot.
What Zig does is great, but it is not actually comprehensively checking that all allocations are fallible and handled. That's not possible on Linux.