Использование GDB для исправления ошибки двойного освобождения или повреждения (! Prev) в большом проекте - PullRequest
0 голосов
/ 18 января 2019

Справочная информация:

Я разработал довольно большой проект ( 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, следуют той же тенденции: пользователи публикуют здесь свой фрагмент кода, а кто-то выявляет ошибку программирования (см. Ниже). Когда я запускаю backtrace, он перенаправляет меня на системные файлы / файлы 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. Использование файлов Core (см. Комментарий Роби Басака)
  3. Отключение рандомизации
  4. Задняя трассировка

Тривиальные вопросы SO:

  1. двойное освобождение или коррупция (! Prev)

  2. Ошибка двойного освобождения или повреждения (! Prev) в C

  3. Ошибка в `./a.out ': двойное освобождение или повреждение (! Prev): 0x0000000000bb0470

1 Ответ

0 голосов
/ 18 января 2019

Есть ли лучший способ в gdb точно определить, где в коде возникает ошибка двойного освобождения или повреждения (! Prev)?

Да: Valgrind и AddressSanitizer очень помогают в поиске основной причины ошибок повреждения кучи.

Кажется, Valgrind также только сообщает, что произошло двойное освобождение, но не там, где в вашем коде это возникает

То есть неверно . Valgrind (и AddressSanitizer) точно скажет вам, где проблема. Для двойного освобождения они сообщают вам, где первое освобождение произошло раньше, и где второе освобождение происходит сейчас (и где изначально был выделен блок).

Вот отчет sampe от sanitizer адреса для программы, которая показывает double-free:

#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).

...