2012-12-02 67 views
1

最近我遇到了段错误问题,它在调用delete方法时被击中。我已深入检查了代码,并消除了删除空指针,多次删除或超出限制的可能性(分配的内存足够大以容纳之后写入的内容)。这个问题可以被复制,每次它在同一个地方发生段错误。段错误代码的可能原因是什么

我想尽办法可能会导致此问题。我不知道是否有可能得到错误代码的一些线索,我得到,如: - 段错误的XXXXXXXXXXXXXX撕裂XXXXXXXXXXXXXX RSP XXXXXXXXXXXXXX错误4

我搜索过网了相当长的时间,只得到有用以下信息来自stackoverflow: -

“错误代码只是页面错误的体系结构错误代码,似乎是特定于体系结构的,它们通常记录在内核源代码的arch/*/mm/fault.c中。 Linux/arch/i386/mm/fault.c的副本具有以下error_code的定义:

bit 0 == 0 means no page found, 1 means protection fault 
bit 1 == 0 means read, 1 means write 
bit 2 == 0 means kernel, 1 means user-mode 

这是我的问题: - 错误代码4(我的平台是RHEL5 64位,x86_64)的可能原因是什么?有什么办法可以从错误代码中知道可能的原因吗?

有关如何诊断这类问题的任何其他建议也受到赞赏!

+2

在'valgrind'下运行你的程序。 –

+0

删除空指针不是问题。 – ldav1s

回答

1

鉴于您提供的arch/i386/mm/fault.c的文档,错误代码4对应于“未找到页面的用户模式读取”。代码4的二进制表示= 100,其中位2是最重要的(最左边的)位。

这种伴随着delete接收SIGSEGV的最常见原因:双免费(试图释放已被释放的指针)。但是,任何堆损坏(例如,通过双重释放别的东西或在其他地方出现缓冲区溢出/越界错误)可能是原因。

尝试在valgrind下运行代码(使用调试版本的内存分配例程运行)(在运行二进制文件之前在环境中将MALLOC_CHECK_设置为1或2),这两种方法都尝试抓住这些错误并在制作完成后尽快向您报告。

valgrind在其存储器模型中是详尽的,并且在适当的检查开启的情况下,几乎可以肯定定位问题的根源。

MALLOC_CHECK_是glibc的内部函数,并且与大多数不是valgrind的大多数其他内存调试工具工具一样,它只能捕获某些类型的相对常见错误并在某些情况下检测堆损坏。有很多其他工具,例如MALLOC_CHECK_(例如Electric Fence),但前者已经内置到您的C库中,其他工具至多会要求其库(主要包含mallocfree覆盖,主要)在使用LD_PRELOAD的C库之前动态链接。

请注意,在空指针上使用C++ delete在技术上不是问题,所以您可以从清单中删除一个(因为我猜你可能已经拥有了,通过修改代码以在删除之前显式检查) 。

更多细节:

对应的错误代码“读未找到的页面的用户模式”意味着一个指针,指向存储器(一些64分之32位数字参照某处在虚拟地址空间)被解除引用(即,某些代码尝试读取指针所保存的虚拟内存地址处的值),但内核页表指示虚拟地址引用的内存页面未被映射到您的进程中,或者已从您的流程中取消映射,因为该指针是有效的。除了想象这种情况的明显方式之外,它可以间接发生,因为堆损坏(其中包含幕后的各种簿记信息):例如,指针算术可以根据传递给delete与堆内部的另一个较早损坏的指针进行比较,然后导致位于指针中的无效值,只是等待代码尝试并使用它。

换句话说,内核错误代码在常见的调试场景中确实没有什么帮助。

我假设你已经在gdb下运行你的程序,并且只需在崩溃前的几行设置一个断点,以观察指针被删除的值以及周围状态的其余部分。

编辑:

删除错误-g2参考,当我显然意味着MALLOC_CHECK_。为您添加了更多的诊断问题和解释。

+0

您的意思是,如果原因位于其他位置,则在编译代码时添加-g2开关可能会在程序出错时强制程序提前中止?但据我所知,-g2开关会将符号添加到二进制文件中,从来没有听说它会进行这种类型的检查,有没有对此提及? – user1137890

+0

我知道,我们可以导出MALLOC_CHECK_以在程序中存在内存损坏时强制程序提前中止。我认为如果这个问题是由其他地方的内存腐败引起的,那么这也是一个不错的选择,你对此有何看法?顺便说一句,在我的情况下,我无法自由访问环境,并且这个问题不能在我的环境中重现(在所讨论的环境中也不能100%重现)。所以Valgrind不是一个好选择。我需要找到一些简单可行的方法来做到这一点。 – user1137890

+0

@ user1137890我的意思是,如果在编译代码时添加'-g2'(而不是仅仅打开调试符号的'-g'),GCC将打开其调试堆分配器和各种其他运行时错误检测工具选项。这会做类似于你描述的'MALLOC_CHECK_'的东西,这也许是一个很好的选择,你也应该尝试一下。如果这个错误还不能被重现,那么这就是怀疑堆损坏的更多理由,在大多数情况下,在运行时第一个内存错误点(使用这些工具)可能会检测到堆损坏,而不是在损坏之后很长时间。 –

相关问题