Tratando de usar free() para entender cómo funciona
Para entender el uso de free en el lenguaje de programación C intenté ejecutar este código en Ubuntu, pero al ejecutar el archivo EXE estoy recibiendo un error SIGABRT. ¿Por qué el programa no sale normalmente?
#include<stdio.h>
#include<stdlib.h>
int main()
{
int ret;
int *ptr;
ptr = (int *)malloc(sizeof(int)*10);
free(ptr);
ptr = &ret;
free(ptr);
return 0;
}
7 answers
Intentar liberar un puntero que no obtuviste de malloc
(o de uno de sus amigos) causa un comportamiento indefinido. Su segunda llamada free(ptr)
intenta eso.
De la especificación C, §7.22.3.3 La función free
, párrafo 2:
El
free
la función hace que el espacio apuntado porptr
no se asignarán, es decir, estarán disponibles para nuevas asignaciones. Siptr
es un puntero nulo, no se produce ninguna acción. De lo contrario, si el argumento no coincide con un puntero devuelto anteriormente por una función de gestión de memoria, o si el espacio ha sido desasignado por una llamada afree
orealloc
, el comportamiento es indefinido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-14 05:28:04
Si bien todas las respuestas de comportamiento indefinido son correctas, ver una implementación podría ser más útil.
Creo que una muy buena referencia a esto es K&R C malloc. Una explicación de cómo funciona está en "El Lenguaje de programación en C", Capítulo 8.7.
Recuerde al mirar el código de las funciones de biblioteca estándar en C que tienen una implementación y una especificación, donde la implementación podría tener un comportamiento reproducible que no es requerido por su especificación.
Esencialmente casi todas las implementaciones de malloc
tienen una lista libre donde administran regiones de memoria libres en una lista (o varias listas). La lista libre a menudo se maneja de una manera, que llamando free
en una región de memoria varias veces pondrá esta lista en un estado incorrecto.
También se puede invocar el comportamiento malicioso cuando las estructuras de datos se crean a propósito. Phrack tiene un artículo fechado sobre cómo invocar la ejecución de código al pasar memoria no válida a free
mientras corrompe al freelist.
Otras implementaciones malloc también podrían valer la pena mirar (esta es una lista incompleta de bibliotecas de asignación).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-14 16:41:06
ptr = &ret;
free(ptr);
Es lo mismo que:
free(&ret);
ret
reside en la pila, no en el montón. Intentando free()
memoria que no fue asignada (con malloc()
, etc.) en el montón causará un comportamiento indefinido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-15 09:19:07
La función free()
solo funciona para la memoria que ha sido asignada en heap
por malloc()
. No para la asignación estática, porque las asignaciones estáticas se manejan automáticamente. Aquí está el error:
int ret;
ptr = &ret;
free(ptr);
No puede hacer esto porque la memoria para ret
no está asignada en el montón. Está en la pila y solo se debe liberar la memoria del montón.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-15 05:15:43
Su segundo free(ptr)
está causando un comportamiento indefinido al intentar liberar un puntero que no asignó. También tenga en cuenta que las asignaciones estáticas se reclaman automáticamente, por lo que no necesita que las liberen.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-14 16:37:48
ptr = &ret;
free(ptr);
Aquí está tratando de liberar la memoria de la variable de pila de almacenamiento local. Según la regla, no debes liberarlo. Cuando el main () sale toda la memoria de almacenamiento local en la pila siempre se libera.
Free solo funciona con la memoria de asignación de montones.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-14 05:23:15
Hay tres áreas donde se pueden crear variables en un programa c o c++.
- las variables globales o estáticas se encuentran en ubicaciones fijas en el archivo binario ejecutable.
- las variables automáticas fuera del ámbito estático están en la pila
- malloc ed o calloc ed variables están en el montón.
Free() es la función que libera la memoria previamente asignada en el montón. Un puntero a la memoria en el montón es devuelto por malloc o funciones similares. La única manera para leer o escribir esa memoria es a través del puntero. Un puntero es una dirección, y un puntero* es el contenido apuntado a esa dirección.
En el ejemplo mostrado, hay dos variables, definidas en Main, y efectivamente estáticas, y el valor devuelto desde Main, que está en la pila. Usando el miniumum int, 16 bits, aquí hay un posible mapa de memoria. En este mapa, las instrucciones comienzan en 0, la pila comienza en algún valor distinto de cero, (comienzo de la pila-bos) y crece aumentando, y un heap comienza en la dirección máxima (...FFFF, también conocido como -1) y crece por decrememeting:
(Recuerde, MIN_INT es -32768, MAX_INT es 32767... la especificación garantiza solo 16 bits, firmados)
Cada byte tiene una dirección que es 'n' bits de ancho-16, 32 o 64 bits, típicamente
-1. (inicio de montón, por ejemplo, 16 bits addr: 0xFFFF, 32 bits addr: 0xFFFFFFFF o 64 bits addr: 0xffffffffffffff)
-2. (1ra ubicación abajo del principio del montón. 0x...FFFE) rpp [9], uno tiempo
-3. (2da ubicación hacia abajo desde el comienzo del montón. 0x...FFFD)
-4. (3ra ubicación abajo del principio del montón. 0x...FFFC) rpp[8 ], a la vez
[snip]
-17. (ubicación 16 desde el comienzo del montón. 0x...FFEF)
-18. (ubicación 17 desde el comienzo del montón. 0x...FFEE) rpp [1], al mismo tiempo
-19. (ubicación 18 desde el comienzo del montón. 0x...FFED)
-20 (ubicación 19 desde el comienzo del montón. 0x...FFEC) rpp [0 ], al mismo tiempo
-21. (parte superior del montón, 10 X 16 bits ints hacia abajo desde el principio del montón. 0x...FFEB), al mismo tiempo
: Una amplia gama de direcciones en máquinas de 32 o 64 bits... :
Tos: ( Parte superior de la pila 0x...tos)
Bos + (sizeof (int ) - 1) Fin de int devuelto desde Main ()
Bos: (principio de pila: sobre los datos estáticos ) Inicio de int devuelto desde Mail ()
Togs: (parte superior de global/estático) Final de "ptr"
: (el tamaño de un puntero es el ancho de bus de direcciones... lo que sea necesario)
Togs - (n-1): (top of global/static - (sizeof (int* ) - 1)) inicio de "ptr"
(togs-n): Fin de"ret"
(togs-n)-1: inicio de "ret"
(cualquier cosa global que el compilador agregue para sí mismo, el depurador, etc.)
(fin del código del programa)
(inicio del código del programa)
(parte superior del código no del programa)
0 (inicio de código no-programa, 0x...0000 )
En tiempo de ejecución, "ptr" y "ret" son probablemente tanto inicio en '0', ya que son valores fijos, estáticos, leídos del archivo del que proviene el binario ejecutable.
A medida que se ejecuta el programa, el valor de "ptr" cambia, primero, para apuntar al montón, en la matriz malloc'ed de 10 ints: "0x...FFEC "
La llamada a free() no cambia el valor de ptr, sigue siendo "0x...FFEC" Free ' ing " 0x...FFEC " es de fiar y funciona sin nada divertido.
La asignación "ptr = & ret" establece un nuevo valor en "ptr", "(togs-n) -1" , el inicio de "ret".
Free ' ing "(togs-n)-1" causa un bloqueo inmediato porque "free" comprueba el valor de "(togs-n)-1" y NO está en el rango válido para una dirección de montón.
"ret" permanece en blanco, nunca se establece, pero como es global/estático, permanece en lo que era cuando el enlazador lo escribió en el disco.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-15 00:43:41