gpt4 book ai didi

c++ - __finally 应该在 EXCEPTION_CONTINUE_SEARCH 之后运行吗?

转载 作者:可可西里 更新时间:2023-11-01 18:39:57 27 4
gpt4 key购买 nike

在下面的代码中,函数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;
}

这里的预期输出应该是

inner finally 0
outer finally 0
inner finally 1
except 1
outer finally 1

但是,outer finally 0 在实际输出中明显缺失。这是错误还是我忽略了一些细节?

为了完整起见,发生在 VS2015 上,针对 x64 进行编译。令人惊讶的是,它并没有发生在 x86 上,这让我相信这确实是一个错误。

最佳答案

存在且更简单的示例(我们可以删除内部 try/finally block :

void foo(int cont)
{
__try
{
__try
{
if (!cont) *(int *)0 = 0;
foo(cont - 1);
}
__except (cont? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
printf("except %d\n", cont);
}
}
__finally
{
printf("finally %d\n", cont);
}
}

有输出

except 1
finally 1

所以 finally 0 block 没有执行。但在非递归情况下 - 没有错误:

__try
{
foo(0);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("except\n");
}

输出:

finally 0
except

这是下一个函数的错误

EXCEPTION_DISPOSITION
__C_specific_handler (
_In_ PEXCEPTION_RECORD ExceptionRecord,
_In_ PVOID EstablisherFrame,
_Inout_ PCONTEXT ContextRecord,
_Inout_ PDISPATCHER_CONTEXT DispatcherContext
);

此函数的旧实现有错误 here :

                    //
// 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(在我的安装中位于 \VC\crt\src\amd64\chandler.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*.dllmsvcrt.dll< 导入(转发到 ntdll.dll)。还 ntdll.dll 导出此函数 - 但是在最新的 win10 builds(14393) 中它仍然没有修复

关于c++ - __finally 应该在 EXCEPTION_CONTINUE_SEARCH 之后运行吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32805892/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com