gpt4 book ai didi

c++ - 方法最开始的段错误

转载 作者:行者123 更新时间:2023-12-05 02:26:53 24 4
gpt4 key购买 nike

我一直在尝试找出在启用 Address Sanitizer (ASAN) 的情况下运行我的应用程序时看到的段错误的根本原因。当我附加 GDB 并调试应用程序时,我看到在方法的开头收到了段错误:

最少的代码:

    int TimerScope::switchMode() {  
doCapture(mode)
}

> int TimerScope::doCapture(Mode captureMode) { <---- segfault here
if(handle == -1)
return 0;

XLOG(TRACE, image(this));
..
}

请注意,我没有看到没有地址清理器的构建的问题。我已经看过这个问题的不同方面(比如寻找变量的垃圾地址,运行 valgrind/UBSAN 等)但没有任何运气。目前我正在查看汇编代码以查看是否有任何线索。使用 GDB,当我打印段错误的位置时,这就是我得到的:

(gdb) p $_siginfo._sifields._sigfault.si_addr
$5 = (void *) 0x7fe4d3908fb8

汇编代码如下所示,它在调用 TimerScope::doCapture 方法时执行一些逻辑:

    0x7fe69595f65e <_ZN7ts9TimerScope9doCaptureENS_8ModeE>          endbr64                                                                                        │
│ 0x7fe69595f662 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+4> push %rbp │
│ 0x7fe69595f663 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+5> mov %rsp,%rbp │
│ 0x7fe69595f666 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+8> push %r15 │
│ 0x7fe69595f668 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+10> push %r14 │
│ 0x7fe69595f66a <_ZN7ts9TimerScope9doCaptureENS_8ModeE+12> push %r13 │
│ 0x7fe69595f66c <_ZN7ts9TimerScope9doCaptureENS_8ModeE+14> push %r12 │
│ 0x7fe69595f66e <_ZN7ts9TimerScope9doCaptureENS_8ModeE+16> push %rbx │
│ 0x7fe69595f66f <_ZN7ts9TimerScope9doCaptureENS_8ModeE+17> sub $0x1000,%rsp │
│ 0x7fe69595f676 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+24> orq $0x0,(%rsp) │
│ 0x7fe69595f67b <_ZN7ts9TimerScope9doCaptureENS_8ModeE+29> sub $0x1a8,%rsp │
│ > 0x7fe69595f682 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+36> mov %rdi,-0x1198(%rbp) │
│ 0x7fe69595f689 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+43> mov %esi,%eax │
│ 0x7fe69595f68b <_ZN7ts9TimerScope9doCaptureENS_8ModeE+45> mov %al,-0x119c(%rbp) │
│ 0x7fe69595f691 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+51> lea -0x1170(%rbp),%rax │
│ 0x7fe69595f698 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+58> mov %rax,-0x11a8(%rbp) │
│ 0x7fe69595f69f <_ZN7ts9TimerScope9doCaptureENS_8ModeE+65> mov %rax,-0x11c0(%rbp) │
│ 0x7fe69595f6a6 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+72> mov 0x7b92943(%rip),%rax # 0x7fe69d4f1ff0 │
│ 0x7fe69595f6ad <_ZN7ts9TimerScope9doCaptureENS_8ModeE+79> cmpl $0x0,(%rax) │
│ 0x7fe69595f6b0 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+82> je 0x7fe69595f6c8 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+106> │
│ 0x7fe69595f6b2 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+84> mov $0x1120,%edi │
│ 0x7fe69595f6b7 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+89> call 0x7fe6952d6510 <__asan_stack_malloc_7@plt> │
│ 0x7fe69595f6bc <_ZN7ts9TimerScope9doCaptureENS_8ModeE+94> test %rax,%rax │
│ 0x7fe69595f6bf <_ZN7ts9TimerScope9doCaptureENS_8ModeE+97> je 0x7fe69595f6c8 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+106> │
│ 0x7fe69595f6c1 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+99> mov %rax,-0x11a8(%rbp) │
│ 0x7fe69595f6c8 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+106> mov -0x11a8(%rbp),%rbx │
│ 0x7fe69595f6cf <_ZN7ts9TimerScope9doCaptureENS_8ModeE+113> lea 0x1140(%rbx),%rax

特别是,以下是出现段错误的行:

0x7fe69595f682 <_ZN7ts9TimerScope9doCaptureENS_8ModeE+36>       mov    %rdi,-0x1198(%rbp)                                                                      

