Is rust cleaning up after exit?


#1

Hello all!
I have made some smaller programs in rust and I really love the language.
I have one thing that I can not get my head around.
I read somewhere that if I in the middle of a function exit my program, using exit, panic!, assert_eq! or similar rust does not clean up memory. To be able to clean up the right way you have to return to main and exit there.
Example:

fn main () {
     another_fn();
}

fn another_fn() {
    for x in y {
        calculating......
         if error {
              println!("There was an error");
              exit(2);  //Program exits but is memory cleaned up?
         }
    }
}

I have been using:

fn main () {
     exit(another_fn());  // Memory is cleaned up the right way
}

fn another_fn()  -> i32 {
    let mut exit_code: i32 = 0;
    for x in y {
        calculating......
         if error {
              println!("There was an error");
              exit_code = 2;
         }
    }
    exit_code
}

Have I understood it the right way?
Am I supposed to exit in main or is memory cleaned up the correct way exiting “in the middle”?

Thanks in advance!


#2

The operating system will recover all of the memory a program has used when it exits.


#3

The OS cleans up after the process exits, but it’ll still show as leaked memory when using something like LeakSanitizer.


#4

So you mean that always return to main is unnecessarily and should not be done?


#5

The kernel will clean up memory, close file handles, etc. But if you have file data buffered in user memory, it won’t be flushed on an abnormal exit.


#6

Should probably define abnormal exit to avoid confusion. My understanding is that a panic unwinds and any Drop::drop are executed along the way (assuming a panic handler doesn’t panic itself, which I believe causes an abort that stops unwinding).


#7

It won’t leak memory, but suddenly quitting the whole program may turn out to be problematic for many other reasons (unsaved data, incomplete output, or just plain annoying to users if pressing one wrong key crashes the whole app).

You should gracefully propagate errors from functions. With plain error codes this may be tedious, but if instead of fn() -> i32 returning an error code you use fn() -> Result<(), i32> (function returning Ok(()) or Err(exit_code)) you will be able to use the ? operator to simplify calling of such functions (in all places… except main(). There use match).


#8

You’re right, that was quite unspecific, and even some of the ways aren’t necessarily “abnormal”. Off the top of my head, here are ways to exit without unwinding:

  • Panic during an unwind causes an abort, as you mentioned.
  • With rustc -C panic=abort, nobody ever unwinds.
  • std::process::abort() (currently unstable)
  • std::process::exit()
  • When main returns, other threads are terminated.
    • ditto if the main thread is fully unwound
  • unsafe code could segfault.
  • FFI code could exit, segfault, etc.