So far I identified a few cases where this might happen:
panics
calling std::process::exit
The issue with this in the current pet project is handling device handles abstracted by a library that is not very good at releasing resources, so that has to be done explcitily.
For the panic!() case one can register another intermediate handler cleaning up the handle and forwarding to the original handler.
But for the generic case, how can I assure that a func is called after the main is called? Coming from a C/C++ embedded background there exists some means of exit handlers (depening on the compiler).
Leaking a smart pointer, e.g. Box::leak() and dropping the returned reference
Creating reference cycles with Rc and Arc
And also a reminder to pre-poop your pants to avoid problems related to just never running destructors.
The linked issue reminds me of a very old issue I created against fuse-rs, where an early termination of an app implementing a VFS would leave FUSE with a dead mount point: https://github.com/zargony/fuse-rs/issues/58
Sorry I couldn't be much more help. This kind of seems like a bug in the OS, and not something Rust can (or should) solve. (But maybe some extra defensive-coding practices could be helpful anyway?)
Actually, sys_common::cleanup() uses closures implemented at_exit_impl of std which can be fed into it with sys_common::push(|| { println!("I am so done")}) (this will panic, since there is no stdout at that point)
dunno how I missed that earlier on.. let's see if it works - and for which of the mentioned cases (@parasyte thanks, I did not have all of them on my radar!)
You should be able to use all the same mechanisms as you would in C. For example the libc crate exposes bindings to atexit() on *nix machines. On Windows machines you can use DllMain for the same purpose.
A lot of these mechanisms are exposed by the OS instead of the compiler, so they should Just Work.
$ cd /tmp && cargo new thingy
$ cargo add libc
$ cat src/main.rs
extern crate libc;
fn main() {
unsafe {
libc::atexit(before_process_exit);
}
println!("Hello, world!");
}
extern "C" fn before_process_exit() {
unsafe {
libc::printf(b"Exiting!\n\0".as_ptr() as *const libc::c_char);
}
}
$ cargo run
Compiling thingy v0.1.0 (/tmp/thingy)
Finished dev [unoptimized + debuginfo] target(s) in 0.15s
Running `target/debug/thingy`
Hello, world!
Exiting!