无明显原因的分段错误

     2023-02-17     156

关键词:

【中文标题】无明显原因的分段错误【英文标题】:Segmentation fault for no obvious reason 【发布时间】:2013-04-06 17:48:50 【问题描述】:

我有一个对我来说没有任何意义的分段错误。 第 538 次调用此函数,失败,但我什么也看不到 参数错误。我可以在 gdb 中输入相同的表达式 它会很乐意毫无怨言地做到这一点。我什至爬到它使用 si 并查看了寄存器,它仍然没有任何意义。 我该如何解决这个问题?

一个奇怪的事情是 gdb 报告“位”参数有 故障时从 0 变为 1。 我想“位”在一个寄存器中,它被重用于其他东西。

我也试过这个没有优化。还有很多说明 参与,但结果是一样的。

请注意,我使用 gdb 访问与 代码即将访问,没有问题。

代码:

void Bits::set(int bit)

    if (bit >= _size*16) BUG;
    _dat[bit/16] |= 1 << (bit & 15);

gdb 运行:

Breakpoint 1, Bits::set (this=0x68374, bit=0) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x3964c <_ZN4Bits3setEi+36>: ldr     r3, [r0, #4]
(gdb) si
0x00039650      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x39650 <_ZN4Bits3setEi+40>: mov     r1, #1
(gdb)
0x00039654      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x39654 <_ZN4Bits3setEi+44>: ldrh    r2, [r12, r3]
(gdb)
0x00039658      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x39658 <_ZN4Bits3setEi+48>: orr     r2, r2, r1, lsl lr
(gdb)
0x0003965c      181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x3965c <_ZN4Bits3setEi+52>: strh    r2, [r12, r3]
(gdb) p _dat
$18 = (short *) 0x4ee74
(gdb) p *_dat
$19 = -3784
(gdb) p $r2
$20 = 61753
(gdb) p $r12
$21 = 0
(gdb) p/x $r3
$22 = 0x4ee74
(gdb) si

Program received signal SIGSEGV, Segmentation fault.
0x0003965c in Bits::set (this=0x68374, bit=1) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
1: x/i $pc
=> 0x3965c <_ZN4Bits3setEi+52>: strh    r2, [r12, r3]
(gdb)

顺便说一句,我在这里使用 gdbserver。这是目标响应:

50:/mnt/home/rw # ./gdbserver x:12 cx Andersen_Studio.cxc
Process cx created; pid = 226
Listening on port 12
Remote debugging from host 192.168.1.40

pc : [<0003965c>]    lr : [<00000000>]    Tainted: P
sp : 7ffffdb4  ip : 00000000  fp : 7ffffe84
r10: 2ada7884  r9 : 0000c6c8  r8 : 2ada8d28
r7 : 00000002  r6 : 0005c0b8  r5 : 00000000  r4 : 0006dc10
r3 : 0004ee74  r2 : 0000f139  r1 : 00000001  r0 : 00068374
Flags: Nzcv  IRQs on  FIQs on  Mode USER_32  Segment user
Control: C000317F  Table: 017EC000  DAC: 00000015

更多信息:如果我手动执行命令,则不会发生故障:

Breakpoint 1, Bits::set (this=0x6c75c, bit=0) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
(gdb) c 538
Will ignore next 537 crossings of breakpoint 1.  Continuing.

Breakpoint 1, Bits::set (this=0x68374, bit=0) at util.cpp:181
181         _dat[bit/16] |= 1 << (bit & 15);
(gdb) p _dat[bit/16] |= 1 << (bit & 15)
$25 = -3783
(gdb) dis 1
(gdb) c
Continuing.

仅引用 _dat[0] 并没有帮助,但例如键入 _dat[0]=0 确实可以防止出现问题。

(稍后编辑)

如果我们要查看为函数生成的代码,我决定关闭优化。这是未优化的代码:

(gdb) disass
Dump of assembler code for function _ZN4Bits3setEi:
   0x0006a1d8 <+0>:     mov     r12, sp
   0x0006a1dc <+4>:     push    r11, r12, lr, pc
   0x0006a1e0 <+8>:     sub     r11, r12, #4
   0x0006a1e4 <+12>:    sub     sp, sp, #8
   0x0006a1e8 <+16>:    str     r0, [r11, #-16]
   0x0006a1ec <+20>:    str     r1, [r11, #-20]
=> 0x0006a1f0 <+24>:    ldr     r3, [r11, #-16]
   0x0006a1f4 <+28>:    ldr     r3, [r3]
   0x0006a1f8 <+32>:    lsl     r2, r3, #4
   0x0006a1fc <+36>:    ldr     r3, [r11, #-20]
   0x0006a200 <+40>:    cmp     r3, r2
   0x0006a204 <+44>:    blt     0x6a220 <_ZN4Bits3setEi+72>
   0x0006a208 <+48>:    ldr     r0, [pc, #108]  ; 0x6a27c <_ZN4Bits3setEi+164>
   0x0006a20c <+52>:    ldr     r1, [pc, #108]  ; 0x6a280 <_ZN4Bits3setEi+168>
   0x0006a210 <+56>:    mov     r2, #180        ; 0xb4
   0x0006a214 <+60>:    bl      0xa00c <printf>
   0x0006a218 <+64>:    mov     r0, #1
   0x0006a21c <+68>:    bl      0xa09c <exit>
   0x0006a220 <+72>:    ldr     r1, [r11, #-16]
   0x0006a224 <+76>:    ldr     r2, [r11, #-20]
   0x0006a228 <+80>:    asr     r3, r2, #31
   0x0006a22c <+84>:    lsr     r3, r3, #28
   0x0006a230 <+88>:    add     r3, r2, r3
   0x0006a234 <+92>:    asr     r0, r3, #4
   0x0006a238 <+96>:    mov     r3, r0
   0x0006a23c <+100>:   lsl     r2, r3, #1
   0x0006a240 <+104>:   ldr     r3, [r1, #4]
   0x0006a244 <+108>:   add     r12, r2, r3
   0x0006a248 <+112>:   ldr     r1, [r11, #-16]
   0x0006a24c <+116>:   mov     r3, r0
   0x0006a250 <+120>:   lsl     r2, r3, #1
   0x0006a254 <+124>:   ldr     r3, [r1, #4]
   0x0006a258 <+128>:   add     r1, r2, r3
   0x0006a25c <+132>:   ldr     r3, [r11, #-20]
   0x0006a260 <+136>:   and     r2, r3, #15
   0x0006a264 <+140>:   mov     r3, #1
   0x0006a268 <+144>:   lsl     r3, r3, r2
   0x0006a26c <+148>:   ldrh    r2, [r1]
   0x0006a270 <+152>:   orr     r3, r2, r3
   0x0006a274 <+156>:   strh    r3, [r12]
   0x0006a278 <+160>:   ldmdb   r11, r11, sp, pc
   0x0006a27c <+164>:   andeq   r8, r8, r0, lsr r12
   0x0006a280 <+168>:   andeq   r8, r8, r4, asr r12
End of assembler dump.
(gdb)

我尝试插入 _dat[0] = 0;在“坏”声明之前,这会导致错误。 我试过 _dat[0]++;这也有问题。

【问题讨论】:

所以你说执行 ARM 汇编指令 strh r2, [r12, r3] 会导致访问冲突。问:0x4ee74(包含在 r3 中)是否有效? 0x4ee74 有效。请参阅 gdb 响应 $19。 _size 的值是多少?我看不出有什么明显的错误。你在使用 glibc 吗?可能值得导出 MALLOC_CHECK_=3 以让 glibc 检查与 malloc 相关的问题。 感谢完整的反汇编代码。阅读优化的代码实际上更容易;但不要改变任何东西。 【参考方案1】:

嗯,看起来一切正常。您可以从该位置读取,但您不能写入......奇怪。

我想到了以下想法:

永远不要相信 gdb 显示的内容。当您在 gdb 中评估一个表达式时,这与您的代码所做的完全不同。特别是它不会使用您的代码(除非您明确地按名称调用函数)。 Gdb 将使用调试信息,这些信息通常有差距并且有很大的解释空间,而您的代码将只使用您的代码。 :-) gdb 中的变量值通常是错误的。这很可能甚至不是 gdbs 的错误。 gdb 不能比编译器生成的调试信息更好。它甚至包含大量(与调试信息相关的)编译器错误的启发式方法。

许多不同的故障情况可能会被您的操作系统映射到 Segfault。例如,这可能是异步数据中止,在这种情况下,真正的问题可能早于数百条指令。

您使用的是安全内存还是非安全内存?从非安全模式通过缓存写入安全内存可能会导致异步数据中止。

这个函数运行 537 次 OK 的事实并不意味着什么。它是否在完全相同的数据/内存位置上运行?我的意思是,set() 函数本质上只是一个内存写入。行为(是否崩溃)将始终取决于变量的内容 bit.

当我在我的程序中看到对我没有任何意义的奇怪崩溃时,我会修改函数,使其行为略有不同。如果你这样做会发生什么:

void Bits::set(int bit)

    if (bit >= _size*16) BUG;
    _dat[bit/16] = 42; // does this crash?
    _dat[0] = 42;      // does this crash?
    _dat[bit/16]++;    // does this crash?
    _dat[bit/16] |= 1 << (bit & 15);

(如果您的程序依赖于此,您可能需要保存/恢复写入的位置。)

还有一个帮助是将程序中的诊断消息打印到一些日志中。这通常比使用调试器更好,因为它使用您的代码和实际值,而不是使用调试信息。

【讨论】:

【参考方案2】:

我无法弄清楚为什么在这个特定的行会出现分段错误,因为使用 gdb 修改内存似乎没有问题。但是,通过在 Bits 构造函数中打印出“this”,并将其与错误处的“this”进行比较,我发现我一定是内存损坏,可能离这里很远。因此,我将中断这一调查,继续假设问题出在其他地方。

(稍后)

我发现了问题,它是一个未初始化的指向 Bits 的指针(令人惊讶!),它恰好足够可信,表面上看起来好像它是正确的。为我指明正确方向的想法是“记录事物”的想法,我刚刚使用 printf 实现了这一点。

【讨论】:

并且还使用-Wall -Wextra 编译(使用最近的 GCC 编译器,例如 4.8)可能也有帮助..【参考方案3】:

1) 所以你说执行 ARM 汇编指令 strh r2, [r12, r3] 会导致访问冲突。

2) 问:0x4ee74(包含在 r3 中)是否有效?

3) 问:0000f139(包含在 r2 中)是否有效?来自手册:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0068b/BABDJCHA.html

字和半字传输的地址对齐:

地址必须是 4 的倍数。

如果您的系统有系统协处理器 (cp15),您可以启用 对齐检查。非对齐传输导致对齐异常 如果启用对齐检查。

如果您的系统没有系统协处理器 (cp15),或对齐 检查已禁用:

未对齐的负载会破坏 Rd。

非对齐保存会破坏内存中的四个字节。内存中损坏的位置是 [address AND NOT b11]。

【讨论】:

由于前面两条指令的加载没有失败,看起来地址是有效的,但内存是写保护的。 地址是4的倍数。r2的内容应该是无关紧要的。我们只是存储它是什么。 如果内存是写保护的,gdb 写入它不会有问题吗?它是如何突然获得写保护的?请注意,它是非零值,这意味着同一个函数已经在之前的 537 次调用中访问过这个位置。

C++ omp 无明显改善

】C++omp无明显改善【英文标题】:C++ompnosignificantimprovement【发布时间】:2020-02-1901:11:36【问题描述】:我在MSVC2019上使用默认编译器。我正在处理的代码是Mandelbrot图像。我的代码的相关部分如下所示:#pragmaompparallelforfor(inty=0;y<... 查看详情

yg错误精选

...nService的名字写错了,改后要清浏览器缓存2-没有显示,前端无明显错误,后端无报错 分页插件未在body加上3-无明显报错,审核不通过 实参写成字符串了,数据表Tb_s 查看详情

打印分段错误原因[重复]

】打印分段错误原因[重复]【英文标题】:printthesegmentationfaultreason[duplicate]【发布时间】:2013-04-0713:32:36【问题描述】:假设我有一个导致分段错误的代码。char*ptr=NULL;*ptr="hello";/*thiswillcauseasegmentationfault*/如何在runtime上打印,发... 查看详情

abb示教器触屏无反应,外屏换后还是无反应,电路板上看无明显异常,请问该怎么处理?

abb机器人示教器故障现象及对应解决方案分析故障:ABB示教器触摸无反应  现象:触摸屏幕时鼠标箭头无任何动作,没有发生位置改变。原因:造成此现象产生的原因很多,下面逐个说明:①表面声波触摸屏四周边上的声波反... 查看详情

分段错误的原因

】分段错误的原因【英文标题】:ReasonforSegmentationFault【发布时间】:2011-07-1210:29:00【问题描述】:我使用设置了CLONE_VM和CLONE_FILES的clone()系统调用编写了一个程序。我无法理解为什么输出显示分段错误。有人可以更正我的代码... 查看详情

ce6下无明显针对mfc的组件,m$已经准备放弃mfc了

如果想用MFC,需要手工将MFC加入到系统中。1:在VS2005目录下找到MFCDLL。在我的电脑上目录是D:/ProgramFiles/MicrosoftVisualStudio8/VC/ce/Dll/x86。因为我用的平台是基于CEPC,所以选择x86目录。2:复制MFCDLL到%WINCE_ROOT%/OSDesigns/MFC目录。将x86下的... 查看详情

分段错误的常见原因的最终列表

】分段错误的常见原因的最终列表【英文标题】:DefinitiveListofCommonReasonsforSegmentationFaults【发布时间】:2015-10-0921:31:42【问题描述】:注意:我们有很多segfault问题,大体相同答案,所以我试图将它们折叠成一个规范的问题,比... 查看详情

分段错误的常见原因的最终列表

】分段错误的常见原因的最终列表【英文标题】:DefinitiveListofCommonReasonsforSegmentationFaults【发布时间】:2020-11-0502:49:46【问题描述】:注意:我们有很多segfault问题,大体相同答案,所以我试图将它们折叠成一个规范的问题,比... 查看详情

在 Linux 服务器上检查分段错误的原因

】在Linux服务器上检查分段错误的原因【英文标题】:CheckingthereasonforsegmentationfaultonLinuxserver【发布时间】:2016-03-0807:57:37【问题描述】:我在远程服务器上部署了一个用C语言编写的Linux脚本,多个客户端可以连接到该服务器。... 查看详情

分段错误错误(信号名称:SIGSEGV)的原因是啥,我将如何找到/修复它?

】分段错误错误(信号名称:SIGSEGV)的原因是啥,我将如何找到/修复它?【英文标题】:Whatisthecauseofasegmentationfaulterror(signalname:SIGSEGV),andhowwouldIfind/fixit?分段错误错误(信号名称:SIGSEGV)的原因是什么,我将如何找到/修复它?... 查看详情

分段错误原因未知Opencv

】分段错误原因未知Opencv【英文标题】:SegmentationFaultreasonunknownOpencv【发布时间】:2012-12-2520:08:47【问题描述】:我在linux终端(linux中的c++)中编译了以下代码,并且正在使用OpenCv2.4.3。但是,运行时出现分段错误,我真的不知... 查看详情

解答vs2013编译报错不准确是什么原因

...逐个报出的2、如果报错的信息双击点过去查看时又发现无明显错误问题时,这个这个时候可以是VS编译的缓存问题,这时清除一下硬盘上的缓存文件,再试试编译就可以准确定位到错误的位置了VS编译时在硬盘上的路径为:C:Windo... 查看详情

取消引用从线程原因返回的指针;分段错误:11 [重复]

】取消引用从线程原因返回的指针;分段错误:11[重复]【英文标题】:Dereferencingreturnedpointerfromthreadcauses;Segmentationfault:11[duplicate]【发布时间】:2016-10-1409:53:09【问题描述】:我对C++和指针编程非常陌生。我试图将一个参数传递... 查看详情

脑机接口减肥大法来了!自动减少暴饮暴食频率,无明显副作用|nature子刊

Alex发自凹非寺量子位|公众号QbitAI有正在(或者打算)控制体重的盆友吗?但当一堆美味佳肴摆在你面前时,是不是常常又馋涎欲滴?(不信?看图)不过现在有个帮你控制食欲的新招儿来了:... 查看详情

如何使用 gdb 和 core-dump 文件查找此分段错误的原因?(GDB 的限制)

】如何使用gdb和core-dump文件查找此分段错误的原因?(GDB的限制)【英文标题】:Howtofindthecauseofthissegmentationfaultusinggdbandcore-dumpfile?(LimitationofGDB)【发布时间】:2018-03-0603:00:17【问题描述】:我知道我可以使用核心转储文件找出... 查看详情

具有显式构造函数的类是不是需要在 emplace 中使用分段构造?

】具有显式构造函数的类是不是需要在emplace中使用分段构造?【英文标题】:Doclasseswithexplicitconstructorsrequirepiecewise_constructinemplace?具有显式构造函数的类是否需要在emplace中使用分段构造?【发布时间】:2016-12-1123:11:34【问题描... 查看详情

C++ 的核心转储分段错误

...我遇到了SegmentationFault错误,我不想找出分段错误的根本原因。请找出以下场景:unionValue整数值整数;浮动值_浮动;RWCString*value_string;无效setValueS 查看详情

分段错误 - 大小为 8 的无效读取

...ze8【发布时间】:2012-01-2921:51:44【问题描述】:由于某种原因,以下C++代码会导致分段错误:#include<sstream>#include<vector>usingnamespacestd;stringcharToString(charc)stringstreamss;strin 查看详情