c++ - 使用 GDB 修复大型项目中的双重释放或损坏 (!prev) 错误

标签 c++ segmentation-fault gdb malloc

背景:

我已经 fork 了一个相当大的项目(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 教程:
  • How to correctly compile
  • Using Core files (see Robie Basak's comment)
  • Disabling Randomization
  • Back Tracing

  • 琐碎的 SO 问题:
  • double free or corruption (!prev)
  • Double free or corruption (!prev) error in C
  • Error in `./a.out': double free or corruption (!prev): 0x0000000000bb0470
  • 最佳答案

    Is there a better way in gdb to find out exact where in the code the double free or corruption (!prev) error is arising?



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

    It seems Valgrind also only informs that a double free has occoured, but not where in your code this arises



    这是不正确的。 Valgrind(和 AddressSanitizer)会告诉你问题出在哪里。对于双重释放,它们会告诉您第一个释放发生在哪里,第二个释放现在发生在哪里(以及 block 最初分配的位置)。

    这是来自地址 sanitizer 的示例报告,用于显示双重释放的程序:
    #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) 问题 block 已被释放的位置; 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)。

    关于c++ - 使用 GDB 修复大型项目中的双重释放或损坏 (!prev) 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54259933/

    相关文章:

    c++ - 千分之一符号 (‰) 上的 wctomb 扼流圈

    C++ Array Allocation Segmental Fault 11 新手

    c - 从数组创建链表时 C 中的段错误

    gdb - 应用程序中所有函数调用的列表

    php - 读取文件行和查询结果的编程函数

    c++ - 在构造时初始化一个 float 组

    c++ - 强制访问私有(private)成员

    C++:gcc 4.2.1 给出了段错误的程序,而不是在 linux 上

    c++ - 调试器无法匹配库中的源代码或步骤代码

    visual-studio-code - 使用 Ubuntu 在 Visual Studio Code 中使用 Bazel 进行调试