【问题标题】:Is there any way of preventing application from crashing when heap is corrupted? - C programing language当堆损坏时,有什么方法可以防止应用程序崩溃? - C 编程语言
【发布时间】:2011-04-18 23:40:31
【问题描述】:

有时在执行中尝试释放内存时,我会在 VS2010 中收到此错误消息:

Windows 已在 [APPNAME].exe 中触发断点。

这可能是由于堆损坏,这表明 [APPNAME].exe 或其已加载的任何 DLL 中存在错误。

这也可能是由于用户在 [APPNAME].exe 获得焦点时按 F12。

输出窗口可能有更多的诊断信息。

Wich 表示堆或指针有问题。

我的问题是,当我的应用构建为发行版时,此错误会使我的应用崩溃。

此外,这只是更大应用程序的一个模块,当它崩溃时,一切都会崩溃。

我希望能够处理这个错误。

来自“免费”的 msdn:

如果在释放内存时发生错误,则使用来自操作系统的有关故障性质的信息设置 errno。有关详细信息,请参阅 errno、_doserrno、_sys_errlist 和 _sys_nerr。

有一个errno_t _get_errno( int * pValue ); 函数返回错误代码。

如果我在上面显示的错误消息上按继续,此函数将返回错误代码。 使用此代码,我可以检测错误、创建调用堆栈并软退出我的函数。

是否有任何编译器开关或其他东西可以防止应用程序在免费失败时崩溃并允许我以自己的方式退出它??

【问题讨论】:

  • 您打算如何退出“我的方式”?如果堆损坏,任何涉及分配或释放内存的进一步操作(即几乎任何有趣的事情)也很可能会崩溃。
  • 我是否可以建议您在修复堆损坏错误之前不要将其编译为发行版?这些错误非常令人讨厌,以至于它们让您认为您的应用程序的其他部分已经脱离了真正的来源。

标签: c memory heap-memory free


【解决方案1】:

如果堆损坏,所有的赌注都没有。内存分配可能会失败(除非它们在堆栈上),它们可能会返回指向古怪区域的指针,甚至是堆上现有的东西可能被破坏得面目全非。在这种情况下,您实际上最好不要崩溃,因为您采取的任何操作(甚至试图优雅地退出)都可能使事情变得更糟。

找到在堆上破坏东西的代码,然后修复或删除它。

【讨论】:

    【解决方案2】:

    理论上,您会尝试使用 SEH 防止您的应用崩溃。 AFAIK“调试断点”是一种可以处理的 SEH 异常。

    __try {
        // do something here
    } __except(EXCEPTION_EXECUTE_HANDLER) {
    }
    

    上面的__try/__except 块将捕获所有异常(C++ 和 SEH)。

    但是

    我相信你不应该这样做。堆损坏以及任何其他无效的内存访问 - 是一个错误一旦发生 - 损坏通常是不可恢复。您可以防止崩溃(希望如此),但您不能保证您的程序会执行它应该执行的操作。从现在开始,它可能会在其他任何地方崩溃。

    我建议你找到敢于覆盖被禁止的内存并破坏堆的不法分子,而不是阻止崩溃。

    【讨论】:

      【解决方案3】:

      修复您的代码,而不是试图忽略如此严重的错误。您的生产代码中不应该有如此严重的内存错误。 AFAIK 没有简单的方法来处理这个问题,这是有充分理由的。

      顺便说一句,我认为对话框仅在调试模式下出现。在释放模式下,不应检测到内存错误,应用程序应立即崩溃(或使用损坏的堆运行,yuk)。

      【讨论】:

      • 是的,这是调试开启的时候。
      • 我正在清理错误,但如果错误发生在最终用户 ID 上,例如不要让整个应用程序崩溃,只是这个模块并记录错误以进行调试......
      • @brlja:但是堆损坏会影响整个过程,而不仅仅是模块。没有安全的方法可以“使模块崩溃”并在堆损坏后允许主应用程序继续运行。
      【解决方案4】:

      许多 Windows 程序使用 HeapSetInformationHeapEnableTerminationOnCorruption 以确保在检测到堆损坏时程序立即崩溃。这是一种安全措施,因为堆损坏可能是可利用的。在堆损坏时立即崩溃是唯一明智的做法。

      但是,如果您尝试调试,并且它是发布版本,则此设置可能会使问题难以调试。听起来您有一个在其他人的应用程序中运行的模块(尽管我不确定您的描述)。在这种情况下,可能是其他应用程序正在设置堆终止标志。不幸的是,一旦设置(每个进程)就不能取消设置。

      您需要附加调试器以在发生崩溃时生成转储文件并尝试从中进行调试。

      【讨论】:

      • 平台是 Lotus Notes。我使用 Lotus C api 处理 Lotus Notes 文档。由于有很多事情可能出错,我想我可能会在它发生时以某种方式将损害降到最低。
      猜你喜欢
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      • 2012-02-05
      • 2012-06-27
      相关资源
      最近更新 更多