每个C++开发人员都应该知道哪些关于结构化异常的重要观点?
如果我在非托管C++,Visual Studio 2008或更高版本中创建一个新项目,我想要使用哪种异常处理模型?
我知道/ EHa选项导致代码效率降低,并且还会捕获SEH异常,对吧?
所以我一直在转向那个选项,并且通常使用/ EHsc,因此我只捕获实际抛出的C++异常,而不是捕获访问冲突和其他结构化的execse,在catch(...)处理程序中.如果我的代码中存在访问冲突,我不希望它被catch(...){}掩盖.
我和其他想要捕获(...){}的人一起编写代码,如果存在访问冲突,他们甚至希望它这样做,这对我来说似乎是一个非常糟糕的主意.如果由于编码错误而导致错误,您不想将手指伸入耳中并大声说"La la la la la!" 这样你就不必让程序崩溃了?事实上,如果代码由于编码错误现在处于错误状态,您真的希望代码继续吗?
所以我的一般想法是/ EHa创建更大/更慢的代码并且它允许程序员逃避编写代码,如果存在致命错误,它将继续以未定义状态运行.
顺便说一下,我说的是应用程序和服务代码,这是我们大部分时间写的.不是低级设备驱动程序或类似的东西.
请考虑一下你的想法.
我试图设置SEH
不使用try except
(这是为了我个人的知识,以更好地了解SEH如何工作)
以下代码不起作用
type
TSeh = packed record
OldSeh:DWORD;
NewSeh:DWORD;
end;
procedure test;
begin
WriteLn('Hello from seh');
end;
var
eu:TSeh;
old_seh:DWORD;
begin
asm
mov eax,fs:[0]
mov old_seh,eax
end;
eu.OldSeh := old_seh;
eu.NewSeh := DWORD(@test);
asm
mov eax,offset eu
mov fs:[0],eax
ret //This will cause an exception because jumps on an invalid memory address
end;
end.
Run Code Online (Sandbox Code Playgroud)
但这样做
procedure test;
begin
WriteLn('Hello from seh');
end;
begin
asm
push offset test
push fs:[0]
mov fs:[0],esp
ret //This will cause …
Run Code Online (Sandbox Code Playgroud) 我不情愿地再次处理Win32结构化异常.我正在尝试生成描述异常的字符串.大多数都很简单,但我坚持一些基本的东西:如何将异常代码(结果GetExceptionCode()
或者ExceptionCode
成员EXCEPTION_RECORD
)转换为描述异常的字符串?
我正在寻找能够将例如0xC0000005转换为"访问冲突"的内容.这只是一个电话FormatMessage()
吗?
对于Windows 8应用程序认证,有(以及其他)这些要求:
/SafeSEH
标志编译您的应用程序,以确保安全的异常处理/NXCOMPAT
标志编译您的应用程序以防止数据执行/DYNAMICBASE
地址空间布局随机化(ASLR)标志进行编译我无法在C++ Builder XE中找到如何启用其中任何一个.
对于/NXCOMPAT
和/DYNAMICBASE
,可以使用editbin.exe
VS或peflags.exe
Cygwin.虽然我对可能的副作用更有信心,但如果有本地方式来启用这些副作用.
无论如何,我完全不知所措/SafeSEH
.
在后台线程中,我的应用程序会定期检查网络文件夹(UNC路径)以获取应用程序更新.它会读出文件的汇编版本,如下所示:
Try
newVers = System.Reflection.AssemblyName.GetAssemblyName("\\server\app.exe").Version
Catch ex As Exception
' ignore
End Try
Run Code Online (Sandbox Code Playgroud)
这段代码经常被执行,到目前为止我总共在多个客户站点猜测超过100.000次没有问题.
有时GetAssemblyName
会引发a FileNotFoundException
,例如万一网络文件夹无法访问(可能发生并且必须处理).这个异常被Catch
下面的块捕获,一切正常.
然而,在三个报告的案例中,GetAssemblyName
电话提出了一个SEHException
.奇怪的是,这个异常并没有被Catch
下面的块捕获,而是被我的全局未处理异常处理程序(System.AppDomain.CurrentDomain.UnhandledException
)捕获.结果,应用程序崩溃.
这是异常细节(遗憾的是,我的错误处理例程没有记录异常的ErrorCode
和CanResume
字段):
Caught exception: System.Runtime.InteropServices.SEHException
Message: External component has thrown an exception.
Source: mscorlib
TargetSite: System.Reflection.AssemblyName nGetFileInformation(System.String)
StackTrace:
at System.Reflection.AssemblyName.nGetFileInformation(String s)
at System.Reflection.AssemblyName.GetAssemblyName(String assemblyFile)
at SyncThread.Run()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart() …
Run Code Online (Sandbox Code Playgroud) 我一直在尝试使用程序化数据断点,CBreakpoint
例如,通过使用SetThreadContext
直接设置调试寄存器.我能找到的大多数引用都表明Visual Studio在遇到数据断点时仍然会中断,即使它没有设置数据断点本身.但是,这似乎不是Visual Studio 2010的工作方式.
我正处于这样一种情况:当程序未被调试时,我的数据断点工作正常(它崩溃STATUS_SINGLE_STEP
,这是数据断点引发的异常).如果我使用WinDbg进行调试,它也会正常中断.但是当在Visual Studio 2010下调试它时,它似乎只是保持卡车并忽略断点.有没有人在Windows 7下使用Visual Studio 2010下的编程设置数据断点有任何经验?有什么东西我需要做才能打破它们吗?(我尝试添加STATUS_SINGLE_STEP
"第一次机会异常"列表,但行为没有变化.)
或者,我可能正在做什么来吞下STATUS_SINGLE_STEP
调试器中的异常?在调试器可以看到之前,结构化异常处理程序是否会使用该异常?这是一个x86_64程序的事实影响了吗?我需要在Visual Studio 2010设置中做一些舞蹈吗?
我目前正在开发一个单元测试框架,用户可以在其中创建测试用例并在框架中注册.
我还想确保如果任何用户测试代码导致崩溃,它不应该崩溃整个框架但应该被标记为失败.为了使这项工作,我编写了以下代码,以便我可以在沙盒功能中运行用户代码
bool SandBox(void *(*fn)(void *),void *arg, void *rc)
{
#ifdef WIN32
__try
{
if (rc)
rc = fn(arg);
else
fn(arg);
return true;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
#else
#endif
}
Run Code Online (Sandbox Code Playgroud)
这在Windows上运行得很好,但我希望我的框架是可移植的,为了这样,我想确保posix环境的类似功能.
我知道C信号处理程序可以拦截OS信号,但是将信号处理机制转换为SEH框架有一些我无法解决的挑战
另一种可能性是我在使用自己的信号处理程序在一个单独的线程上运行用户测试代码并从信号处理程序终止线程,但又不确定这是否可行.
所以在我超越之前,如果他们意识到解决这个问题/情况的更好解决方案,我希望得到社区的帮助.
这两个节点控制台和QT5的V8为基础QJSEngine
可以通过以下代码崩溃:
a = []; for (;;) { a.push("hello"); }
Run Code Online (Sandbox Code Playgroud)
崩溃前节点的输出:
FATAL ERROR: JS Allocation failed - process out of memory
Run Code Online (Sandbox Code Playgroud)
QJSEngine
崩溃前的输出:
#
# Fatal error in JS
# Allocation failed - process out of memory
#
Run Code Online (Sandbox Code Playgroud)
如果我QJSEngine
在调试器下运行我的测试应用程序(见下文),它会v8::internal::OS::DebugBreak
在V8代码中显示一个调用.如果我换行代码调用QJSEngine::evaluate
到__try-__except
(SEH),然后应用程序不会崩溃,但这种方法是针对Windows的.
问题:有没有v8::internal::OS::DebugBreak
办法在节点和Qt应用程序中以独立于平台的方式处理?
=== QJSEngine测试代码===
开发环境:QtCreator,Qt5和Windows SDK 7.1,在Windows XP SP3上
QJSEngineTest.pro:
TEMPLATE = app
QT -= gui
QT += core qml
CONFIG -= app_bundle
CONFIG += console …
Run Code Online (Sandbox Code Playgroud) 在下面的代码中,函数以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)