__finally应该在EXCEPTION_CONTINUE_SEARCH之后运行
Is __finally supposed to run after EXCEPTION_CONTINUE_SEARCH?
在下面的代码中,函数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 %dn", cont);
}
}
__except (!cont? EXCEPTION_CONTINUE_SEARCH: EXCEPTION_EXECUTE_HANDLER)
{
printf("except %dn", cont);
}
}
__finally
{
printf("outer finally %dn", cont);
}
}
int main()
{
__try
{
foo(1);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("mainn");
}
return 0;
}
这里的预期输出应该是
inner finally 0
outer finally 0
inner finally 1
except 1
outer finally 1
然而,outer finally 0
在实际输出中明显缺失。这是bug还是我忽略了什么细节?
为完整起见,发生在VS2015中,为x64编译。令人惊讶的是,它没有发生在x86上,这让我相信这真的是一个bug。
存在,更简单的例子(我们可以删除内部try/finally
块:
void foo(int cont)
{
__try
{
__try
{
if (!cont) *(int *)0 = 0;
foo(cont - 1);
}
__except (cont? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
printf("except %dn", cont);
}
}
__finally
{
printf("finally %dn", cont);
}
}
与输出except 1
finally 1
所以finally 0
块没有执行。但在非递归情况下-没有bug:
__try
{
foo(0);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("exceptn");
}
输出:finally 0
except
这是next函数
中的错误EXCEPTION_DISPOSITION
__C_specific_handler (
_In_ PEXCEPTION_RECORD ExceptionRecord,
_In_ PVOID EstablisherFrame,
_Inout_ PCONTEXT ContextRecord,
_Inout_ PDISPATCHER_CONTEXT DispatcherContext
);
这个函数的旧实现,这里有bug:
//
// try/except - exception filter (JumpTarget != 0).
// After the exception filter is called, the exception
// handler clause is executed by the call to unwind
// above. Having reached this point in the scan of the
// scope tables, any other termination handlers will
// be outside the scope of the try/except.
//
if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) { // bug
break;
}
如果我们安装了最新的VC编译器/库,搜索chandler.c
(在我的安装中位于VCcrtsrcamd64chandler.c
)
和在文件中现在可以查看下一个代码:
if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget
// Terminate only when we are at the Target frame;
// otherwise, continue search for outer finally:
&& IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)
) {
break;
}
所以添加了额外的条件IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)
来修复这个错误
__C_specific_handler
在不同的crt库中实现(在某些情况下使用静态链接,在某些情况下将从vcruntime*.dll
或msvcrt.dll
导入(被转发到ntdll.dll
))。ntdll.dll
也导出了这个函数-但是在最新的win10版本(14393)中,它仍然没有修复
相关文章:
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 在类定义之后定义一个私有方法
- 在循环C++中指定字符串之后,不会打印该字符串
- C++宏忽略之后的内容
- 要与"if constexpr"一起使用的编译时消息(在预处理器之后)
- strncpy之后的char数组的错误行为
- 计算十进制 c++ 之后的数字
- "x += x--"之后的 x 是什么?
- 类的前向声明之后的类成员函数定义,在类声明之前
- 为什么将双精度转换为 int 似乎在第 16 位数字之后将其四舍五入?
- execlp() 在 fork() 之后无法正常工作
- QTableview Search
- LeetCode 1011.Binary Search,C++和Python的想法相同,但输出不同
- 我认为我的代码很好,但它在 cin a 之后停止并且没有进一步?
- 如何在MISRA C++之后实施CRTP
- 在 OpenCV 的 namedWindow 之前或之后初始化 Tesseract
- 检测到堆损坏:在正常块 c++ 动态 2D 数组之后
- C++ 如果在 if 为 true 之后运行,为什么还会这样做
- 在 fork() 之后,我在我的程序中不断得到相同的 pid
- OpenSSL C API:如何在程序exec()之后恢复TLS连接?