使用GDB修复大型项目中的双自由或损坏(!prev)错误



背景:

我已经派生了一个相当大的项目(popcornmix omxplayer repo),我正在对其进行修改,以允许在多个显示器上进行同步。我在运行时遇到以下分段故障

*** Error in `./omxplayer.bin': double free or corruption (!prev): 0x02141400 ***
./omxplayer: line 67: 17399 Aborted                 (core dumped) LD_LIBRARY_PATH="$OMXPLAYER_LIBS${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" $OMXPLAYER_BIN "$@"

事实证明,打印报表毫无用处。我正在遵循在线教程(见下面的链接),使用gdb来跟踪分段故障发生的确切位置,但我发现他们给出的示例微不足道,甚至是一个hello_world程序,这并不能说明我的问题。类似地,在SO上提出的问题也遵循同样的趋势,用户在这里发布他们的代码片段,然后有人识别编程错误(见下文)。当我运行回溯时,它会将我重定向到系统文件/C文件(不确定术语)。以下是输出示例:

$ gdb omxplayer.bin core
GNU gdb (Raspbian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from omxplayer.bin...(no debugging symbols found)...done.
[New LWP 17417]
[New LWP 17412]
[New LWP 17399]
[New LWP 17416]
[New LWP 17409]
[New LWP 17413]
[New LWP 17411]
[New LWP 17408]
[New LWP 17415]
[New LWP 17410]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
Core was generated by `./omxplayer.bin --sync-server --server-port 1234 --sync-num-client 1 --sync-ver'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[Current thread is 1 (Thread 0x6ef80340 (LWP 17417))]
(gdb) where
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x75a9c824 in __GI_abort () at abort.c:89
#2  0x00083dc0 in sig_handler(int) ()
#3  <signal handler called>
#4  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#5  0x75a9c824 in __GI_abort () at abort.c:89
#6  0x75ad5f78 in __libc_message (do_abort=do_abort@entry=2, fmt=<optimized out>)
at ../sysdeps/posix/libc_fatal.c:175
#7  0x75adcad4 in malloc_printerr (action=<optimized out>, 
str=0x75b8ef70 "double free or corruption (!prev)", ptr=<optimized out>, 
ar_ptr=<optimized out>) at malloc.c:5049
#8  0x75add514 in _int_free (av=0x75bab794 <main_arena>, p=0x21413f8, 
have_lock=<optimized out>) at malloc.c:3905
#9  0x00038260 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) list
46  in ../sysdeps/unix/sysv/linux/raise.c
(gdb) list
46  in ../sysdeps/unix/sysv/linux/raise.c
(gdb) 
46  in ../sysdeps/unix/sysv/linux/raise.c
(gdb) backtrace
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x75a9c824 in __GI_abort () at abort.c:89
#2  0x00083dc0 in sig_handler(int) ()
#3  <signal handler called>
#4  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#5  0x75a9c824 in __GI_abort () at abort.c:89
#6  0x75ad5f78 in __libc_message (do_abort=do_abort@entry=2, fmt=<optimized out>)
at ../sysdeps/posix/libc_fatal.c:175
#7  0x75adcad4 in malloc_printerr (action=<optimized out>, 
str=0x75b8ef70 "double free or corruption (!prev)", ptr=<optimized out>, 
ar_ptr=<optimized out>) at malloc.c:5049
#8  0x75add514 in _int_free (av=0x75bab794 <main_arena>, p=0x21413f8, 
have_lock=<optimized out>) at malloc.c:3905
#9  0x00038260 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

我希望得到像omxplayer.cpp line 123: int *foo这样的评论,但它却告诉我错误发生在malloc.c中,这并不完全有用。

问题:gdb中是否有更好的方法来准确查找double free or corruption (!prev) error在代码中的出现位置?

一些GDB教程:

  1. 如何正确编译
  2. 使用核心文件(参见Robie Basak的评论)
  3. 禁用随机化
  4. 回溯

琐碎的SO问题:

  1. 双重免费或损坏(!prev)

  2. C 中的双自由或损坏(!prev)错误

  3. "中出错/a.out':双自由或损坏(!prev):0x0000000000bb0470

gdb中是否有更好的方法来准确查找代码中出现双自由或损坏(!prev)错误的位置?

是的:Valgrind和AddressSanitizer极大地帮助找到堆损坏错误的根本原因。

似乎Valgrind也只通知发生了双重免费,但没有通知在你的代码中出现的地方

这是不正确的。Valgrind(和AddressSanitizer)会告诉你问题的确切位置。对于双免费,他们会告诉你第一次免费之前发生在哪里,第二次免费现在发生在哪里(以及区块最初分配的位置)。

以下是一个显示双重免费的程序的地址清理程序的采样报告:

#include <malloc.h>
int use_and_free(int *p)
{
int result = *p;
free(p);
}
int main(void)
{
const int num_pointers = 2;
int *p[num_pointers];
for (int j = 0; j < num_pointers; j++) {
p[j] = malloc(sizeof(int));
*p[j] = j;
}
int sum = 0;
for (int j = 0; j < num_pointers; j++) {
sum += use_and_free(p[j]);
}
// Oops: double-free.
free(p[0]);
return sum;
}
gcc -g t.c -fsanitize=address && ./a.out
=================================================================
==132174==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T0:
#0 0x7fa305b698c8 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd98c8)
#1 0x5654448c1ba9 in main /tmp/t.c:25
#2 0x7fa3057112b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
#3 0x5654448c18a9 in _start (/tmp/a.out+0x8a9)
0x602000000010 is located 0 bytes inside of 4-byte region [0x602000000010,0x602000000014)
freed by thread T0 here:
#0 0x7fa305b698c8 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd98c8)
#1 0x5654448c19e1 in use_and_free /tmp/t.c:6
#2 0x5654448c1b6a in main /tmp/t.c:21
#3 0x7fa3057112b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
previously allocated by thread T0 here:
#0 0x7fa305b69c20 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd9c20)
#1 0x5654448c1a77 in main /tmp/t.c:15
#2 0x7fa3057112b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
SUMMARY: AddressSanitizer: double-free (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd98c8) in __interceptor_free
==132174==ABORTING

您可以清楚地看到1)错误发生的位置2)问题块已被释放的位置;以及3)它最初被分配到哪里。

以下是相同程序的Valgrind输出:

==132339== Invalid free() / delete / delete[] / realloc()
==132339==    at 0x4C2CD57: free (vg_replace_malloc.c:530)
==132339==    by 0x1087B1: main (t.c:25)
==132339==  Address 0x51d7040 is 0 bytes inside a block of size 4 free'd
==132339==    at 0x4C2CD57: free (vg_replace_malloc.c:530)
==132339==    by 0x1086AA: use_and_free (t.c:6)
==132339==    by 0x108793: main (t.c:21)

在上面,您可以看到1)和2)。

相关内容

  • 没有找到相关文章