Windows 中崩溃进程的可预测退出代码
对于Windows中正常退出的进程,该进程的退出码一般要么是main
的返回值,要么是传递给std::exit
的退出码.%ERRORLEVEL%
然后可用于查询退出代码,并可用于确定程序是否正确执行,或者是否有一些异常输入/失败指示特定问题(特定于应用程序).
但是,如果进程崩溃,我对退出代码感兴趣.举一个很简单的例子程序:
int main(){int * a = nullptr;*a = 0xBAD;返回0;}
当我编译它并在 Windows 中运行时,我在命令行上得到:
MyCrashProgram.exe ->崩溃回声 %ERRORLEVEL% ->-1073741819
退出代码始终是这个数字.这让我想到了几个问题:
- 基于无效写入崩溃,退出代码
-1073741819
是否可以预测? - 如果是这样,是否有某种方法可以根据退出代码确定崩溃的类型?
- 这是否会随着所使用的编译器而改变(我使用的是 MSVC 2012)?
- 这是否会随着使用的 Windows 版本(我使用的是 Win10 TP)而改变?
- 这是否会随着架构而改变(例如 x64 - 我使用的是 Win32)?
注意,我对如何修改程序来捕获异常不感兴趣.我有兴趣对现有程序中可能发生的崩溃进行分类,我可能无法修改.
解决方案关于 STATUS_ACCESS_VIOLATION
的评论,把我带到了 GetExceptionCode
:
EXCEPTION_ACCESS_VIOLATION
映射到后面列表中的 STATUS_ACCESS_VIOLATION
.列表中以STATUS
为前缀的所有异常都直接定义为以EXCEPTION
为前缀的异常代码.按照文档 RaiseException
,它解释了在异常发生时尝试调试异常的过程,最后一步是:
所以回答我的问题:
- 是的,退出代码是可预测的,它映射到
EXCEPTION_STATUS_VIOLATION
. - 其他类型的错误会映射到其他常见的异常代码.但是,通过使用任意异常代码(未处理)调用 RaiseException,进程的退出代码可以是任何东西
- 退出代码取决于执行 Windows 版本或体系结构的 Windows SDK,而不是编译器.虽然这在理论上可能会随着较新的 ??Windows SDK 而改变,但这不太可能实现向后兼容性.
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:
- Was the exit code
-1073741819
somehow predicable, based on the invalid write crash? - If so, is there some way to determine the type of crash, based on the exit code?
- Does this change with the compiler used (I used MSVC 2012)?
- Does this change with the version of Windows being used (I used Win10 TP)?
- Does this change with the architecture (eg. x64 - I used Win32)?
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:
- Yes, the exit code was predicatble, it maps to
EXCEPTION_STATUS_VIOLATION
. - Other types of errors would map to other common exception codes. However, with a call to RaiseException with an arbitrary exception code (which was unhandled), the exit code of the process could be anything
- The exit code is dependent on the Windows SDK, not the compiler, executing Windows version or architecture. Although this could theoretically change with newer Windows SDKs, that is highly unlikely for backwards compatibility.
相关文章