【问题标题】:Different behaviour observed when using SEH (structured exception handling)使用 SEH(结构化异常处理)时观察到的不同行为
【发布时间】:2013-02-26 10:48:41
【问题描述】:

我正在用 SEH 做一些实验。在我的代码中,我在 __try 子句中编写了导致错误的块,并在 __except() 中编写了一个处理程序。

__try{
Test *pTest = 0;
int k = pTest->GetValue();
cout << "continue after exception" << endl;
}
__except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION,EXCEPTION_EXECUTE_HANDLER)
{
 cout << "caught!!" << endl;
}
cout << "Exception handled" << endl;

__except() 的第二个参数是其中之一 -

EXCEPTION_CONTINUE_SEARCH 无法识别异常。继续在堆栈中搜索处理程序,首先是包含 try-except 语句,然后是具有下一个最高优先级的处理程序。

EXCEPTION_CONTINUE_EXECUTION 异常被识别但被解除。在发生异常的地方继续执行。

EXCEPTION_EXECUTE_HANDLER 识别出异常。通过执行 __except 复合语句将控制权转移到异常处理程序,然后在发生异常的点继续执行。

当我使用 EXCEPTION_CONTINUE_EXECUTION/EXCEPTION_EXECUTE_HANDLER 时,它不会在异常发生点继续执行(可能是我误解了异常发生点的含义)。 当我在调试模式下运行它时,输出是

caught
Exception handled

当我在发布模式下运行它时,输出是

continue after exception
Exception handled

我不明白为什么它的行为不同。请任何人帮忙。

【问题讨论】:

  • 显示 GetValue() 方法的内容
  • 向我们展示Test 的定义,并向我们展示调试和发布选项在 SEH 和 C++ 异常方面有何不同,有一些选项可供选择。或者更好的是向我们展示在发布模式下对__try{} 块的反汇编。它可能有一些更好的线索。
  • 我担心pTest 是一个指向类的指针,它可能不需要为了执行GetValue() 而取消引用,并且编译器认识到,当在发布模式下启用优化时.或者甚至它认为GetValue() 是无用的,并且不会生成任何代码来调用它。编译器也有可能看到取消引用 NULL 指针会导致未定义的行为,并决定在编译时通过修改代码来惩罚你,它完全有权这样做。 gcc 因这样做而臭名昭著。
  • 谢谢阿列克谢。你说的对。由于空指针检查的编译器优化,它实际上并没有引发 exception_access_violation。当我使用 RaiseException() 显式抛出异常时,它开始在调试\发布模式下显示类似的行为。但是 EXCEPTION_EXECUTE_HANDLER 并没有完全按照文档所说的那样做。根据文档,它应该首先在 __except() 之后执行块 {},然后在发生异常时继续执行。
  • 您要么误解了文档,要么做错了什么。 SEH 工作正常。我将上述评论移到我的答案中,因为这是实际的调试与发布问题。

标签: c++ windows exception seh


【解决方案1】:

@Joachim 正确指出了逗号运算符问题。

我认为,__except() 应该是这样的:

__except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
         EXCEPTION_EXECUTE_HANDLER :
         EXCEPTION_CONTINUE_SEARCH)

如果异常是访问冲突,这将使异常处理程序执行。如果不是,异常将传播到最近的外部__try,如果有的话。

我担心pTest 是一个指向类的指针,它可能不需要为了执行GetValue() 而取消引用,并且编译器会识别出在发布模式下启用优化时。或者甚至它认为GetValue() 是无用的,并且不会生成任何代码来调用它。编译器也有可能看到取消引用 NULL 指针会导致未定义的行为,并决定在编译时通过修改代码来惩罚你,它完全有权这样做。例如,gcc 因这样做而臭名昭著。

【讨论】:

  • 我已按照您的建议编辑了代码。但即使捕获的异常是 EXCEPTION_ACCESS_VIOLATION 它也没有显示字符串“caught!!”在发布模式中
【解决方案2】:

表达式

GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION,EXCEPTION_EXECUTE_HANDLER

没有做你期望的事情。它所做的是将GetExceptionCode() 的结果与EXCEPTION_ACCESS_VIOLATION 进行比较,但整个表达式的结果是EXCEPTION_EXECUTE_HANDLER

阅读有关逗号运算符at Wikipedia 的更多信息。

你想做的是,大概:

GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION || GetExceptionCode() == EXCEPTION_EXECUTE_HANDLER

【讨论】:

  • GetExceptionCode() 不返回EXCEPTION_EXECUTE_HANDLER
  • 感谢 Joachim 的回答。但我仍然不知道为什么它在调试/发布模式下表现不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多