这里执行的逻辑是什么?我可以看到寄存器rbp的值是0x7fe4d390a150,故障地址0x7fe4d3908fb8可以通过减去0x1198得到来自 0x7fe4d390a150。为什么地址 0x7fe4d3908fb8 会导致段错误?

框架信息如下:

(gdb) info frame
Stack level 0, frame at 0x7fe4d390a160:
rip = 0x7fe69595f682 in ts::TimerScope::doCapture (/tsmgr/src/TimerScope.cpp:142);
saved rip = 0x7fe69595ec93
called by frame at 0x7fe4d390a540
source language c++.
Arglist at 0x7fe4d390a150, args: this=0x0, mode=ts::Mode::None
Locals at 0x7fe4d390a150, Previous frame's sp is 0x7fe4d390a160
Saved registers:
rbx at 0x7fe4d390a128, rbp at 0x7fe4d390a150, r12 at 0x7fe4d390a130, r13 at 0x7fe4d390a138, r14 at 0x7fe4d390a140, r15 at 0x7fe4d390a148, rip at 0x7fe4d390a158

另一件奇怪的事情是,如果我此时分离调试器,为段错误打印的错误消息显示不同的错误地址 (0x3e95c1f300086ab5):

*** Aborted at 1659061552 (Unix time, try 'date -d @1659061552') ***
*** Signal 11 (SIGSEGV) (0x3e95c1f300086ab5) received by PID 551605 (pthread TID 0x7fbe64166700) (linux TID 551964) (maybe from PID 551605, UID 1050001907) (code: -6), stack trace: ***

ASAN 也报告相同的地址:

==551605==ERROR: AddressSanitizer: SEGV on unknown address 0x3e95c1f300086ab5 (pc 0x7fbf388386c4 bp 0x7fbe64128100 sp 0x7fbe641260d8 T358)
==551605==The signal is caused by a WRITE memory access.

为什么 GDB 报告的故障地址与信号处理程序 ASAN 打印的地址不同?

在出现段错误的回溯中,thismode 尚未在方法调用后设置(因此它们显示的值与第 1 帧中的值不同) :

#0  0x00007fe69595f682 in ts::TimerScope::doCapture(this=0x0, mode=ts::Mode::None)
at /tsmgr/src/TimerScope.cpp:142
#1 0x00007fe69595ec93 in ts::TimerScope::switchMode(this=0x612002750d40, mode=ts::Mode::Exclusive)
at /tsmgr/src/TimerScope.cpp:132
#2 0x00007fe6993b2c2b in ts::DataTimer::switchMode(this=0x6040021ac4e0, mode=ts::Mode::Exclusive)
at /tsmgr/src/DataTimer.hpp:84
#3 0x00007fe6993c47c6 in ts::DataTimerScope::switchMode(this=0x6030037d13d0, mode=ts::Mode::Exclusive)
at /tsmgr/src/DataTimerScope.cpp:49
#4 0x00007fe698e0a02a in ts::DataEntry::changeTimerMode (this=0x7fe29ba72700, mode=ts::Mode::Exclusive)

我正在使用支持 libasan6 的 gcc/g++-10 来构建应用程序,并在 ubuntu 20.04 环境中运行它。

能够仅提供代码片段,因为还有许多其他逻辑很难以合理的方式呈现。关于如何进一步处理该问题的任何指示都会有所帮助。当需要更多信息时,会不断更新问题。


编辑 #1:在段错误点,帧 0 中的堆栈指针与堆栈底部(帧 76)中的堆栈指针之间的差异为 199568 字节。栈空间大小设置为8M(默认)

对于故障地址:

(gdb) p $_siginfo._sifields._sigfault.si_addr
$2 = (void *) 0x7f442a630c68

并且 rbp 指向 0x7f442a632150

使用 info proc mappings,我看到以下地址匹配:

  0x7f4429e71000     0x7f442a631000   0x7c0000        0x0
0x7f442a631000 0x7f442a671000 0x40000 0x0

最佳答案

我还在多线程应用程序中使用 AddressSanitizer 构建。我还遇到过一些情况,其中 AddressSanitizer 构建在代码中创建了段错误,但代码却很好。所以在我的例子中,段错误的根源是特定线程上的小堆栈大小。

AddressSanitizer 构建有时需要多达 3 倍的堆栈内存。

以下是 clang 编译器的所有限制:https://clang.llvm.org/docs/AddressSanitizer.html#limitations

关于c++ - 方法最开始的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73578021/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com