Подтвердить что ты не робот

Как отслеживать ошибку "двойной свободной или коррупции"

Когда я запускаю свою (C++) программу, она вылетает с этой ошибкой.

* обнаружен glibc *./load: double free или коррупция (! prev): 0x0000000000c6ed50 ***

Как я могу отслеживать ошибку?

Я пробовал использовать инструкции print (std::cout) без успеха. Может ли gdb сделать это проще?

4b9b3361

Ответ 1

Если вы используете glibc, вы можете установить переменную среды MALLOC_CHECK_ в 2, это приведет к тому, что glibc будет использовать допустимую для ошибок версию malloc, что приведет к прерыванию вашей программы в точке, где делается двойной свободный.

Вы можете установить это из gdb с помощью команды set environment MALLOC_CHECK_ 2 перед запуском вашей программы; программа должна прерываться, при этом вызов free() отображается в обратном направлении.

см. справочную страницу для malloc() для получения дополнительной информации

Ответ 2

Есть как минимум две возможные ситуации:

  • вы удаляете одну и ту же сущность дважды
  • вы удаляете то, что не было выделено

Для первого я настоятельно рекомендую NULL-все удаленные указатели.

У вас есть три варианта:

  • перегружать новые и удалять и отслеживать распределения
  • да, используйте gdb - тогда вы получите обратную трассировку от вашего сбоя, и это, вероятно, будет очень полезно
  • как предлагалось - используйте Valgrind - попасть туда нелегко, но это спасет вас в тысячи раз в будущем...

Ответ 3

Вы можете использовать gdb, но сначала я попробую Valgrind. См. Краткое руководство по началу работы.

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

Ответ 4

Три основных правила:

  1. Установите указатель на NULL после бесплатного
  2. Перед NULL проверьте наличие NULL.
  3. Инициализировать указатель на NULL в начале.

Сочетание этих трех работ достаточно хорошо.

Ответ 5

Вы можете использовать valgrind для его отладки.

#include<stdio.h>
#include<stdlib.h>

int main()
{
 char *x = malloc(100);
 free(x);
 free(x);
 return 0;
}

[[email protected] testbox]$ vim t1.c
[[email protected] testbox]$ cc -g t1.c -o t1
[[email protected] testbox]$ ./t1
*** glibc detected *** ./t1: double free or corruption (top): 0x00000000058f7010 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3a3127245f]
/lib64/libc.so.6(cfree+0x4b)[0x3a312728bb]
./t1[0x400500]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x3a3121d994]
./t1[0x400429]
======= Memory map: ========
00400000-00401000 r-xp 00000000 68:02 30246184                           /home/sand/testbox/t1
00600000-00601000 rw-p 00000000 68:02 30246184                           /home/sand/testbox/t1
058f7000-05918000 rw-p 058f7000 00:00 0                                  [heap]
3a30e00000-3a30e1c000 r-xp 00000000 68:03 5308733                        /lib64/ld-2.5.so
3a3101b000-3a3101c000 r--p 0001b000 68:03 5308733                        /lib64/ld-2.5.so
3a3101c000-3a3101d000 rw-p 0001c000 68:03 5308733                        /lib64/ld-2.5.so
3a31200000-3a3134e000 r-xp 00000000 68:03 5310248                        /lib64/libc-2.5.so
3a3134e000-3a3154e000 ---p 0014e000 68:03 5310248                        /lib64/libc-2.5.so
3a3154e000-3a31552000 r--p 0014e000 68:03 5310248                        /lib64/libc-2.5.so
3a31552000-3a31553000 rw-p 00152000 68:03 5310248                        /lib64/libc-2.5.so
3a31553000-3a31558000 rw-p 3a31553000 00:00 0
3a41c00000-3a41c0d000 r-xp 00000000 68:03 5310264                        /lib64/libgcc_s-4.1.2-20080825.so.1
3a41c0d000-3a41e0d000 ---p 0000d000 68:03 5310264                        /lib64/libgcc_s-4.1.2-20080825.so.1
3a41e0d000-3a41e0e000 rw-p 0000d000 68:03 5310264                        /lib64/libgcc_s-4.1.2-20080825.so.1
2b1912300000-2b1912302000 rw-p 2b1912300000 00:00 0
2b191231c000-2b191231d000 rw-p 2b191231c000 00:00 0
7ffffe214000-7ffffe229000 rw-p 7ffffffe9000 00:00 0                      [stack]
7ffffe2b0000-7ffffe2b4000 r-xp 7ffffe2b0000 00:00 0                      [vdso]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0                  [vsyscall]
Aborted
[[email protected] testbox]$


[[email protected] testbox]$ vim t1.c
[[email protected] testbox]$ cc -g t1.c -o t1
[[email protected] testbox]$ valgrind --tool=memcheck ./t1
==20859== Memcheck, a memory error detector
==20859== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20859== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20859== Command: ./t1
==20859==
==20859== Invalid free() / delete / delete[]
==20859==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859==    by 0x4004FF: main (t1.c:8)
==20859==  Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20859==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20859==    by 0x4004F6: main (t1.c:7)
==20859==
==20859==
==20859== HEAP SUMMARY:
==20859==     in use at exit: 0 bytes in 0 blocks
==20859==   total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20859==
==20859== All heap blocks were freed -- no leaks are possible
==20859==
==20859== For counts of detected and suppressed errors, rerun with: -v
==20859== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[[email protected] testbox]$


