Estoy implementando un algoritmo polinomial de divide y vencerás para poder compararlo con una implementación de OpenCL, pero no puedo ponerme malloc
a trabajar. Cuando ejecuto el programa, asigna un montón de cosas, verifica algunas cosas y luego las envía size/2
al algoritmo. Luego, cuando vuelvo a tocar la malloc
línea, escupe esto:
malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted
La línea en cuestión es:
int *mult(int size, int *a, int *b) {
int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
fprintf(stdout, "size: %d\n", size);
out = (int *)malloc(sizeof(int) * size * 2);
}
Verifiqué el tamaño con a fprintf
, y es un número entero positivo (generalmente 50 en ese punto). Intenté llamar también malloc
con un número simple y todavía recibo el error. Estoy perplejo con lo que está pasando, y nada de Google que he encontrado hasta ahora es útil.
¿Alguna idea de qué está pasando? Estoy tratando de averiguar cómo compilar un GCC más nuevo en caso de que sea un error del compilador, pero realmente lo dudo.
Respuestas:
99,9% de probabilidad de que haya dañado la memoria (un búfer excesivo o insuficiente, escribió en un puntero después de que se liberó, llamó libre dos veces en el mismo puntero, etc.)
Ejecute su código en Valgrind para ver dónde su programa hizo algo incorrecto.
fuente
Para que comprendas mejor por qué sucede esto, me gustaría ampliar un poco la respuesta de @ r-samuel-klatchko.
Cuando llamas
malloc
, lo que realmente está sucediendo es un poco más complicado que solo darte un trozo de memoria para jugar. Debajo del capó,malloc
también guarda cierta información de limpieza sobre la memoria que le ha proporcionado (lo más importante, su tamaño), para que cuando llamefree
, sepa cosas como cuánta memoria liberar. Esta información normalmente se guarda justo antes de que le devuelva la ubicación de la memoriamalloc
. Se puede encontrar información más exhaustiva en Internet ™ , pero la idea (muy) básica es algo como esto:+------+-------------------------------------------------+ + size | malloc'd memory + +------+-------------------------------------------------+ ^-- location in pointer returned by malloc
Basándose en esto (y simplificando mucho las cosas), cuando llama
malloc
, necesita obtener un puntero a la siguiente parte de la memoria que esté disponible. Una forma muy sencilla de hacer esto es mirar el bit de memoria anterior que dio y mover lossize
bytes hacia abajo (o hacia arriba) en la memoria. Con esta implementación, terminas con tu memoria con un aspecto similar a esto después de la asignaciónp1
,p2
yp3
:Entonces, ¿qué está causando tu error?
Bueno, imagine que su código escribe erróneamente más allá de la cantidad de memoria que ha asignado (ya sea porque asignó menos de la que necesitaba, como era su problema, o porque está utilizando las condiciones de límite incorrectas en algún lugar de su código). Supongamos que su código escribe tantos datos
p2
que comienza a sobrescribir lo que está enp3
elsize
campo. La próxima vez que llamemalloc
, verá la última ubicación de memoria que devolvió, verá su campo de tamaño, se moveráp3 + size
y luego comenzará a asignar memoria desde allí.size
Sin embargo, dado que su código se ha sobrescrito , esta ubicación de memoria ya no es posterior a la memoria asignada anteriormente.No hace falta decir que esto puede causar estragos. Los implementadores de
malloc
, por lo tanto, han introducido una serie de "afirmaciones", o comprobaciones, que intentan realizar un montón de comprobaciones de cordura para detectar este (y otros problemas) si están a punto de suceder. En su caso particular, estas afirmaciones se violan y, por lo tantomalloc
, se cancelan, indicándole que su código estaba a punto de hacer algo que realmente no debería estar haciendo.Como se dijo anteriormente, esta es una simplificación excesiva, pero es suficiente para ilustrar el punto. La implementación glibc de
malloc
es de más de 5k líneas, y ha habido una cantidad sustancial de investigación sobre cómo construir buenos mecanismos de asignación de memoria dinámica, por lo que cubrirlo todo en una respuesta SO no es posible. ¡Esperamos que esto le haya dado una idea de lo que realmente está causando el problema!fuente
Mi solución alternativa al uso de Valgrind:
Estoy muy feliz porque acabo de ayudar a mi amigo a depurar un programa. Su programa tenía exactamente este problema (
malloc()
provocando un aborto), con el mismo mensaje de error de GDB.Compilé su programa usando Address Sanitizer con
gcc -Wall -g3 -fsanitize=address -o new new.c ^^^^^^^^^^^^^^^^^^
Y luego corrió
gdb new
. Cuando el programa se termina por unaSIGABRT
causa posteriormalloc()
, se imprime una gran cantidad de información útil:================================================================= ==407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8 WRITE of size 104 at 0x6060000000b4 thread T0 #0 0x7ffffe49ed19 (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19) #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59 #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96) #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679) 0x6060000000b4 is located 0 bytes to the right of 52-byte region [0x606000000080,0x6060000000b4) allocated by thread T0 here: #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50) #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55 #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209 #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
Echemos un vistazo a la salida, especialmente al seguimiento de la pila:
La primera parte dice que hay una operación de escritura no válida en
new.c:59
. Esa línea dicememset(len,0,sizeof(int*)*p); ^^^^^^^^^^^^
La segunda parte dice que se crea la memoria en la que ocurrió la mala escritura
new.c:55
. Esa línea diceif(!(len=(int*)malloc(sizeof(int)*p))){ ^^^^^^^^^^^
Eso es. Solo me tomó menos de medio minuto localizar el error que confundió a mi amigo durante unas horas. Logró localizar la falla, pero es una
malloc()
llamada posterior que falló, sin poder detectar este error en el código anterior.En resumen: pruebe con
-fsanitize=address
GCC o Clang. Puede resultar muy útil para depurar problemas de memoria.fuente
Probablemente esté sobrepasando la memoria asignada en alguna parte. entonces el sw subyacente no lo detecta hasta que llamas a malloc
Puede haber un valor de guardia golpeado que está siendo capturado por malloc.
editar ... agregué esto para la ayuda de verificación de límites
http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html
fuente
Recibí el siguiente mensaje, similar al tuyo:
Cometí un error en alguna llamada al método antes, al usar malloc. Sobrescribió erróneamente el signo de multiplicación '*' con un '+', al actualizar el factor después del operador sizeof () - al agregar un campo a la matriz de caracteres sin firmar.
Aquí está el código responsable del error en mi caso:
En otro método más tarde, utilicé malloc nuevamente y produjo el mensaje de error que se muestra arriba. La llamada fue (bastante simple):
Piense en usar el signo '+' - en la primera llamada, que conduce a errores de cálculo en combinación con la inicialización inmediata de la matriz después (sobrescribir la memoria que no se asignó a la matriz), trajo cierta confusión al mapa de memoria de malloc. Por lo tanto, la segunda llamada salió mal.
fuente
Recibimos este error porque nos olvidamos de multiplicar por sizeof (int). Tenga en cuenta que el argumento de malloc (..) es un número de bytes, no un número de palabras de máquina o lo que sea.
fuente
Tengo el mismo problema, utilicé malloc sobre n otra vez en un bucle para agregar nuevos datos de cadena de caracteres *. Me enfrenté al mismo problema, pero después de liberar el
void free()
problema de memoria asignada se solucionófuente
Estaba transfiriendo una aplicación de Visual C a gcc en Linux y tuve el mismo problema con
Moví el mismo código a una distribución de Suse (en otra computadora) y no tengo ningún problema.
Sospecho que los problemas no están en nuestros programas sino en la propia libc.
fuente