【问题标题】:Can I decode a C++ exception from a Windows SEH exception? (And if so, how?)我可以从 Windows SEH 异常中解码 C++ 异常吗? (如果是这样,怎么做?)
【发布时间】:2012-10-20 07:52:19
【问题描述】:

如果出现未处理的 C++ 异常,我想打印:

  1. C++ 异常的消息 (what())
  2. 堆栈跟踪。

为了获取堆栈跟踪,我将SetUnhandledExceptionFilterStackWalker 库结合使用:

struct FooStackWalker : StackWalker
{
    virtual void OnCallstackEntry(CallstackEntryType, CallstackEntry &entry) override
    {
        std::cerr << entry.lineFileName << " (" << entry.lineNumber << "): " << entry.undFullName << std::endl;
    }
};

LONG WINAPI UnhandledExceptionHandler(LPEXCEPTION_POINTERS pointers)
{
    FooStackWalker walker;
    walker.ShowCallstack(::GetCurrentThread(), pointers->ContextRecord);
    ::TerminateProcess(::GetCurrentProcess(), 1);
}


int main()
{
    ::SetUnhandledExceptionFilter(UnhandledExceptionHandler);
}

我已经可以很好地打印堆栈跟踪,但现在很难获得what

有什么方法可以将 SEH 异常解码为 C++ 异常,以便在终止之前调用此成员函数?

【问题讨论】:

  • 你会得到 3 个 ExceptionInformation 词。第二个是指向异常对象的指针。你没有解释它的希望,没有 C++ 中的反射之类的东西。 catch 关键字发出的异常过滤器至关重要。
  • @Hans:如果假设抛出的东西总是源自std::exception(对于许多代码库来说都是如此),它不能被解释吗?一旦你有了std::exception,如果需要,你可以dynamic_cast 到特定的异常类型...
  • 强制转换为 what 异常?那是关键。你可能会得到what
  • @Hans:这是一个void *——不能只是static_caststd::exception*吗?

标签: c++ winapi visual-c++ exception


【解决方案1】:

为什么不使用已经为您提供异常详细信息的 C++ 机制?它不是 SEH 过滤器独有的(尽管它SetUnhandledExceptionFilter 独有的)。您只需要正确嵌套处理程序:

int main()
{
    try {
        return cppexcept_main();
    }
    catch (const std::exception& e)
    {
        //use e.what()
    }
}

int cppexcept_main()
{
    __try {
        return application_main();
    }
    __except(GrabStackTrace(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) {
         /* never reached due to EXCEPTION_CONTINUE_SEARCH */
    }
}

【讨论】:

    【解决方案2】:

    编辑:我误解了你的问题。我不能确定 C++ 异常的答案是什么,但我有理由确定答案是“否”。我不相信有任何方法可以区分由 SEH 引起的未处理异常(例如访问冲突)和未捕获的 C++ 异常,或者任何方法来区分不同类型的 C++ 异常。那匹马已经离开了马厩。

    原答案如下:


    不,因为 SEH 异常没有what。这不是std::exceptionThis MSDN example 表示当您尝试将 SEH 异常作为 C++ 异常捕获时,只能使用省略号 (...) catch 处理程序来捕获它。您可以使用_set_se_translator 定义您自己的函数,将 SEH 异常转换为 C++ 异常,但此时您只是在不同位置从相同信息生成您自己的what(即使那样,我也不知道是否可以从UnhandledExceptionFilter 获得它。

    LPEXCEPTION_POINTERS structure 中有您需要的所有信息。如果发生访问冲突,则pointers-&gt;ExceptionRecord-&gt;ExceptionCode 将是EXCEPTION_ACCESS_VIOLATION (0xC0000005)。如果发生这种情况,那么您可以检查 NumberParametersExceptionInformation 变量,以确定它是读取还是写入冲突以及尝试访问的地址。

    【讨论】:

    • 不,我想反其道而行之——将 SEH 异常转换为 C++ 异常。当然,如果 SEH 异常 not 实际上是 C++ 异常(MSVC++ 似乎使用异常代码 0xE06D7363),那么无论转换完成都会失败或以其他方式告诉我下地狱(其中情况下,我无论如何都不想尝试打印堆栈跟踪——不应该尝试在访问冲突或其他情况后继续运行)。
    • (应该注意的是,我很乐意在普通的 C++ catch 中做这种事情,但此时堆栈已展开,因此打印投掷点的堆栈是不可能)
    • 该信息用于调试/诊断目的。它不是你的程序应该依赖的东西,因为它可以随时改变。
    • @Raymond:我知道——这就是我问这个问题的原因——看看是否有支持的方法。 (除非我无论如何都要重新编译和更改 CRT,否则它不会改变——毕竟,所有解释异常的位都必须以某种方式嵌入到普通的 C++ catch 站点中)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 2021-06-30
    • 1970-01-01
    • 2017-11-14
    • 2017-09-26
    • 2022-11-28
    • 2021-11-08
    相关资源
    最近更新 更多