Bug or feature? std.c.stdlib.exit() breaks RAII

Ashish Myles marcianx at gmail.com
Thu Dec 29 20:03:23 PST 2011


On Thu, Dec 29, 2011 at 7:16 PM, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
>
> A D exit function would have to do essentially the same thing as throw an
> exception and catch it in main anyway. The only way that the stack is going to
> be unwound properly is if you actually unwind it. The only way in the language
> to do that without actually returning from each and every function on the
> stack is to throw an exception.
>
> How many modern languages do you know of with an exit function that cleans
> everything up properly? C++ won't for the same reasons that D won't. Java gets
> away with it because it doesn't have destructors or scope statements or
> anything else that would actually require unwinding the stack.
>
> All a D exit function _could_ do would be to throw an exception and then have
> the runtime catch it - which still wouldn't work if the programmer was foolish
> enough to do something like
>
> catch(Exception) {}
>
> in their code. So, throwing an exception and catching it _is_ the way to do
> it, and it really makes more sense if you're doing it yourself, since then
> you're less likely to make that mistake and catch all Exceptions somewhere in
> your code and eat the one which is supposed to exit the program.
>
> - Jonathan M Davis

Hm...embarassingly, it didn't occur to me that C++ didn't clean up
either; but sure enough, the following code shows that exit() breaks
C++ RAII.

#include <iostream>
#include <cstdlib>

struct SafeExit {
    ~SafeExit() {
        std::cout << "Safely exit with destructor." << std::endl;
    }
};

int main(int argc, char** argv)
{
    SafeExit safeExit;

    std::cout << "Test if std.c.stdlib.exit() breaks RAII." << std::endl;
    std::cout << "Pre-exit!" << std::endl;
    exit(0);
    std::cout << "Post-exit! Should not get here!" << std::endl;

    return 0;
}

On the other hand, ruby happily *does* unwind the stack properly on exit().

def safe_exit
    begin
        yield
    ensure
        puts "Safely exit with ensure."
    end
end

safe_exit do
    puts "Test if std.c.stdlib.exit() breaks RAII."
    puts "Pre-exit!"
    exit(0);
    puts "Post-exit! Should not get here!"
end

Honestly, I would rather have the latter robustness. While I have
always thought of abort() as being a dirty exit, I had, until now,
always thought of exit() as being very safe.  Violating RAII on a
safely-intended exit() is a really Bad Thing, I would think.  Since D
could conceivably implement a very safe exit() without an explicit use
of Exceptions to get around the "catch Exception() {}" problem you
mentioned above, does it make sense to request a safer exit() feature
for D?

Ashish


More information about the Digitalmars-d-learn mailing list