0

We have some c++ code that can make calls to exit(3) through the users API. My assumption is that we are not properly unwinding stacks and that this considered bad in c++. Also there is a big c++ library involved that must be considered a black box.

I want to patch this, and also have an idea how, but don't know how to observe and compare the change. Can I make this somehow visible? Possibly on OS X?

eljefedelrodeodeljefe
  • 6,304
  • 7
  • 29
  • 61
  • 1
    Your assessment is correct: http://stackoverflow.com/questions/2668075/will-exit-or-an-exception-prevent-an-end-of-scope-destructor-from-being-called – Anya Shenanigans May 10 '16 at 17:30
  • 1
    Depends. The process is exiting. You don't need to release memory. Kernel objects will be closed automatically. So much of your cleanup need not be done. BUT! Just because a file handle is closed by the kernel does not mean the final flush of data to the file was done. And some external resources are sensitive to not being properly closed - databases prefer the client to notify them rather than just terminate the connection. So it depends: If you _know_ that no permanent side effects to the environment remain (file flushes, logging, clean database closing) go ahead and exit. – davidbak May 10 '16 at 17:38

1 Answers1

1

exit() apparently does some cleanup. This is described in section 18.5 [support.start.term] of the standard, but the frequently correct site www.cplusplus.com summarizes it.

So it says objects with static storage or thread storage will be cleaned up, as will the entire I/O system (files will be flushed, etc).

But there are other ways to exit without running the C++ cleanup. For example, if it is a library that calls exit and it is a C language library (not C++) then it may or may not do the C++ cleanup. Or there are calls to abort or quick_exit. And, too, if you call the OS directly (e.g., ExitProcess() on Windows) then the process exits immediately and no C++ cleanup is done.

If you want to make the behavior visible: Make a object with a destructor that does something interesting - like log a message somewhere. Or maybe when it is constructed it creates a file with a certain name and when destructed it deletes it. Declare an instance this object in your main(). Declare another one (with a different message) at static scope. So now you have an effect observable in your environment.

The following is from 18.5 of N4140 (2014-10-07):

[[noreturn]] void exit(int status) 
8 The function exit() has additional behavior in this International Standard:
(8.1) First, objects with thread storage duration and associated with the current
      thread are destroyed. Next,objects with static storage duration are destroyed
      and functions registered by calling `atexit` are called. See 3.6.3 for the
      order of destructions and calls. (Automatic objects are not destroyed as a
      result of calling `exit()`.) If control leaves a registered function called by
      `exit` because the function does not provide a handler for a thrown exception,
      `std::terminate()` shall be called (15.5.1).
(8.2) Next, all open C streams (as mediated by the function signatures declared in
      `<cstdio>`) with unwritten buffered data are flushed, all open C streams are
      closed, and all files created by calling `tmpfile()` are removed.
(8.3) Finally, control is returned to the host environment. If `status` is zero or
      `EXIT_SUCCESS`, an implementation-defined form of the status _successful 
      termination_ is returned. If `status` is `EXIT_FAILURE`, an implementation-
      defined form of the status _unsuccessful termination_ is returned. Otherwise 
      the status returned is implementation-defined.
davidbak
  • 5,775
  • 3
  • 34
  • 50