堆栈展开失败的原因
Posted
技术标签:
【中文标题】堆栈展开失败的原因【英文标题】:Reasons for stack unwinding fail 【发布时间】:2009-03-05 19:28:29 【问题描述】:我在调试一个应用程序时遇到了以下代码:
int Func()
try
CSingleLock aLock(&m_CriticalSection, TRUE);
//user code
catch(...)
//exception handling
return -1;
m_CriticalSection 是 CCrialSection。
我发现用户代码抛出了一个异常,使得 m_CriticalSection 根本没有被释放。这意味着由于某些原因堆栈已损坏,因此展开失败。
我的问题是: 1) 在哪些不同情况下堆栈展开可能会失败?
2) 有哪些不同的异常可能引发堆栈展开失败。
3) 我可以通过将 CSingleLock 放在 try 块之外来解决这个问题吗?
谢谢,
【问题讨论】:
如果你提到抛出了什么样的异常,如果它实际上在 catch(...) 处被捕获,将会有所帮助。 为什么不在用户代码周围放置 try ... catch 块呢? 【参考方案1】:您是否遇到程序异常终止?
我相信你的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 块之外来解决这个问题吗?
如果不查看堆栈和错误/崩溃就很难说。你为什么不试一试。它还可能通过隐藏真正的问题来引入一个微妙的错误。
【讨论】:
【参考方案2】:首先让我说我不知道 CSingleLock 和 CCriticalSection 是做什么的。
我所知道的是,在您的“用户代码”部分中引发的异常应该展开堆栈并销毁在 try 块中创建的所有变量。
在我看来,我希望您的 aLock 变量会被异常破坏,而不是 m_CriticalSection。您正在将指向 m_CriticalSection 的指针传递给 aLock 变量,但 m_CriticalSection 对象已经存在,并且是在其他地方创建的。
【讨论】:
【参考方案3】: 您确定 m_CriticalSection 的生命周期比 CSingleLock 长吗? 可能有人损坏了您的堆栈?3) 我可以通过将 CSingleLock 放在 try 块之外来解决这个问题吗?
在这种情况下 - 是的。但是请记住,将大块放入互斥锁中对性能不利。
顺便说一句,catch(...) 通常不是好习惯。在 Win32 中,它 (catch(...)) 也捕获 SEH 异常,而不仅仅是 c++ 异常。也许你在这个函数中有核心并用 catch(...) 捕获它。
【讨论】:
VC++ catch (...) 自 VC++2005 以来没有捕获 SEH 异常。 好消息和不错的补充:)【参考方案4】:我的问题是: 1) 在哪些不同情况下堆栈展开可能会失败?
如果 exit() terminate() abort() 或 unexpected() 被调用。
除了直接调用之外,哪些情况可能发生: 引发未处理的异常。 (此处不适用) throw an exception from a destructor while another exception is popogating2) 有哪些不同的异常可能引发堆栈展开失败。
throw 表达式的构造函数抛出异常 异常传播时析构函数抛出异常。 抛出的异常从未被捕获(如果这实际上展开堆栈,则实现定义)。 抛出的异常未在异常规范中指定。 跨 C ABI 引发异常。 在未捕获的线程内抛出异常(实现定义了发生的情况)3) 我可以通过将 CSingleLock 放在 try 块之外来解决这个问题吗?
没有。以上所有情况都会导致应用程序终止而无需进一步展开堆栈。
【讨论】:
以上是关于堆栈展开失败的原因的主要内容,如果未能解决你的问题,请参考以下文章