【问题标题】:C Runtime Library issue MD/MDdC 运行时库问题 MD/MDd
【发布时间】:2019-08-12 14:02:23
【问题描述】:

我们有一个想要分发的 C 库以及 C 示例代码。

该库当然是在发布模式下构建的。 示例代码项目位于 cmake 中,因此可以在 Linux 和 Windows 上轻松运行。 在 Linux(调试和发布)以及 Windows(发布)上,我们没有问题。 但是,在 Windows(调试)上,我们在离开 main 时遇到了一个问题:程序触发了一个断言:

Invalid address specified to RtlValidateHeap
Expression: _CrtIsValidHeapPointer(block)

然后在继续该过程时,它会引发以下异常:

Unhandled exception at [...] (ntdll.dll)
0xC000000D STATUS_INVALID_PARAMETER

由于这似乎与运行时库有关,我们尝试将其从 MDd(多线程 dll 调试)更改为 MD(多线程 dll)[more on these here],它解决了这个问题。 然而,这似乎是一种变通而不是修复:发布库(使用 MD 构建)应该可以在使用 MDd 的调试程序中使用,对吧?

据我们了解,运行时库中的冲突仅在调用者进行分配和被调用者进行释放时才会出现,反之亦然。 因此,我们跟踪了所有分配以检查它们,一切似乎都很好。 我们在 Linux (Valgrind) 和 Windows (CrtDbg) 中对示例代码进行了泄漏检测,但他们没有发现任何泄漏,一切似乎都很好。

期望使用 MD 构建的发布库在 MDd 程序中运行是否正确? 如果不是,那似乎很奇怪:库总是在发布中分发,但在开发时用于调试解决方案...... 如果是,是什么原因造成的?

【问题讨论】:

  • 什么是MD和MDd?
  • 无论如何,这听起来更像是堆损坏而不是泄漏。这意味着有人正在覆盖堆(传递了它分配的内存)。
  • @PaulOgilvie - 我认为 MDMDd 已定义 here,但问题中并不清楚。
  • @PaulOgilvie 无论如何,这听起来更像是堆损坏而不是泄漏。确实如此。 Microsoft 的调试库执行诸如覆盖free() 上的内存之类的操作,并在分配时用非零值填充它。遇到调试库问题但非调试运行时没有问题是程序损坏内存的标志。
  • 您可能还想尝试-fsanitize=undefined 来查找 Linux GCC 的未定义行为。或者最后它可能像 long int 索引一样狡猾,用于寻址 > 4G 的数组,它可以在 Linux 中工作,因为 long int 是什么,并且在 Windows 中处于发布模式,因为溢出被​​忽略......

标签: c windows visual-studio runtime-error


【解决方案1】:

这听起来更像是堆损坏而不是泄漏。这意味着有人正在覆盖堆(传递了它分配的内存)。找到它可能会很痛苦。

首先,检查您的示例代码。将它剥离到最低限度的“hello world”,然后构建它直到它再次发生。然后检查示例代码。如果不是示例代码,请检查调用了哪些库函数并进行代码审查。

作为辅助,您可以使用 MS 堆检查功能。将它们放在函数入口和函数出口,或维护您定期检查的全局版本。下面是一个例子:

#include <crtdbg.h>

void example(void)
{
    _CrtMemState memStateStart, memStateEnd, memStateDelta;

    // Make a checkpoint of the heap's state so we can later check the heap is still OK
    _CrtMemCheckpoint( &memStateStart );
    //
    // do your things
    //
    // Check the heap
    _CrtMemCheckpoint( &memStateEnd );
    _CrtSetReportMode( _CRT_WARN,   _CRTDBG_MODE_WNDW );
    _CrtSetReportMode( _CRT_ERROR,  _CRTDBG_MODE_WNDW );
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_WNDW );
    if (_CrtMemDifference( &memStateDelta, &memStateStart, &memStateEnd ))
        _CrtMemDumpStatistics( &memStateDelta );
    _CrtDumpMemoryLeaks();
}

【讨论】:

  • 在库中的静态函数中分配了一个 char*,但从未解除分配。因此,它是由被调用者分配的,而调用者在退出时默认释放它,引发运行时库冲突注释代码并通过二分法进行处理使我们能够找到它,修复后问题消失了。非常感谢大家!
猜你喜欢
  • 2013-03-18
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多