OS X 10.5 malloc 中的错误?

Posted

技术标签:

【中文标题】OS X 10.5 malloc 中的错误?【英文标题】:Bug in OS X 10.5 malloc? 【发布时间】:2011-06-24 12:42:23 【问题描述】:

我正在用 C 语言编写程序。我有两台主要的开发机器,都是 Mac。一个运行 OS X 10.5 并且是 32 位机器,另一个运行 OS X 10.6 并且是 64 位。该程序在 64 位机器上编译和运行时运行良好。但是,当我在 32 位机器上编译完全相同的程序时,它会运行一段时间,然后在 malloc 内的某个地方崩溃。这是回溯:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xeeb40fe0
0x9036d598 in small_malloc_from_free_list ()
(gdb) bt
#0  0x9036d598 in small_malloc_from_free_list ()
#1  0x90365286 in szone_malloc ()
#2  0x903650b8 in malloc_zone_malloc ()
#3  0x9036504c in malloc ()
#4  0x0000b14c in xmalloc (s=2048) at Common.h:185
...

xmalloc 是我的自定义包装器,如果malloc 返回NULL,它只会调用exit,因此它不会耗尽内存。

如果我用-ltcmalloc 链接相同的代码,它可以正常工作,所以我强烈怀疑这是 OS X 10.5 的默认分配器中的某个错误。可能是我的程序在某处造成了一些内存损坏,而tcmalloc 并没有被它绊倒。我试图通过在不同的程序中执行相同的mallocs 和frees 序列来重现失败,但效果很好。

所以我的问题是:

以前有人见过这个错误吗?或者,或者,

如何调试这样的东西?例如,是否有 OS X 的 malloc 的调试版本?

顺便说一句,这些是链接库:

$ otool -L ./interp 
./interp:
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.5)

更新:是的,由于写入数组末尾而导致堆损坏,现在可以正常工作了。我应该在发布问题之前运行valgrind。尽管如此,我还是对如何防止这种损坏的技术(除了 valgrind)感兴趣,所以谢谢。

【问题讨论】:

“所以我强烈怀疑这是 OS X 10.5 的默认分配器中的某个错误”:不,不是。你在某处破坏记忆。你试过在 valgrind 下运行吗? 这几乎可以肯定是你的程序中的一个错误,它破坏了堆。 可能malloc 中的错误,但请记住:当开发人员说“我怀疑库中有错误”时,他们有 90% 的可能性重新错了。 (类似地,当库编写者说“我怀疑内核中存在错误”时,他们有 90% 的可能性是错误的;当内核工程师说“我怀疑硬件中存在错误”时,有 90% 的可能性他们也错了)。在这种情况下,您的代码看起来像是在使用 malloc 的内部数据结构之一;因为 tcmalloc 有不同的内部数据结构,使用它可以避免这个问题。 @stephen:对于像 malloc 这样基本的东西,我想说几率远高于 90%。让我想起了一个“程序员”,他在 strcat 中“发现”(并报告)了一个“错误”,不知道目的地需要空间来保存连接结果。 @xcramps:哦,我知道,我当时非常保守(实际数字更像是 99.99%)。还有@nominolo:我怀着极大的同情说这一切,因为有人 (a) 发表了这样的声明,并且 (b) 发现了库、内核和硬件中的合法错误。 【参考方案1】:

您是否阅读过 MacOS X 上 malloc() 的手册页?在某种程度上,它说:

调试分配错误

提供了许多工具来帮助调试应用程序中的分配错误。这些 设施主要通过环境变量控制。公认的环境变量 并且它们的含义记录在下面。

环境

以下环境变量会改变分配相关函数的行为。

MallocLogFile <f>

创建/附加消息到给定的文件路径,而不是写入 标准错误。

MallocGuardEdges

如果设置,则在每个大块之前和之后添加一个保护页面。

MallocDoNotProtectPrelude

如果设置,不要在大块之前添加保护页,即使 MallocGuardEdges 环境变量已设置。

MallocDoNotProtectPostlude

如果设置,不要在大块之后添加保护页,即使 MallocGuardEdges 环境变量已设置。

MallocStackLogging

如果设置,则记录所有堆栈,以便使用泄漏之类的工具。

MallocStackLoggingNoCompact

如果设置,则以兼容的方式记录所有堆栈 malloc_history 程序。

MallocStackLoggingDirectory

如果设置,将堆栈日志记录到指定目录而不是保存 它们到默认位置 (/tmp)。

MallocScribble

如果设置,则用 0xaa 字节填充已分配的内存。这 增加了对新分配内存的内容进行假设的程序失败的可能性。此外,如果设置,填充内存 已用 0x55 字节释放。这增加了可能性 程序将由于访问不再分配的内存而失败。

MallocCheckHeapStart <s>

如果设置,指定分配数量<s> 在开始之前等待 按照 MallocCheckHeapEach 的规定,每隔 <n> 定期进行堆检查。如果 设置了 MallocCheckHeapStart 但未指定 MallocCheckHeapEach,则 默认检查重复次数为 1000。

MallocCheckHeapEach <n>

如果设置,则每<n> 操作对堆运行一次一致性检查。 MallocCheckHeapEach 仅在 MallocCheckHeapStart 也是有意义的情况下才有意义 设置。

MallocCheckHeapSleep <t>

设置休眠秒数(等待调试器附加) 当设置了 MallocCheckHeapStart 并检测到堆损坏时。这 默认值为 100 秒。将此设置为零意味着根本不睡觉。 将此设置为负数意味着睡眠(对于正数 秒)仅在第一次检测到堆损坏时。

MallocCheckHeapAbort <b>

当设置了 MallocCheckHeapStart 并将其设置为非零值时, 如果检测到堆损坏,则调用 abort(3),而不是 任何睡觉。

MallocErrorAbort

如果设置,则在遇到错误时调用 abort(3) malloc(3) 或 free(3) ,例如先前在指针上调用 free(3) 释放。

MallocCorruptionAbort

与 MallocErrorAbort 类似,但不会在内存不足的情况下中止,因此仅捕获那些会导致的错误更有用 内存损坏。 MallocCorruptionAbort 始终在 64 位进程上设置。


也就是说,我还是会先使用valgrind

【讨论】:

【参考方案2】:

以前有人见过这个错误

是的,这是常见的编程错误,几乎可以肯定在您的代码中。见http://www.efnetcpp.org/wiki/Heap_Corruption

我怎样才能调试这样的东西?

请参阅上述链接的“工具”部分。

【讨论】:

以上是关于OS X 10.5 malloc 中的错误?的主要内容,如果未能解决你的问题,请参考以下文章

NPM:在 OS X El Capitan 上的“ld: library not found for -lgcc_s.10.5”?

Pyraf 在 os x 上构建错误版本的 gcc

如何在 Mac OS X 10.5 中处理从 Finder 中的多个文件拖放?

OS X - x64:堆栈不是 16 字节对齐错误

OS X 10.5 SDK 已弃用 getAttributeNS;我应该改用啥?

如何在Mac OS X 10.5 Leopard中刷新DNS