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
并没有被它绊倒。我试图通过在不同的程序中执行相同的malloc
s 和free
s 序列来重现失败,但效果很好。
所以我的问题是:
以前有人见过这个错误吗?或者,或者,
如何调试这样的东西?例如,是否有 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”?
如何在 Mac OS X 10.5 中处理从 Finder 中的多个文件拖放?