2

我在一个用 MSVC 2005 编译的大型多线程应用程序中遇到了一个神秘的崩溃问题。客户端日常使用该应用程序,任何崩溃都会对它们造成重大破坏。我需要一个解决方法。如果我可以将问题隔离到一个功能,并按照以下方式做一些事情:

__try
{
  FunctionWhichMayCauseCrash();
}
__except ( [filter expression] )
{
  Recover();  // magic - this allows us to prevent crash and continue
}

那么这在理论上对我来说似乎是个好主意。在实践中,有些人(例如这里的拉里奥斯特曼和这里的道格哈里森认为这可能是一个非常糟糕的主意 - 不应该用驳船杆接触 SEH。

现实检查:我的程序正在生成结构化异常,我不知道在哪里。我正在使用Hans Dietrich 的 XCrashReport 的部分内容——它本身就在使用__try/__except——试图深入了解这些异常的来源,但到目前为止还没有运气。似乎某些共享资源没有被正确锁定,因此一个线程正在从另一个线程下面拉扯地毯,从而在或多或少随机的地方导致访问冲突。

是否有一个务实的中间立场,这种机制可以防止我的程序崩溃?我是否应该担心我选择的崩溃恢复机制使用了其他人警惕的东西?

澄清:由于程序崩溃造成的极端破坏,我寻求一种防止崩溃的解决方法,而不是最终的永久解决方案。我无意用__try/__except地毯下的问题扫除。我只是想了解它是否像某些人所说的那样危险,还是应该谨慎使用的合法工具。有些人说话的方式,在我尝试使用定义编译代码的那一刻/EHa,我的计算机可能会起火。我很想知道人们是否会说使用/EHa,_set_se_translatortry/catch(...)更好,或者等同于同一件事,或者两者是否真的是坏主意。

澄清 2:我不需要帮助调试 :-) 相反,我需要帮助理解混合 SEH 和 C++ 的含义,这似乎在这个论坛和其他论坛上产生的热量多于光。我的低声誉表明论坛的新奇,而不是 C++ 的新奇。我故意将我的应用程序抽象出来,以鼓励人们关注将 SEH 构造引入 C++ 程序的含义。好吧,那是行不通的 :-) 碰巧的是,我的应用程序有一个对象管道,如果我检测到它们中的损坏,我可以很容易地转储其中的任何一个。所以我的神奇Recover()功能并不像听起来那么神奇,而且很有可能腐败会限制在堆的一小部分。所以......回到问题:使用__try/__except可取吗?

4

2 回答 2

1

做。不是。做。这个。

我完全同意 Doug Harrison 在您的链接中的评论 - 使用 SEH 非常危险,因为您最终会在代码中隐藏(可能很严重)错误。

如果您对异常可能发生的位置有一个非常具体的想法,暂时将 SEH 块添加到您的代码中可能有助于跟踪它,但我怀疑情况并非如此 - 您的堆栈已损坏。

我建议不要将 SEH 块添加到程序的大部分中,因为它所做的只是以隐藏这些问题为代价使程序免于崩溃。您将隐藏崩溃,但您不会知道应用程序的状态是否已损坏(以及损坏程度)。如果损坏的数据保存在数据库中,您的客户将不会有太大帮助。

这是另一个SEH 问题,我认为它可能对您有用。

与其尝试使用 SEH,不如使用您的时间和精力来尝试解决问题。使用 WinDbg(如果您从崩溃中获得了小型转储)可以加快速度。如果你不熟悉它,这里有一个教程

我不是 SEH 专家,因此其他人可能会给您更详细的建议,但我只会尝试将 SEH 解决方案作为非常非常最后的手段,因为可能会出现更难发现的问题。

于 2013-02-05T03:19:19.763 回答
0

问题是,当 SEH 被调用时,您的应用程序已经完全瘫痪了。 任何可以访问(不仅仅是使用)的 RAMFunctionWhichMayCauseCrash都必须被假定为已销毁,包括 CRT 在用户空间中完成的所有操作。真正要做的最好的事情是记录所有你能得到的东西——以一种完全依赖于内核函数的方式——中止整个进程,关闭它的所有 IPC 和共享句柄,并在它自己的中启动一个闪亮的新进程地址空间。

如果您真的想要在这种情况下进行细粒度的崩溃恢复,您可能需要重新构建一系列管道连接的进程或类似的进程。

于 2013-02-05T03:20:27.480 回答