Predictable exit code from a crashed process in Windows

For a process that typically runs on Windows, the process exit code is usually either the return value from main or the exit code passed to std::exit . %ERRORLEVEL% can then be used to request an exit code, and this can be used to determine if the program was executed correctly, or there were some exceptional inputs / failures that indicate a specific problem (application specificity).

However, I am interested in the exit code if the process crashes. Take a very simple sample program:

 int main() { int * a = nullptr; *a = 0xBAD; return 0; } 

When I compile this and run on Windows, at the command prompt I get:

 MyCrashProgram.exe -> crashes echo %ERRORLEVEL% -> -1073741819 

The exit code is a number. This leads me to a few questions:

  • Was the exit code -1073741819 somehow predictable based on an invalid write error?
  • If so, is there a way to determine the type of failure based on the exit code?
  • Does this change using the compiler (I used MSVC 2012)?
  • Does this change using the version of Windows used (I used Win10 TP)?
  • Does this change with architecture (e.g. x64 - I used Win32)?

Notice I'm not interested in how to change a program to catch an exception. I am interested in classifying crashes that can occur in existing programs that I cannot change.

+5
source share
3 answers

A comment on STATUS_ACCESS_VIOLATION led me to the documentation for GetExceptionCode :

The return value determines the type of exception. The following table lists the exception codes that may occur due to common programming errors. These values ​​are defined in WinBase.h and WinNT.h.

EXCEPTION_ACCESS_VIOLATION displayed in STATUS_ACCESS_VIOLATION in the following list. All exclusions from the list with the STATUS prefix are determined directly by exception codes with the EXCEPTION prefix. Following the documentation for RaiseException , it explains the process of trying to debug an exception when this happens, the final step is:

If the process is not debugged or if the appropriate debugger does not handle the exception, the system provides default processing based on the type of exception. For most exceptions, the default action is to call the ExitProcess function.

So, to answer my questions:

  • Yes, the exit code was predicatble, it maps to EXCEPTION_STATUS_VIOLATION .
  • Other types of errors will be mapped to other common exception codes. However, when RaiseException is thrown with an arbitrary exception code (which was unhandled), the process exit code can be any
  • The exit code depends on the Windows SDK, not on the compiler that runs the version or architecture of Windows. Although this could theoretically change with the new Windows SDKs, it is unlikely for backward compatibility.
+4
source

Here is the link to a 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 what GetExitCodeProcess will give back. The kernel does not interpret the meaning. If you want code 42, it means "Something infinitely unlikely," then more power for you.

There is an agreement, however, that the exit code from zero means success (although what constitutes β€œsuccess” remains at the discretion of the program author) and a non-zero exit code means failure (again, with details left to the discretion of the programmer). Often, higher values ​​for the exit code indicate more serious types of failures. The ERRORLEVEL shell keyword was developed using these conventions in mind.

There are times when your process will be in such a bad state that the component will commit itself to terminating the process. For example, if a process cannot find the DLLs from which it imports, or one of those DLLs cannot be initialized , the loader will stop processing and use the status code as the process exit code. I believe that when a program crashes due to an unhandled exception, an exception code is used as the exit code.

The client saw the program malfunctioning with exit code 3 and could not understand where it came from. They never use this code output in their program. In the end, the source of magic number 3 was identified: The C interrupt function terminates the process with exit code 3 .

+1
source

This is not a complete answer, but a few tips so you can move forward.

I think that it is not possible to distinguish all the possible causes of the accident automatically. To do this, you will have to catch the error yourself and provide your exit code

To catch all possible (exciting) errors, you need to configure both exceptions and signal handlers. This is because access violations are exceptions due to windows and signal (SIGSEV) under Linux.

See this question for subtle details about the different kinds of errors in windows: Exclusion of access violation exceptions

Here is another Linux signal processing thread

0
source

All Articles