2008-11-12 13 views
6

¿Es posible liberar memoria asignada por alloca() de C explícitamente, antes de que la función actual salga? ¿Si es así, cómo?Liberación de la memoria asignada aloca

+0

¿Podría explicar su motivación? ¿Por qué querrías liberar el espacio asignado antes de volver? – Motti

Respuesta

8

Es posible, pero no hay una función escrita previamente para hacerlo. Tendría que profundizar en la implementación de alloca() de su compilador para descubrir qué está haciendo y luego escribir su propia freea(). Como cada compilador realiza alloca() de manera diferente, debe volver a escribir su freea() para cada compilador.

Pero me parece difícil de creer que valga la pena el problema. Simplemente use malloc/free si necesita liberarlo explícitamente; esas funciones suelen estar muy optimizadas. Aproveche de ellos.

+3

Una implementación portátil es "void freea (void * p) {} // Just fake it". – paxdiablo

+0

Um, no. no puede mover el puntero de pila sin dañarlo, y no puede reubicar elementos en la pila porque sus direcciones pueden almacenarse en otro lugar. La razón del trabajo libre/malloc es que tienen control total de su espacio de almacenamiento dinámico. – SquareCog

+4

Implementé alloca(), y sí, puedes hacer un freea(). No se trasladarán los elementos más de lo que alloca() lo hace: los locales con su dirección tomada son necesariamente antes del espacio asignado. No debe dejar punteros colgantes en el espacio libre de todos modos, como tampoco puede hacerlo en el espacio libre. –

1

No, porque está asignado en la pila junto con las variables locales. Si desea memoria que pueda liberar explícitamente, use una de las funciones de asignación de memoria dinámica.

No hay ningún híbrido que le permita liberar explícitamente Y tenerlo automáticamente libre al salir de la función también, al menos no en el estándar.

2

Está asignando en la pila con alloca(); Si algo más sucedió después (y no puedes controlarlo sin escribir todo en el ensamblaje), no puedes simplemente reducir la pila. Entonces, hasta que abandones el marco de pila de tu función, esto es imposible.

Esta es también la razón por la que realmente puede ensuciar las cosas si desborda el búfer asignado. Puede comenzar a sobrescribir las direcciones de código a las que su función vuelve, haciendo que salte en otro lugar, todo tipo de cosas horribles. ¡Ten cuidado!

Malloc funciona en el montón, por eso es mucho más flexible en lo que puede hacer.

8

De http://www.gnu.org/software/libc/manual/html_mono/libc.html#Variable-Size-Automatic:

La asignación de un bloque con alloca es una acción explícita; puede asignar tantos bloques como desee y calcular el tamaño en tiempo de ejecución. Pero todos los bloques se liberan cuando sale de la función desde la que se llamó a alloca, como si fueran variables automáticas declaradas en esa función. No hay forma de liberar el espacio explícitamente.

1

Esto sería útil para el estilo de paso de continuación (CPS), en lugar de una realloca.

Podría llamar a una función que asignó y manipuló una cadena en la parte superior de la pila, antes de reducir la pila a la longitud de la cadena y llamar a la siguiente función.

No hay ninguna razón conceptual por la que no podría haber un freea(), que sería un nop para cualquier cosa que no sea la entrada más alta en la pila.

2

Usando C99 puede lograr lo mismo usando Variable Length Array. Simplemente declare el VLA en un nuevo alcance; se liberará automáticamente cuando se cierre el alcance.

Por ejemplo:

int some_function(int n) { 
    // n has the desired length of the array 
    ... 
    { // new scope 
     int arr[n]; // instead of int *arr = alloca(n*sizeof(int)); 
     // do stuff with array 
    } 
    // function continues with arr deallocated 
    ... 
} 
1

Sí, pero depende de la implementación de alloca(). Una implementación razonable y simple de alloca() es que el bloque recién asignado se colocó en en la parte superior de la pila ajustando el puntero de la pila.Por lo tanto para liberar esta memoria sólo tenemos que hacer un negativo asignación (pero hay que estudiar la aplicación real de alloca()), vamos a verificar que mediante la adopción de la no portátil siguiente código de ejemplo:

#include <stdio.h> 
#include <alloca.h> 

int main() 
{ 
    unsigned long p0, p1, p2; 
    p0=(unsigned long)alloca(0); 
    p1=(unsigned long)alloca((size_t) 0x1000); 
    p2=(unsigned long)alloca((size_t)-0x1000); 
    printf("p0=%lX, p1=%lX, p2=%lX\n", p0, p1, p2); 
    return 0; 
} 

en una máquina x64 edad con sonido metálico 2.9, una salida de muestra es:

p0=7FFF2C75B89F, p1=7FFF2C75A89F, p2=7FFF2C75B89F 

por lo que sabemos de la aplicación no validar el argumento -0x1 000, de lo contrario, el valor sin signo será un entero muy grande. El puntero de pila originalmente era 0x ... B89F; ya que esta pila crece hacia arriba alloca (0x1000) por lo tanto, cambie el puntero de la pila hasta a (0x ... B89F - 0x1000) = 0x ... A89F. Después de la asignación negativa (0xA89F - (-0x1000)) el puntero de pila volvió a 0x ... B89F.

Sin embargo, con gcc 4.8.3, un ejemplo de salida es:

p0=7FFFA3E27A90, p1=7FFFA3E26A80, p2=7FFFA3E27A70 

En /usr/include/alloca.h encontramos:

#ifdef __GNUC__ 
# define alloca(size) __builtin_alloca (size) 
#endif /* GCC. */ 

por lo que sabemos que la orden interna alloca La función proporcionada por gcc 4.8.3 hizo algo similar, excepto que asignó 0x10 bytes adicionales como margen de seguridad. Al hacer una asignación negativa, aún asume que crece hacia arriba y, por lo tanto, intentó reservar 0x10 bytes adicionales (- 0x10) así que p2 = 0x ... 6A80 - (-0x1000) - 0x10 = 0x ... 7A70. Por lo tanto, ten mucho cuidado.

Cuestiones relacionadas