OK, ya se publicaron algunas respuestas sobre malloc.
La parte más interesante es cómo funciona gratis (y en esta dirección, malloc también se puede entender mejor).
En muchas implementaciones malloc / free, free normalmente no devuelve la memoria al sistema operativo (o al menos solo en casos excepcionales). La razón es que obtendrá huecos en su montón y, por lo tanto, puede suceder, que simplemente termine sus 2 o 4 GB de memoria virtual con huecos. Esto debe evitarse, ya que tan pronto como termine la memoria virtual, se encontrará en un gran problema. La otra razón es que el sistema operativo solo puede manejar fragmentos de memoria de un tamaño y alineación específicos. Para ser específicos: normalmente el sistema operativo solo puede manejar bloques que el administrador de memoria virtual puede manejar (con frecuencia múltiplos de 512 bytes, por ejemplo, 4KB).
Por lo tanto, devolver 40 Bytes al sistema operativo simplemente no funcionará. Entonces, ¿qué hace gratis?
Free pondrá el bloque de memoria en su propia lista de bloqueos gratuitos. Normalmente también intenta fusionar bloques adyacentes en el espacio de direcciones. La lista de bloqueo libre es solo una lista circular de fragmentos de memoria que tienen algunos datos administrativos al principio. Esta es también la razón por la cual administrar elementos de memoria muy pequeños con el estándar malloc / free no es eficiente. Cada fragmento de memoria necesita datos adicionales y con tamaños más pequeños se produce una mayor fragmentación.
La lista libre también es el primer lugar que malloc mira cuando se necesita una nueva porción de memoria. Se escanea antes de solicitar nueva memoria del sistema operativo. Cuando se encuentra un fragmento que es más grande que la memoria necesaria, se divide en dos partes. Uno se devuelve a la persona que llama, el otro se vuelve a colocar en la lista gratuita.
Hay muchas optimizaciones diferentes para este comportamiento estándar (por ejemplo, para pequeños fragmentos de memoria). Pero dado que malloc y free deben ser tan universales, el comportamiento estándar siempre es la alternativa cuando las alternativas no son utilizables. También hay optimizaciones en el manejo de la lista libre, por ejemplo, almacenar los fragmentos en listas ordenadas por tamaños. Pero todas las optimizaciones también tienen sus propias limitaciones.
¿Por qué se bloquea tu código?
La razón es que al escribir 9 caracteres (no olvide el byte nulo final) en un área de 4 caracteres, probablemente sobrescribirá los datos administrativos almacenados para otro fragmento de memoria que reside "detrás" de su fragmento de datos ( ya que estos datos se almacenan con mayor frecuencia "en frente" de los fragmentos de memoria). Cuando está libre, entonces intenta poner su parte en la lista libre, puede tocar estos datos administrativos y, por lo tanto, tropezar con un puntero sobrescrito. Esto bloqueará el sistema.
Este es un comportamiento bastante elegante. También he visto situaciones en las que un puntero desbocado en algún lugar ha sobrescrito datos en la lista libre de memoria y el sistema no se bloqueó de inmediato, sino algunas subrutinas más tarde. ¡Incluso en un sistema de complejidad media, tales problemas pueden ser muy, muy difíciles de depurar! En el único caso en el que estuve involucrado, nos tomó (un grupo más grande de desarrolladores) varios días encontrar la razón del bloqueo, ya que estaba en una ubicación totalmente diferente a la indicada por el volcado de memoria. Es como una bomba de tiempo. Ya sabes, tu próximo "gratis" o "malloc" se bloqueará, ¡pero no sabes por qué!
Esos son algunos de los peores problemas de C / C ++, y una de las razones por las cuales los punteros pueden ser tan problemáticos.