[[email protected] testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20899== Memcheck, a memory error detector
==20899== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20899== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20899== Command: ./t1
==20899==
==20899== Invalid free() / delete / delete[]
==20899==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899==    by 0x4004FF: main (t1.c:8)
==20899==  Address 0x4c26040 is 0 bytes inside a block of size 100 free'd
==20899==    at 0x4A05A31: free (vg_replace_malloc.c:325)
==20899==    by 0x4004F6: main (t1.c:7)
==20899==
==20899==
==20899== HEAP SUMMARY:
==20899==     in use at exit: 0 bytes in 0 blocks
==20899==   total heap usage: 1 allocs, 2 frees, 100 bytes allocated
==20899==
==20899== All heap blocks were freed -- no leaks are possible
==20899==
==20899== For counts of detected and suppressed errors, rerun with: -v
==20899== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
[[email protected] testbox]$

Одно возможное исправление:

#include<stdio.h>
#include<stdlib.h>

int main()
{
 char *x = malloc(100);
 free(x);
 x=NULL;
 free(x);
 return 0;
}

[[email protected] testbox]$ vim t1.c
[[email protected] testbox]$ cc -g t1.c -o t1
[[email protected] testbox]$ ./t1
[[email protected] testbox]$

[[email protected] testbox]$ valgrind --tool=memcheck --leak-check=full ./t1
==20958== Memcheck, a memory error detector
==20958== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==20958== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==20958== Command: ./t1
==20958==
==20958==
==20958== HEAP SUMMARY:
==20958==     in use at exit: 0 bytes in 0 blocks
==20958==   total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==20958==
==20958== All heap blocks were freed -- no leaks are possible
==20958==
==20958== For counts of detected and suppressed errors, rerun with: -v
==20958== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
[[email protected] testbox]$

Проверьте блог на использовании Valgrind Ссылка

Ответ 6

Используете ли вы умные указатели, такие как Boost shared_ptr? Если да, проверьте, не используете ли вы прямой указатель где-либо, вызывая get(). Я обнаружил, что это довольно распространенная проблема.

Например, представьте сценарий, в котором передается необработанный указатель (возможно, как обработчик обратного вызова), к вашему коду. Вы можете назначить это умному указателю, чтобы справиться с подсчетом ссылок и т.д. Большая ошибка: ваш код не владеет этим указателем, если вы не делаете глубокую копию. Когда ваш код будет выполнен с помощью умного указателя, он уничтожит его и попытается уничтожить память, на которую он указывает, поскольку он думает, что ему больше никто не нужен, , но вызов код затем попытается удалить его, и вы получите двойную свободную проблему.

Конечно, это может быть не ваша проблема. У него проще всего пример, который показывает, как это может произойти. Первое удаление - это хорошо, но компилятор понимает, что он уже удалил эту память и вызвал проблему. Именно поэтому назначение 0 указателю сразу после удаления является хорошей идеей.

int main(int argc, char* argv[])
{
    char* ptr = new char[20];

    delete[] ptr;
    ptr = 0;  // Comment me out and watch me crash and burn.
    delete[] ptr;
}

Изменить: изменено delete на delete[], так как ptr представляет собой массив char.

Ответ 7

С современными компиляторами С++ вы можете использовать дезинфицирующие средства для отслеживания.

Пример примера:

Моя программа:

$cat d_free.cxx 
#include<iostream>

using namespace std;

int main()

{
   int * i = new int();
   delete i;
   //i = NULL;
   delete i;
}

Скомпилируйте с помощью дезинфицирующих средств:

# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g

Выполнить:

# ./a.out 
=================================================================
==4836==ERROR: AddressSanitizer: attempting double-free on 0x602000000010 in thread T0:
    #0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140
    #1 0x400b2c in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:11
    #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)
    #3 0x400a08  (/media/sf_shared/jkr/cpp/d_free/a.out+0x400a08)

0x602000000010 is located 0 bytes inside of 4-byte region [0x602000000010,0x602000000014)
freed by thread T0 here:
    #0 0x7f35b2d7b3c8 in operator delete(void*, unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140
    #1 0x400b1b in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:9
    #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)

previously allocated by thread T0 here:
    #0 0x7f35b2d7a040 in operator new(unsigned long) /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:80
    #1 0x400ac9 in main /media/sf_shared/jkr/cpp/d_free/d_free.cxx:8
    #2 0x7f35b2050c04 in __libc_start_main (/lib64/libc.so.6+0x21c04)

SUMMARY: AddressSanitizer: double-free /media/sf_shared/gcc-7.1.0/libsanitizer/asan/asan_new_delete.cc:140 in operator delete(void*, unsigned long)
==4836==ABORTING

Чтобы узнать больше о дезинфицирующих средствах, вы можете проверить this или this или любые современные компиляторы С++ (например, gcc, clang и т.д.).

Ответ 8

Я знаю, что это очень старый поток, но это самый лучший поиск Google для этой ошибки, и ни один из ответов не упоминает общую причину ошибки.

Закрытие файла, который вы уже закрыли.

Если вы не обращаете внимания и у вас есть две разные функции, закройте один и тот же файл, а второй будет генерировать эту ошибку.