【问题标题】:EXCEPTION_CONTINUE_EXECUTION strange behavour异常继续执行奇怪的行为
【发布时间】:2014-11-14 17:42:03
【问题描述】:

我写了代码

void SEHtest(int i) {
  int s = 0;
  __try {
    cout << "code1" << endl;
    int j = 1 / s;
    cout << "code2" << endl;
  } __except((s = 1, i)) {
    cout << "code3" << endl;
  }
  cout << "code4" << endl;
  return;
}
int main() {
  SEHtest(-1);
  return 0;
}

我正在等待输出

code1
code2
code4

但我只有

code1

和无限循环。

为什么会这样?

volatile 键名添加到 s 和 j 并没有修复它。

【问题讨论】:

  • 看看编译器生成的汇编代码。 (1/s) 中的 s 很可能被视为常数零,因为在正常的 C/C++ 控制流中它不可能有任何其他值。
  • 你用的是什么编译器?我使用 C++Builder,你所展示的内容对我来说很好,我看到 code1code2code4 符合预期。
  • @RemyLebeau VC 编译器来自 Visual Studio 2008

标签: c++ winapi seh


【解决方案1】:

导致无限循环的原因是每次恢复执行时都会重新抛出异常。在过滤器中设置s = 1 的值并不重要,因为执行是从导致陷阱的指令恢复的,在这种情况下是除以零。如果您按如下方式重新组织代码,您将看到异常不断被抛出:

int ExceptionFilter(int& s) {
  cout << "exception filter with s = " << s << endl;
  s++;
  return -1; // EXCEPTION_CONTINUE_EXECUTION
}

void SEHtest() {
  int s = 0;
  __try {
    cout << "before exception" << endl;
    int j = 1 / s;
    cout << "after exception" << endl;
  } __except(ExceptionFilter(s)) {
    cout << "exception handler" << endl;
  }
  cout << "after try-catch" << endl;
  return;
}

int main() {
  SEHtest();
  return 0;
}

结果应该是:

before exception
exception filter with s = 0
exception filter with s = 1
exception filter with s = 2
...

异常继续被抛出,因为执行是在除以零的指令上恢复的,而不是在加载 s 值的指令上。步骤是:

1  set a register to 0
2  store that register in s (might be optimized out)
3  enter try block
4  output "before exception"
5  load a register from s
6  divide 1 by register (trigger exception)
7  jump to exception filter
8  in filter increment/change s
9  filter returns -1
10 execution continues on line 6 above
6  divide 1 by register (trigger exception)
7  jump to exception filter
8  in filter increment/change s
9  filter returns -1
10 execution continues on line 6 above
...

我认为您无法从该异常中恢复。

【讨论】:

  • 如果您知道哪个寄存器用于除法,您将能够恢复,并调整该寄存器的值而不是调整s 变量。但这需要您对特定编译器如何为此代码生成机器指令有一些深入的了解。在这个特定的示例中,代码应该只使用EXCEPTION_EXECUTE_HANDLER 来处理异常并继续前进。
【解决方案2】:

如果你想执行最后一部分,试着把整个东西放在另一个里面

__try { 
 < your code>
}
__finally{
    < code that will be executed at end>
}

更多信息请查看herehere

'code 2' 行将不会显示,因为执行被上一行的异常中断。

【讨论】:

  • 是的,我知道 __finally ,但现在我学习 __try ... __except(code)。当 code = 0 或 1 时,我的程序运行良好,但当 code = EXCEPTION_CONTINUE_EXECUTION 时,这很奇怪。实际上,我尝试编写一个有效的代码示例
  • CONTINUE_EXECUTION 假设您已采取措施来修复错误,并且您在 (s=1, i) 中尝试这样做。在这里,我会检查汇编翻译,看看到底发生了什么。您不能假设“s”在程序集级别保留了预期的语义。它可能已经被翻译为寄存器中的值或常量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 2015-03-29
  • 1970-01-01
相关资源
最近更新 更多