Cuando ejecuto mi programa (C ++), se bloquea con este error.
* glibc detectado * ./load: doble libre o corrupción (! prev): 0x0000000000c6ed50 ***
¿Cómo puedo localizar el error?
Intenté usar std::cout
declaraciones print ( ), sin éxito. ¿Podría gdb
hacer esto más fácil?
NULL
punteros (que enmascaran errores que de otra manera se detectan, como muestra muy bien esta pregunta), pero nadie sugiere simplemente no hacer la gestión manual de memoria en absoluto, lo cual es muy posible en C ++. No he escritodelete
en años. (Y, sí, mi código es crítico para el rendimiento. De lo contrario, no se habría escrito en C ++.)NULL
Los punteros pueden hacer que su programa se bloquee antes.NULL
punteros es evitar quedelete ptr;
explote un segundo , lo que enmascara un error, porque ese segundodelete
nunca debería haber sucedido. (También se usa para verificar si un puntero sigue apuntando a un objeto válido. Pero eso solo plantea la pregunta de por qué tiene un puntero en el alcance que no tiene un objeto al que apuntar).Respuestas:
Si está usando glibc, puede establecer la
MALLOC_CHECK_
variable de entorno en2
, esto hará que glibc use una versión tolerante a errores demalloc
, lo que hará que su programa se anule en el punto donde se realiza el doble libre.Puede configurar esto desde gdb usando el
set environment MALLOC_CHECK_ 2
comando antes de ejecutar su programa; el programa debe abortar, con lafree()
llamada visible en el backtrace.consulte la página
malloc()
del manual para obtener más informaciónfuente
MALLOC_CHECK_2
realmente solucionó mi problema de doble libre (aunque no se está solucionando si está solo en modo de depuración)Hay al menos dos situaciones posibles:
Para el primero, sugiero encarecidamente anular todos los punteros eliminados.
Tienes tres opciones:
fuente
Puede usar gdb, pero primero probaría Valgrind . Consulte la guía de inicio rápido .
Brevemente, Valgrind instrumenta su programa para que pueda detectar varios tipos de errores en el uso de memoria asignada dinámicamente, como liberaciones dobles y escrituras más allá del final de los bloques de memoria asignados (que pueden dañar el montón). Detecta e informa los errores tan pronto como ocurren , lo que le indica directamente la causa del problema.
fuente
Tres reglas básicas:
NULL
after freeNULL
antes de liberar.NULL
al principio.La combinación de estos tres funciona bastante bien.
fuente
Puede utilizar
valgrind
para depurarlo.#include<stdio.h> #include<stdlib.h> int main() { char *x = malloc(100); free(x); free(x); return 0; } [sand@PS-CNTOS-64-S11 testbox]$ vim t1.c [sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1 [sand@PS-CNTOS-64-S11 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 [sand@PS-CNTOS-64-S11 testbox]$ [sand@PS-CNTOS-64-S11 testbox]$ vim t1.c [sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1 [sand@PS-CNTOS-64-S11 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) [sand@PS-CNTOS-64-S11 testbox]$ [sand@PS-CNTOS-64-S11 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) [sand@PS-CNTOS-64-S11 testbox]$
Una posible solución:
#include<stdio.h> #include<stdlib.h> int main() { char *x = malloc(100); free(x); x=NULL; free(x); return 0; } [sand@PS-CNTOS-64-S11 testbox]$ vim t1.c [sand@PS-CNTOS-64-S11 testbox]$ cc -g t1.c -o t1 [sand@PS-CNTOS-64-S11 testbox]$ ./t1 [sand@PS-CNTOS-64-S11 testbox]$ [sand@PS-CNTOS-64-S11 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) [sand@PS-CNTOS-64-S11 testbox]$
Consulte el blog sobre el uso de Valgrind Link
fuente
Con los compiladores modernos de C ++ puede utilizar desinfectantes para rastrear.
Ejemplo de muestra:
Mi programa:
$cat d_free.cxx #include<iostream> using namespace std; int main() { int * i = new int(); delete i; //i = NULL; delete i; }
Compile con desinfectantes de direcciones:
# g++-7.1 d_free.cxx -Wall -Werror -fsanitize=address -g
Ejecutar:
# ./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
Para obtener más información sobre los desinfectantes, puede consultar la documentación de este o este o cualquier compilador moderno de C ++ (por ejemplo, gcc, clang, etc.).
fuente
¿Estás usando punteros inteligentes como Boost
shared_ptr
? Si es así, verifique si está usando directamente el puntero sin procesar en cualquier lugar llamandoget()
. Descubrí que este es un problema bastante común.Por ejemplo, imagine un escenario en el que se pasa un puntero sin procesar (tal vez como un controlador de devolución de llamada, por ejemplo) a su código. Puede decidir asignar esto a un puntero inteligente para hacer frente al recuento de referencias, etc. Gran error: su código no posee este puntero a menos que realice una copia profunda. Cuando su código termine con el puntero inteligente, lo destruirá e intentará destruir la memoria a la que apunta, ya que cree que nadie más lo necesita, pero el código de llamada intentará eliminarlo y obtendrá un doble problema libre.
Por supuesto, ese podría no ser su problema aquí. En su forma más simple, aquí hay un ejemplo que muestra cómo puede suceder. La primera eliminación está bien, pero el compilador detecta que ya se eliminó esa memoria y causa un problema. Es por eso que asignar 0 a un puntero inmediatamente después de la eliminación es una buena idea.
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; }
Editar: cambiado
delete
adelete[]
, ya que ptr es una matriz de char.fuente
Sé que este es un hilo muy antiguo, pero es la principal búsqueda de Google para este error, y ninguna de las respuestas menciona una causa común del error.
Lo cual es cerrar un archivo que ya ha cerrado.
Si no está prestando atención y tiene dos funciones diferentes que cierran el mismo archivo, la segunda generará este error.
fuente