【问题标题】:Consistant Way to Catch C++ Library Crashes捕获 C++ 库崩溃的一致方法
【发布时间】:2014-09-28 13:04:27
【问题描述】:

我环顾了不同的网站,除了那些似乎不起作用的问题之外,找不到任何关于这个问题的答案。正如标题所说,我正试图找到一种方法来捕捉我正在处理的库是否崩溃。我有一个 Root 类,其中包含我在库中拥有的许多管理器样式类的实例,并且它在其析构函数中释放实例。当然,管理人员要对相当多的数据负责,因此如果处理不当,可能会出现相当不可接受甚至危险的内存泄漏。

我知道,当程序崩溃时,操作系统会为程序释放堆栈空间,但这不包括调用已分配对象的析构函数。它也不包括删除执行期间分配的任何堆,这是我处理库中大量内存的方式,这又回到了广泛的内存泄漏问题。

我在其他网站上遇到的很多答案只是说要向atexit() 注册一个函数,但如果应用程序崩溃,该函数将不起作用。而且,如上所述,由于崩溃不调用析构函数,因此无法创建一个全局单例来在其被销毁时关闭所有内容,这是我如何处理这个问题的最初想法。我的另一个想法是希望库的最终用户能够采取适当的预防措施以避免崩溃(通过广泛使用异常抛出),但我觉得这违背了良好编码库的想法,坦率地说我认为它要求最终用户处理这个问题。

所以我想我的 TL;DR 问题是这样的:有没有办法通过标准 C++ 函数或通过某种管理器类来捕捉库何时崩溃并适当地处理它?

编辑:另外,我真的更喜欢跨平台的方式来处理这个问题。我的代码库大量使用 C++11 的特性,因此我以编程方式将可用编译器限制为最新版本的 GCC 和 Clang。

不仅如此,我还有几个类,比如 Logger,它们会关闭它们到文件系统的流并打印出一些关于退出状态的消息。我还有一个内存跟踪器,它可以将任何可能的内存泄漏报告给文件,但仅限于它的析构函数中。

【问题讨论】:

  • 在哪个操作系统上?使用哪些编译器和编译标志?如果在 Linux 上,在哪个发行版上?一些 Linux 发行版具有其系统库的调试变体。
  • "它也不包括删除任何在执行期间分配的堆" 一般是这样。
  • 处理代码崩溃的最佳方法是修复导致崩溃的错误。 其他任何事情都只是一个 hack。
  • @BasileStarynkevitch,当我要求标准 C++ 函数时,我的意思是它是跨平台的,但这是我的假设,抱歉。我更新了问题。
  • 如果您的代码中存在导致这些崩溃的错误,您的首要任务应该是修复该错误。您甚至不应该考虑编写更多代码来解决该错误。

标签: c++ exception memory crash atexit


【解决方案1】:

“有没有办法通过标准 C++ 函数或某种管理器类来捕捉库何时崩溃并适当地处理它?”

我能想到的最简洁的回答是:

坚持C++ Standard Error handling的类和类别。


当您要求atexit() 时,standard reference 中也明确定义了该行为。

注意还有更多的处理程序机制,例如 std::terminate_handler,允许您以一种可移植且符合标准的方式处理一些异常中止情况。

最后但并非最不重要的一点是,可能需要安装某些(特定于操作系统的)signal handlers,以赶上由于堆栈溢出或类似原因引发的所谓的segmentation fault (SIGSEV) 之类的错误。

【讨论】:

  • 对于 C++ 异常没有一致的 ABI。当您不控制双方的工具链时,让它们跨模块边界传播是自找麻烦。
  • std::terminate_handler 看起来像我可能正在寻找的东西。我现在去看看,谢谢。
  • 因为我基本上将成为我的库的主要最终用户(在可预见的将来,如果发生变化,那么我的库将会改变),我将为库和库使用相同的编译器我的项目。
  • 经过大量测试后,std::terminate_handlerstd::set_terminate 正是我想要的。我只是用set_terminate 注册了一个全局函数,它用根单例调用正确的函数。非常感谢!
【解决方案2】:

所以我想我的 TL;DR 问题是:有没有办法,或者通过 标准 C++ 函数,或通过某种管理器类,来捕捉 当一个库崩溃并适当地处理它?

在存在诸如结构化异常处理和各种分段错误和总线错误(标准对这些事情没有任何说明)之类的情况下,防止库崩溃导致用户应用程序崩溃的唯一方法是提供库通过客户端程序执行的二进制文件,并让客户端负责监视客户端进程是否死亡。

如果您希望将库直接链接到用户的应用程序您无能为力绝对确保库中的错误不会导致用户的应用程序崩溃。这就是单元、子系统和系统测试套件的用途。请记住,如果您的库使应用程序崩溃,我所知道的几乎每个操作系统都会回收它分配的所有资源,因此您不需要全局单例来释放堆内存:操作系统会自动在崩溃点。

最后请注意,如果库崩溃,则该进程已经处于错误状态。您无法在此时安全地执行任何代码(例如,如果进程堆损坏怎么办),包括写入日志消息或转储内存泄漏状态。

【讨论】:

    猜你喜欢
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 2018-07-11
    • 1970-01-01
    相关资源
    最近更新 更多