堆栈展开的原因失败

时间:2009-03-05 19:28:29

标签: c++ winapi mfc

我正在调试应用程序并遇到以下代码:

int Func()
{

 try 
 {

   CSingleLock aLock(&m_CriticalSection, TRUE);
   {
     //user code
   }
 }
 catch(...)
 {
     //exception handling
 }
 return -1;

}

m_CriticalSection是CCricialSection。

我发现用户代码抛出异常,导致m_CriticalSection根本没有释放。这意味着由于某些原因,堆栈已损坏,因此展开失败。

我的问题是: 1)在什么不同的情况下,堆栈展开会失败?

2)可以抛出异常的不同可能性,使堆栈展开失败。

3)我可以通过将CSingleLock放在try块之外来解决这个问题吗?

谢谢,

4 个答案:

答案 0 :(得分:2)

您是否收到异常程序终止?

我相信你的CCriticalSection对象将被释放CSingleLock的析构函数。析构函数将始终被调用,因为它是堆栈中的对象。当用户代码抛出时,函数中throw和catch之间的所有堆栈都将被展开。

但是,在此期间,您的用户代码中的某些其他对象甚至CSingleLock析构函数可能会抛出另一个异常。在这种情况下,m_CriticalSection对象将无法正常释放,并且std::terminate被调用并且您的程序将死亡。

以下是一些示例。注意:我使用std::terminate处理函数来通知我状态。您还可以使用std::uncaught_exception查看是否存在未捕获的异常。这个here上有一个很好的讨论和示例代码。

struct S {
    S() { std::cout << __FUNCTION__ << std::endl; }
    ~S() { throw __FUNCTION__; std::cout << __FUNCTION__ << std::endl;  }
};

void func() {
    try {
        S s;
        {
            throw 42;
        }
    } catch(int e) {            
         std::cout << "Exception: " << e << std::endl; 
    }
}

void rip() {
    std::cout << " help me, O mighty Lord!\n"; // pray
}

int main() {
    std::set_terminate(rip);
    try {
        func();
    }
    catch(char *se) {
        std::cout << "Exception: " << se << std::endl;
    }
}

为了清晰起见,请阅读this常见问题解答。

  

我可以通过将CSingleLock放在try块之外来解决这个问题吗?

很难说没有看看堆栈和错误/崩溃。你为什么不试一试。它还可能通过隐藏真正的问题来引入一个微妙的错误。

答案 1 :(得分:0)

首先让我说我不知道​​CSingleLock和CCriticalSection做了什么。

我所知道的是,“用户代码”部分中抛出的异常应该展开堆栈并销毁在try {}块中创建的所有变量。

在我看来,我希望你的aLock变量被异常破坏,但不会被m_CriticalSection破坏。您正在将指向m_CriticalSection的指针传递给aLock变量,但m_CriticalSection对象已存在,并且已在其他位置创建。

答案 2 :(得分:0)

  • 你确定你的m_CriticalSection的生命周期比CSingleLock更长吗?
  • 也许有人腐败你的筹码?
  •   
        

    3)我可以通过将CSingleLock放在try块之外来解决这个问题吗?

      

    在这种情况下 - 是的。但请记住,将大块放在互斥锁中对性能来说并不是一件好事。

  • 顺便说一下,捕捉(......)一般不是好习惯。在Win32中它(catch(...))也捕获SEH异常,而不仅仅是c ++异常。也许你在这个函数中有核心并用catch(...)来捕获它。

答案 3 :(得分:0)

我的问题是:
1)在什么不同的情况下,堆栈展开会失败?

2)可以抛出异常的不同可能性,使堆栈展开失败。

  • 从throw表达式的构造函数抛出的异常
  • 异常传播时从析构函数抛出异常。
  • 从未捕获的异常抛出(如果实际上解除了堆栈,则实现了实现)。
  • 抛出的异常未在异常规范中指定。
  • C ABI抛出异常。
  • 在未捕获的线程内抛出异常(实现定义会发生什么)

3)我可以通过将CSingleLock放在try块之外来解决这个问题吗?

没有。所有这些导致应用程序终止而不进一步展开堆栈。