每个C++开发人员都应该知道哪些关于结构化异常的重要观点?
为什么64位Windows在异常期间不能展开堆栈,如果堆栈跨越内核边界 - 当32位Windows可以?
整个问题的背景来自:
消失的OnLoad异常 - x64中的用户模式回调异常的情况
在32位Windows中,如果我在我的用户模式代码中抛出异常,那是从内核模式代码调用的,这是从我的用户模式代码调用的,例如:
User mode Kernel Mode
------------------ -------------------
CreateWindow(...); ------> NtCreateWindow(...)
|
WindowProc <---------------------+
Run Code Online (Sandbox Code Playgroud)
Windows中的结构化异常处理(SEH)可以展开堆栈,通过内核模式展开回到我的用户代码,在那里我可以处理异常,并且我看到有效的堆栈跟踪.
64位版本的Windows无法执行此操作:
由于复杂的原因,我们无法在64位操作系统(amd64和IA64)上传播异常.自从Server 2003的第一个64位版本发布以来,情况一直如此.在x86上,情况并非如此 - 异常通过内核边界传播,并最终将帧移回
由于在这种情况下无法回溯可靠的堆栈跟踪,因此必须做出决定:让您看到非荒谬的异常,或者完全隐藏它:
当时的内核架构师决定采用保守的AppCompat友好方法 - 隐藏异常,并希望最好.
本文接着讨论了所有64位Windows操作系统的表现如何:
但是从Windows 7(和Windows Server 2008)开始,架构师改变了主意 - 有点像.对于仅 64位应用程序(不是32位应用程序),它们(默认情况下)会停止抑制这些用户内核用户异常.所以,默认情况下,在:
所有64位应用程序都会看到这些异常,他们从来没有看到它们.
在Windows 7中,当本机x64应用程序以这种方式崩溃时,将通知 …
windows 64-bit structured-exception windows64 windows-appcompat-platform
在下面的代码中,函数以foo递归方式调用一次.内部调用导致引发访问冲突.外部调用捕获异常.
#include <windows.h>
#include <stdio.h>
void foo(int cont)
{
__try
{
__try
{
__try
{
if (!cont)
*(int *)0 = 0;
foo(cont - 1);
}
__finally
{
printf("inner finally %d\n", cont);
}
}
__except (!cont? EXCEPTION_CONTINUE_SEARCH: EXCEPTION_EXECUTE_HANDLER)
{
printf("except %d\n", cont);
}
}
__finally
{
printf("outer finally %d\n", cont);
}
}
int main()
{
__try
{
foo(1);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("main\n");
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这里的预期输出应该是
inner finally 0
outer finally 0
inner finally 1
except 1 …Run Code Online (Sandbox Code Playgroud) Enable C++ Exceptions: Yes With SEH Exceptions (/EHa)"._set_se_translator()用它调用.set_terminate()和set_unexpected().EXCEPTION_STACK_OVERFLOW异常的捕获.我尝试的所有事情都没有导致EXCEPTION_STACK_OVERFLOW异常.
有没有人知道如何保证在发布模式的运行时期间有机会获得此异常?
(考虑到这个网站的名称,我有点惊讶这个问题已不在这里了!)
c++ stack-overflow debugging exception-handling structured-exception
我正在考虑修改MS结构化异常到异常映射代码,我们必须使用新的C++ 11 error_code/error_condition/exception mechanisim.
我的理解是,一般的哲学是你应该首先尝试将你的错误代码映射到std :: error_condition代码,否则,制作你自己的自定义error_condition代码.
我看到的问题是std :: errc非常适合与POSIX错误配合使用.如果我从一个源代码中获取代码,该代码具有与典型OS调用相比差异很大的错误,那么它就不能很好地映射.
例如,我们可以使用Microsoft的SEH代码.这些来自操作系统,所以理论上它应该映射以及POSIX之外的任何东西.但它肯定似乎没有很好地映射:
EXCEPTION_ACCESS_VIOLATION = permission_denied
EXCEPTION_ARRAY_BOUNDS_EXCEEDED = argument_out_of_domain perhaps?
EXCEPTION_BREAKPOINT = ?
EXCEPTION_DATATYPE_MISALIGNMENT = ?
EXCEPTION_FLT_DENORMAL_OPERAND = ?
EXCEPTION_FLT_DIVIDE_BY_ZERO = ?
EXCEPTION_FLT_INEXACT_RESULT = ?
EXCEPTION_FLT_INVALID_OPERATION = ?
EXCEPTION_FLT_OVERFLOW = ?
EXCEPTION_FLT_STACK_CHECK = ?
EXCEPTION_FLT_UNDERFLOW = ?
EXCEPTION_GUARD_PAGE = ?
EXCEPTION_ILLEGAL_INSTRUCTION = ?
EXCEPTION_IN_PAGE_ERROR = ?
EXCEPTION_INT_DIVIDE_BY_ZERO = ?
EXCEPTION_INT_OVERFLOW = value_too_large perhaps, but then what do I use for _STACK_OVERFLOW?
EXCEPTION_INVALID_DISPOSITION = ?
EXCEPTION_INVALID_HANDLE = ? …Run Code Online (Sandbox Code Playgroud) 我在Visual C++中实现的COM服务器使用了大量其他C++代码.其他C++代码有时会包含代码__try- __except并将结构化异常转换为自定义C++异常.这部分我无法改变.
我的COM服务器的任何方法都不应该允许这些异常通过COM边界传播,因此它必须捕获并将它们转换为HRESULTs.这些自定义C++异常包含在翻译期间获得的原始错误代码 - 它就像是EXCEPTION_ACCESS_VIOLATION.问题是我如何设计一个合适的HRESULT值,以便客户端尽可能多地获得有关发生的事情的信息(并且可能在看到访问冲突后决定重新启动服务器(以及在inproc的情况下).
假设它是EXCEPTION_ACCESS_VIOLATION在中定义的WinBase.h
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
Run Code Online (Sandbox Code Playgroud)
而后者的定义是 WinNT.h
#define STATUS_ACCESS_VIOLATION ((DWORD)0xC0000005L)
Run Code Online (Sandbox Code Playgroud)
我可以使用它HRESULT_FROM_WIN32()来转换代码,HRESULT假设它首先是一个Win32错误.
我HRESULT_FROM_WIN32()在这里使用还是以其他方式进行翻译?
我有一个函数,我调用它getaddrinfo()来获取sockaddr*系统分配的目标内存.许多人可能知道,你需要调用freeaddrinfo()来释放getaddrinfo()分配的内存.
现在,在我的函数中,有一些地方,我可能会抛出异常,因为某些函数失败了.我的第一个解决方案是将freeaddrinfo()每个if块整合到一起.但对我来说这看起来确实很难看,因为在我的函数返回之前我不得不调用它,所以我想出了SEH的尝试 - 终于......
但我遇到的问题是,不允许将throw语句编码到__try-block中
然后,我读了msdn并尝试将throw语句交换到__try-block中调用的辅助函数...瞧,编译器不再呻吟了......
这是为什么?这样安全吗?这对我来说没有意义:/
码:
void function()
{
//...
addrinfo* pFinal;
__try
{
getaddrinfo(..., &pFinal);
//if(DoSomething1() == FAILED)
// throw(exception); //error C2712: Cannot use __try in functions that require object unwinding
//but this works
Helper();
//...
}
__finally
{
freeaddrinfo();
}
}
void Helper()
{
throw(Exception);
}
Run Code Online (Sandbox Code Playgroud)
编辑:
尝试了下面的内容,它可以抛出一个整数,但是当我使用一个类作为例外时却不行:
class X
{
public:
X(){};
~X(){};
};
void Helper()
{
throw(X());
}
void base()
{
__try
{
std::cout << "entering …Run Code Online (Sandbox Code Playgroud) 我正在编写一个小型实用程序(VC 2010,无 clr),它使用第 3 方库执行一项简单的任务(光栅化)。稍后的实用程序将被更大的应用程序使用。有时,该实用程序会因第 3 方库中的某些堆损坏而崩溃。没关系,但 Windows (Vista/2008) 显示众所周知的对话框“程序已停止工作...关闭/调试程序”。这不适合我的情况(服务器端)。实用程序应该静默地崩溃/终止,没有任何可见的影响。
为此,我为未处理的异常安装了 SEH (SetUnhandledExceptionFilter)。对于 AV ( *(PDWORD)0 = 0 ) 等异常,可以完美调用该处理程序,但由于某种原因,在堆损坏的情况下不会调用该处理程序。卸载第 3 方库 dll 之一的 dllmain 时发生损坏。
有几个问题。谁能解释为什么不调用处理程序?还有其他方法可以阻止该对话框吗?
我需要使用当前翻译手动翻译结构化异常.
我如何"获得"某人设定的价值_set_se_translator?