views:

394

answers:

2

There are various ways of exiting a process:

e.g.: ExitProcess, ExitThread (from the main thread), exit, abort, return from main, terminate.

I'd like to know the effects each method has on static/global/automatic object destruction.

For example, I have a project that crashes (probably due to some deallocation error) when ExitProcess is called, but not when exit() is called. (related to this question, incidentally).

So basically I'd like to know under which circumstances deallocation of the above objects occurs, and in what order (For VC++).

+8  A: 

In short: The only totally safe thing to do is to allow main(), or your thread function, to return.

The C++ standard guarantees (3.6.3/1, 18.3) that destructors for global objects (including static objects) will be called if exit() is called, however it explicitly states that destructors for local variables will not be called in this case. exit() will call any functions registered with atexit(), and will also flush and then close any open stdio streams (including at least stdin, stdout, stderr).

Calling abort() is guaranteed not to call local or global destructors. Nor will it call functions registered with atexit() or flush stdio streams.

Calling any Win32 primitive such as ExitProcess() or ExitThread() will certainly not call destructors for local variables, and will almost certainly not call any destructors for global objects, or any functions registered with atexit(). Calling these functions directly in a C++ program is not advised -- basically, these Win32 functions and the C++ runtime library know nothing about each other. In fact, even the MSDN documentation for ExitThread() advises that C++ programs should return from the thread function instead of calling ExitThread().

(It is theoretically possible that the runtime library has specially arranged for ExitProcess() to call global object destructors -- this could be done by always loading a specific DLL whose entry point function will perform these calls, since ExitProcess() will call the entry point function for each loaded DLL with DLL_PROCESS_DETACH -- however to my knowledge, no implementation does this.)

j_random_hacker
Actually ExitProcess does call atexit-registered global destructors, if they are defined in a DLL. It depends on the order of the calls to DLLMain (detach process). ExitProcess seems to detach DLLs first and then try to clean up its own atexits, and exit() does the opposite thing. Thus, if you declare statics that rely on some external DLL, they may fail to destruct through ExitProcess.(This is based on some experimentation I've done today.)
Assaf Lavie
Interesting that other DLLs seem to call their destructors when they receive DLL_PROCESS_DETACH. The docs for ExitProcess() don't say in what order the DLLs' entry points are called, but even if they are called in LIFO order, I think problems can still arise if global objects in different DLLs refer to each other.
j_random_hacker
Calling dtors from DLL_PROCESS_DETACH makes sense if you notice they call ctors from DLL_PROCESS_ATTACH. But it's really up to the compiler that created the DLL and the caller to arrange this. Look at DLL lazy loading to see another possible implementation path.
MSalters
A: 

See the source code of ExitProcess() (posted on compuserve, usenet)

Tempted to -1 this -- if at all possible, you should avoid depending on implementation details, as they are **subject to change without notice at any moment** (e.g. when a Windows Update background process next installs a security update). That said, if you know for sure that the source code corresponds to the version you are running, this might help you debug something.
j_random_hacker