For a process exiting normally in Windows, the exit code of the process is generally either the return value from main
, or the exit code passed to std::exit
. %ERRORLEVEL%
can then be used to query the exit code, and that can be used to determine whether the program executed either correctly, or there were some exceptional inputs/failures that indicate a particular problem (application specific).
However, I'm interested in the exit code if the process crashes. Take a very simple example program:
int main()
{
int * a = nullptr;
*a = 0xBAD;
return 0;
}
When I compile this and run in Windows, on the command line I get:
MyCrashProgram.exe -> crashes
echo %ERRORLEVEL% -> -1073741819
The exit code is consistently this number. Which leads me to several questions:
-1073741819
somehow predicable, based on the invalid write crash? Note, I am not interested in how to modify the program to catch the exception. I am interested in classifying crashes that can happen in existing programs, that I may not be able to modify.
The comment about STATUS_ACCESS_VIOLATION
, led me to the documentation on GetExceptionCode
:
The return value identifies the type of exception. The following table identifies the exception codes that can occur due to common programming errors. These values are defined in WinBase.h and WinNT.h.
EXCEPTION_ACCESS_VIOLATION
maps to STATUS_ACCESS_VIOLATION
in the list that follows. All exceptions in the list prefixed with STATUS
are directly defined to exception codes prefixed with EXCEPTION
. Following the documentation to RaiseException
, it explains the process of attempting to debug the exception when it occurs, the final step being:
If the process is not being debugged, or if the associated debugger does not handle the exception, the system provides default handling based on the exception type. For most exceptions, the default action is to call the ExitProcess function.
So to answer my questions:
EXCEPTION_STATUS_VIOLATION
. Here is a related short blog post by Raymond Chen (emphasis mine):
There is no standard for process exit codes. You can pass anything you want to ExitProcess, and that's what GetExitCodeProcess will give back. The kernel does no interpretation of the value. If youw want code 42 to mean "Something infinitely improbable has occurred" then more power to you.
There is a convention, however, that an exit code of zero means success (though what constitutes "success" is left to the discretion of the author of the program) and a nonzero exit code means failure (again, with details left to the discretion of the programmer). Often, higher values for the exit code indicate more severe types of failure. The command processor ERRORLEVEL keyword was designed with these convention in mind.
There are cases where your process will get in such a bad state that a component will take it upon itself to terminate the process. For example, if a process cannot locate the DLLs it imports from, or one of those DLLs fails to initialize, the loader will terminate the process and use the status code as the process exit code. I believe that when a program crashes due to an unhandled exception, the exception code is used as the exit code.
A customer was seeing their program crash with an exit code of 3 and couldn't figure out where it was coming from. They never use that exit code in their program. Eventually, the source of the magic number 3 was identified: The C runtime abort function terminates the process with exit code 3.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With