debugging - “gdb”和“valgrind”以不同的方式执行二进制文件?
问题描述
我的程序收到有关堆内存损坏的错误。
osboxes@osboxes:/mnt/hgfs/VM_Shared/ISSUES/_[02]$ ./shuf /dev/null
*** Error in `./shuf': corrupted double-linked list: 0xb7f01ac0 ***
在仅使用 gdb 进行调试时,我遇到了valgrind
. (感谢这里)
而且...我得到了使用valgrind
.
(抱歉日志太长了,提问前我想先缩写,但怕漏掉一些分析所需的信息。)
osboxes@osboxes:~/Desktop/VM_Shared/ISSUES/_[02]$ valgrind --run-libc-freeres=no ./shuf /dev/null
==23373== Command: ./shuf /dev/null
==23373==
==23373== Invalid read of size 4
==23373== at 0x40B7859: _IO_file_close_it@@GLIBC_2.1 (fileops.c:178)
==23373== by 0x40B4AE6: freopen64 (freopen64.c:49)
==23373== by 0x804EECF: ??? (shuf.s:22773)
==23373== Address 0x20 is not stack'd, malloc'd or (recently) free'd
==23373==
==23373== Process terminating with default action of signal 11 (SIGSEGV)
==23373== Access not within mapped region at address 0x20
==23373== at 0x40B7859: _IO_file_close_it@@GLIBC_2.1 (fileops.c:178)
==23373== by 0x40B4AE6: freopen64 (freopen64.c:49)
==23373== by 0x804EECF: ??? (shuf.s:22773)
==23373== If you believe this happened as a result of a stack
==23373== overflow in your program's main thread (unlikely but
==23373== possible), you can try to increase the size of the
==23373== main thread stack using the --main-stacksize= flag.
==23373== The main thread stack size used in this run was 8388608.
==23373==
==23373== HEAP SUMMARY:
==23373== in use at exit: 2,020 bytes in 31 blocks
==23373== total heap usage: 32 allocs, 1 frees, 2,025 bytes allocated
==23373==
==23373== LEAK SUMMARY:
==23373== definitely lost: 0 bytes in 0 blocks
==23373== indirectly lost: 0 bytes in 0 blocks
==23373== possibly lost: 0 bytes in 0 blocks
==23373== still reachable: 2,020 bytes in 31 blocks
==23373== suppressed: 0 bytes in 0 blocks
==23373== Rerun with --leak-check=full to see details of leaked memory
==23373==
==23373== For counts of detected and suppressed errors, rerun with: -v
==23373== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
问题:
valgrind
说无效读取发生在178 line in fileopc.c
。
但是,我发现这个程序178 line in fileopc.c
在被gdb
!
控制流以不同的方式进行,如下所示。
pwndbg>
176 in fileops.c
────────────────────────────[ DISASM ]────────────────────────────
0xb7e7184f <_IO_file_close_it+63> mov edx, dword ptr [ebx + 0x68]
0xb7e71852 <_IO_file_close_it+66> test edx, edx
> 0xb7e71854 <_IO_file_close_it+68> ✔ jle _IO_file_close_it+151 <0xb7e718a7>
↓
0xb7e718a7 <_IO_file_close_it+151> push 0
0xb7e718a9 <_IO_file_close_it+153> push 0
0xb7e718ab <_IO_file_close_it+155> push 0
pwndbg>
185 in fileops.c
────────────────────────────[ DISASM ]────────────────────────────
0xb7e7184f <_IO_file_close_it+63> mov edx, dword ptr [ebx + 0x68]
0xb7e71852 <_IO_file_close_it+66> test edx, edx
0xb7e71854 <_IO_file_close_it+68> jle _IO_file_close_it+151 <0xb7e718a7>
↓
> 0xb7e718a7 <_IO_file_close_it+151> push 0
0xb7e718a9 <_IO_file_close_it+153> push 0
0xb7e718ab <_IO_file_close_it+155> push 0
问题(续):
如您所见,控制流没有到达178 line in fileopc.c
,valgrind
所说的错误嵌套在哪里。
相反,控制流只是直接从 跳转176 in fileops.c
到185 in fileops.c
。
问题:
这里发生了什么?valgrind
为什么和之间的控制流不同gdb
?
是因为这两个工具在生成被检查程序时使用不同的方式吗?
解决方案
这里发生了什么?
程序在 Valgrind 上运行正常,但在退出时会产生一堆涉及 __libc_freeres 的错误,然后因分段错误而死。
当程序退出时,Valgrind 运行 glibc 中的 __libc_freeres 过程。这是内存调试器的一个钩子,因此他们可以要求 glibc 释放它使用的任何内存。这样做是为了确保 Valgrind 不会错误地报告 glibc 中的空间泄漏。
问题是在较旧的 glibc 版本中运行 __libc_freeres 会导致此崩溃。
1.1.X 和更高版本的 Valgrind 的解决方法:使用 --run-libc-freeres=no 选项。然后,您可能会得到 glibc 分配的空间泄漏报告(请不要将这些报告给 glibc 人员,因为它们不是真正的泄漏),但至少程序运行。
请注意,虽然上面的文字讨论的是较旧的 GLIBC,但这也可能发生在破坏 GLIBC 内部状态的程序中,这显然是这里的情况。
为什么 valgrind 和 gdb 之间的控制流不同
GDB 不调用__libc_freeres
,Valgrind 调用。(还有许多其他细微的差异,但这是观察到的崩溃最可能的解释。)
推荐阅读
- makefile - Makefile 文件无法识别:文件格式无法识别
- loops - %0|%0 是如何工作的?
- php - PHP - preg_match():在字符串中搜索多个 unicode 字符不是重复的,实际阅读
- java - 如果我写了一个实现 Comparable 接口的类“Hello”的版本,那么这个版本的 Hello 类是“IS-A Hello”还是“IS-A Comparable”
- ajax - AJAX如何将php函数的值传递给AJAX动作调用
- google-cloud-dataflow - 数据流水印概念
- keychain - 从 CA 请求证书时出现“未知错误 = 1”
- openssl - 如何使用 Openssl:ECDSA 获取它的 pubkey
- c# - FileSavePicker 可以在 UWP 后台进程中使用吗?
- http - 由于 http 代码 -1,无法通过 http 调用向服务器发送数据