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 llame free
, sepa cosas como cuánta memoria liberar. Esta información normalmente se guarda justo antes de que le devuelva la ubicación de la memoria malloc
. 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 los size
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ón p1
, p2
y p3
:
+------+----------------+------+--------------------+------+----------+
+ size | | size | | size | +
+------+----------------+------+--------------------+------+----------+
^- p1 ^- p2 ^- p3
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á en p3
el size
campo. La próxima vez que llame malloc
, 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 tanto malloc
, 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!