【问题标题】:intermixing c++ exception handling and SEH (windows)混合 C++ 异常处理和 SEH (windows)
【发布时间】:2011-07-15 14:52:54
【问题描述】:

我有一个函数,我调用getaddrinfo() 来获取一个sockaddr*,它的目标内存是由系统分配的。 很多人都知道,您需要调用freeaddrinfo() 来释放由getaddrinfo() 分配的内存。

现在,在我的函数中,有几个地方我可能会抛出异常,因为某些函数失败了。 我的第一个解决方案是将freeaddrinfo() 合并到每个 if 块中。 但这对我来说确实很难看,因为无论如何我都必须在函数返回之前调用它,所以我想出了 SEH 的 try-finally...

但我遇到的问题是,不允许将 throw-statements 编码到 __try-block 中

然后,我在 msdn 上阅读并尝试将 throw 语句交换到从 __try-block 中调用的辅助函数中……瞧,编译器不再抱怨了……

这是为什么呢?这安全吗?这对我来说没有意义:/

代码:

void function()
{
    //...
    addrinfo* pFinal;
    __try
    {
        getaddrinfo(..., &pFinal);

        //if(DoSomething1() == FAILED)
        //  throw(exception);           //error C2712: Cannot use __try in functions that require object unwinding

        //but this works
        Helper();


        //...

    }
    __finally
    {
        freeaddrinfo();
    }
}


void Helper()
{
    throw(Exception);
}

编辑:

尝试了以下方法,它适用于抛出一个整数,但当我使用一个类作为异常时不起作用:

class X
{
public:
    X(){};
    ~X(){};
};


void Helper()
{
    throw(X());
}


void base()
{
    __try
        {
            std::cout << "entering __try\n";

            Helper();

            std::cout << "leaving __try\n";
        }
        __finally
        {
            std::cout << "in __finally\n";
        }
};


int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        base();
    }
    catch(int& X)
    {
        std::cout << "caught a X" << std::endl;
    }

    std::cin.get();
    return 0;
}

为什么? :/

【问题讨论】:

    标签: c++ exception-handling seh structured-exception


    【解决方案1】:

    您不能混合使用这两种异常类型。在幕后,C++ 异常使用 SEH,而您的 SEH 异常处理程序可能会弄乱异常传播逻辑。因此,C++ 编译器不允许您混合使用它们。

    PS:结构化异常处理几乎总是一个非常糟糕的主意。 Microsoft 在内部禁止使用 SEH,除非在非常有限的情况下。任何使用结构化异常处理的组件都会自动接受强烈代码审查(我们有工具扫描代码以查找其使用情况,以确保不会遗漏任何情况)。

    SEH 的问题是在使用 SEH 时很容易意外引入安全漏洞。

    【讨论】:

    • 我非常尊重你以及你在博客上总是有很好的解释,但我在这里不同意。当使用/EHa 时,Visual C++ 确实混合了这两种类型。 catch (...) 捕获 SEH,__finally 针对 C++ 异常执行。不过,我想知道,SEH 处理程序是被禁止的还是只是使用 SEH 进行流量控制的代码(即它合成了一个 SEH 异常)? .NET 代码处处处理 SEH 异常。
    • 启用 /EHa 具有潜在的安全后果。它还禁用大多数编译器优化,因为编译器必须禁用所有代码流分析(设置 /EHa 时,它告诉编译器 any 指令可能导致异常,而不仅仅是方法调用)。一些合法的 SEH 处理程序是:内核参数探测(SEH 处理程序是强制性的)、C++ 异常处理、.Net 异常处理、RPC 的异常处理程序和一小部分其他处理程序。所有这些案例都经过深入审查。
    • 您是否参考过描述这些安全后果的博客文章或类似文章?
    • 查找一些几年前关于.ani 漏洞的文章,Michael Howard 和 David LeBlanc 已经写过关于它的文章。请记住,这些是潜在安全后果,而不是直接后果。可以正确使用 /EHa。但这非常困难,您必须认真了解自己在做什么。 /EHa 的最大问题是与交换机相关的性能后果(以及与使用 SEH 相关的可靠性后果)。
    【解决方案2】:

    您可以将 addrinfo 包装在一个类中,该类在构造函数中调用 getaddrinfo,在其析构函数中调用 freeaddrinfo

    这样无论是否抛出异常,它都会被释放。

    【讨论】:

      【解决方案3】:
      catch(int& X)
      {
          std::cout << "caught a X" << std::endl;
      }
      

      这不会捕获X,它会捕获int&amp;。由于没有匹配的 catch 块,异常未被捕获,堆栈展开不会发生,__finally 处理程序不会运行。

      您可以将catch (...) 放入您的线程入口点(主线程是main()),以确保发生堆栈展开,尽管有些异常是不可恢复的,但C++ 异常绝不会如此。

      【讨论】:

      • 我想你不明白,或者我写得不够清楚:首先我尝试抛出一个 int,然后用 X ......我可能在手写时混合了第二个代码放在这里,见谅
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      • 1970-01-01
      • 2011-08-08
      相关资源
      最近更新 更多