direcciones - ¿Por qué el uso de alloca() no se considera una buena práctica?
stack memory (24)
alloca()
asigna memoria desde Stack en lugar de heap, lo que es un caso en malloc()
. Entonces, cuando vuelvo de la rutina se libera la memoria. Entonces, en realidad esto resuelve mi problema de liberar la memoria asignada dinámicamente. La liberación de la memoria asignada a través de malloc()
es un gran dolor de cabeza y, si de alguna manera se pierde, se producen problemas de memoria de todo tipo.
¿Por qué se desaconseja el uso de alloca()
a pesar de las características anteriores?
Todavía se desalienta el uso de la coca, ¿por qué?
No percibo tal consenso. Muchos pros fuertes; algunos contras
- C99 proporciona matrices de longitud variable, que a menudo se usarían preferentemente como la notación más coherente con las matrices de longitud fija y en general intuitiva
- muchos sistemas tienen menos espacio total de memoria / direcciones disponibles para la pila que para el montón, lo que hace que el programa sea un poco más susceptible al agotamiento de la memoria (a través del desbordamiento de la pila): esto puede verse como algo bueno o malo - uno Las razones por las que la pila no crece automáticamente como lo hace el montón es evitar que los programas fuera de control tengan tanto impacto adverso en toda la máquina.
- cuando se usa en un ámbito más local (como un
while
ofor
bucle) o en varios ámbitos, la memoria se acumula por iteración / alcance y no se libera hasta que la función sale: esto contrasta con las variables normales definidas en el alcance de una estructura de control (por ejemplo,for {int i = 0; i < 2; ++i) { X }
acumularía la memoriaalloca
solicitada en X, pero la memoria para una matriz de tamaño fijo se reciclaría por iteración). - los compiladores modernos normalmente no tienen funciones en
inline
que llamanalloca
, pero si los fuerza, entonces laalloca
sucederá en el contexto de los que llaman (es decir, la pila no se liberará hasta que el que llama vuelva) - Hace mucho tiempo,
alloca
pasó de una función / hack no portátil a una extensión estandarizada, pero puede persistir alguna percepción negativa - el tiempo de vida está vinculado al alcance de la función, que puede o no adaptarse al programador mejor que el control explícito de
malloc
- tener que usar
malloc
alienta a pensar en la desasignación, si se administra a través de una función de envoltura (por ejemplo,WonderfulObject_DestructorFree(ptr)
), la función proporciona un punto para las operaciones de limpieza de la implementación (como cerrar descriptores de archivos, liberar punteros internos o realizar algún registro) sin cambios explícitos en el código del cliente: a veces es un buen modelo para adoptar constantemente- en este estilo de programación pseudo-OO, es natural querer algo como
WonderfulObject* p = WonderfulObject_AllocConstructor();
- eso es posible cuando el "constructor" es una función que devuelve memoria malloced (ya que la memoria permanece asignada después de que la función devuelve el valor para ser almacenado enp
), pero no si el "constructor" usaalloca
- una versión macro de
WonderfulObject_AllocConstructor
podría lograr esto, pero "las macros son malvadas" en el sentido de que pueden entrar en conflicto entre sí y con el código no macro y crear sustituciones no deseadas y los consiguientes problemas difíciles de diagnosticar
- una versión macro de
- las operaciones
free
faltantes pueden ser detectadas por ValGrind, Purify, etc., pero las llamadas faltantes del "destructor" no siempre pueden detectarse en absoluto - un beneficio muy tenue en términos de cumplimiento del uso previsto; algunas implementaciones dealloca()
(como las GCC) usan una macro en línea paraalloca()
, por lo que la sustitución en tiempo de ejecución de una biblioteca de diagnóstico de uso de memoria no es posible como esmalloc
/realloc
/free
(por ejemplo, cerca eléctrica)
- en este estilo de programación pseudo-OO, es natural querer algo como
- Algunas implementaciones tienen problemas sutiles: por ejemplo, de la página de manual de Linux:
En muchos sistemas, alloca () no se puede usar dentro de la lista de argumentos de una llamada a función, porque el espacio de pila reservado por alloca () aparecería en la pila en medio del espacio para los argumentos de función.
Sé que esta pregunta está etiquetada como C, pero como programador en C ++ pensé que usaría C ++ para ilustrar la utilidad potencial de alloca
: el siguiente código (y aquí en ideone ) crea un vector que rastrea tipos polimórficos de diferentes tamaños que se asignan por pila ( con el tiempo de vida vinculado a la función de retorno) en lugar de montón asignado.
#include <alloca.h>
#include <iostream>
#include <vector>
struct Base
{
virtual ~Base() { }
virtual int to_int() const = 0;
};
struct Integer : Base
{
Integer(int n) : n_(n) { }
int to_int() const { return n_; }
int n_;
};
struct Double : Base
{
Double(double n) : n_(n) { }
int to_int() const { return -n_; }
double n_;
};
inline Base* factory(double d) __attribute__((always_inline));
inline Base* factory(double d)
{
if ((double)(int)d != d)
return new (alloca(sizeof(Double))) Double(d);
else
return new (alloca(sizeof(Integer))) Integer(d);
}
int main()
{
std::vector<Base*> numbers;
numbers.push_back(factory(29.3));
numbers.push_back(factory(29));
numbers.push_back(factory(7.1));
numbers.push_back(factory(2));
numbers.push_back(factory(231.0));
for (std::vector<Base*>::const_iterator i = numbers.begin();
i != numbers.end(); ++i)
{
std::cout << *i << '' '' << (*i)->to_int() << ''/n'';
(*i)->~Base(); // optionally / else Undefined Behaviour iff the
// program depends on side effects of destructor
}
}
Antigua pregunta pero nadie mencionó que debería ser reemplazada por matrices de longitud variable.
char arr[size];
en lugar de
char *arr=alloca(size);
Está en el estándar C99 y existió como extensión del compilador en muchos compiladores.
Como se señaló en esta publicación de grupos de noticias , hay algunas razones por las que usar alloca
puede considerarse difícil y peligroso:
- No todos los compiladores soportan
alloca
. - Algunos compiladores interpretan el comportamiento deseado de
alloca
dealloca
diferente, por lo que la portabilidad no está garantizada incluso entre los compiladores que la soportan. - Algunas implementaciones son buggy.
Este es el por qué:
char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;
No es que alguien escriba este código, pero el argumento del tamaño que está pasando a alloca
casi seguro que proviene de algún tipo de entrada, que podría apuntar maliciosamente a que su programa alloca
algo tan grande como ese. Después de todo, si el tamaño no se basa en la entrada o no tiene la posibilidad de ser grande, ¿por qué no acaba de declarar un búfer local pequeño de tamaño fijo?
Prácticamente todos los códigos que utilizan alloca
y / o C99 tienen errores graves que pueden provocar fallos (si tienes suerte) o un compromiso de privilegios (si no tienes tanta suerte).
La respuesta está allí mismo en la página del man
(al menos en Linux):
VALOR DEVUELTO La función alloca () devuelve un puntero al principio del espacio asignado. Si la asignación provoca un desbordamiento de pila, el comportamiento del programa no está definido.
Lo que no quiere decir que nunca se debe usar. Uno de los proyectos de OSS en los que trabajo lo usa ampliamente, y mientras no lo esté abusando ( alloca
valores enormes), está bien. Una vez que pase la marca de "unos pocos cientos de bytes", es el momento de usar malloc
y sus amigos. Es posible que todavía obtengas fallas en la asignación, pero al menos tendrás alguna indicación de la falla en lugar de simplemente volar la pila.
Lamentablemente, la alloca()
verdaderamente impresionante alloca()
falta en el casi impresionante tcc. Gcc tiene alloca()
.
Siembra la semilla de su propia destrucción. Con el retorno como el destructor.
Al igual que
malloc()
, devuelve un puntero no válido en caso de falla que se segfault en los sistemas modernos con una MMU (y es de esperar que reinicie aquellos sin).A diferencia de las variables automáticas, puede especificar el tamaño en tiempo de ejecución.
Funciona bien con la recursividad. Puede usar variables estáticas para lograr algo similar a la recursión de la cola y usar solo algunos otros para pasar la información a cada iteración.
Si presiona demasiado, tiene la seguridad de una falla de seguridad (si tiene una MMU).
Tenga en cuenta que malloc()
no ofrece más, ya que devuelve NULL (que también se segfault si se asigna) cuando el sistema está fuera de la memoria. Es decir, todo lo que puede hacer es rescatar o simplemente tratar de asignarlo de cualquier manera.
Para usar malloc()
uso globals y les asigno NULL. Si el puntero no es NULL, lo libero antes de usar malloc()
.
También puede usar realloc()
como caso general si desea copiar cualquier información existente. realloc()
marcar el puntero antes de calcular si va a copiar o concatenar después del realloc()
.
Muchas respuestas interesantes a esta pregunta "antigua", incluso algunas respuestas relativamente nuevas, pero no encontré ninguna que mencione esto ...
Cuando se usa correctamente y con cuidado, el uso consistente de
alloca()
(tal vez en toda la aplicación) para manejar pequeñas asignaciones de longitud variable (o VLA C99, cuando estén disponibles) puede llevar a un crecimiento de pila total más bajo que una implementación equivalente que utilice matrices locales de gran tamaño de longitud fija. Así quealloca()
puede ser bueno para tu pila si lo usas con cuidado.
Encontré esa cita en ... OK, hice esa cita. Pero realmente, piénsalo ...
@j_random_hacker tiene mucha razón en sus comentarios sobre otras respuestas: Evitar el uso de alloca()
en favor de arreglos locales de gran tamaño no hace que su programa sea más seguro frente a los desbordamientos de pila (a menos que su compilador sea lo suficientemente antiguo como para permitir la incorporación de funciones que utilizan alloca()
en cuyo caso debería actualizar, o a menos que use alloca()
dentro de los bucles, en cuyo caso debería ... no usar alloca()
dentro de los bucles).
He trabajado en entornos de escritorio / servidor y sistemas embebidos. Una gran cantidad de sistemas integrados no utilizan un montón (ni siquiera se vinculan con la compatibilidad), por razones que incluyen la percepción de que la memoria asignada dinámicamente es mala debido a los riesgos de pérdidas de memoria en una aplicación que nunca cada vez que se reinicia durante años, o la justificación más razonable de que la memoria dinámica es peligrosa porque no se puede saber con certeza que una aplicación nunca fragmentará su montón hasta el punto de agotamiento de la memoria falsa. Así que a los programadores integrados les quedan pocas alternativas.
alloca()
(o VLA) puede ser la herramienta adecuada para el trabajo.
He visto una y otra vez que un programador hace que un búfer asignado a la pila sea "lo suficientemente grande como para manejar cualquier posible caso". En un árbol de llamadas profundamente anidado, el uso repetido de ese patrón (anti -?) Conduce a un uso de pila exagerado. (Imagine un árbol de llamadas de 20 niveles de profundidad, donde en cada nivel por diferentes razones, la función sobre asigna ciegamente un búfer de 1024 bytes "solo para estar seguro" cuando generalmente solo usará 16 o menos de ellos, y solo en muy los casos raros pueden usar más.) Una alternativa es usar alloca()
o VLA y asignar solo el espacio de pila que su función necesita, para evitar cargar innecesariamente la pila. Es de esperar que cuando una función en el árbol de llamadas necesite una asignación mayor a la normal, otras en el árbol de llamadas sigan usando sus pequeñas asignaciones normales, y el uso general de la pila de aplicaciones sea significativamente menor que si todas las funciones asignaran un búfer local ciego .
Pero si eliges usar alloca()
...
Según las otras respuestas en esta página, parece que los VLA deberían ser seguros (no componen las asignaciones de pila si se llaman desde dentro de un bucle), pero si está usando alloca()
, tenga cuidado de no usarlo dentro de un bucle y asegúrese de que su función no pueda estar en línea si existe alguna posibilidad de que se pueda llamar dentro del bucle de otra función.
Todas las otras respuestas son correctas. Sin embargo, si lo que quiere asignar con alloca()
es razonablemente pequeño, creo que es una buena técnica que es más rápida y conveniente que usar malloc()
o de otra manera.
En otras palabras, la alloca( 0x00ffffff )
es peligrosa y es probable que cause desbordamiento, exactamente tanto como char hugeArray[ 0x00ffffff ];
es. Sé prudente y razonable y estarás bien.
Todo el mundo ya ha señalado lo importante que es el comportamiento potencialmente indefinido de un desbordamiento de pila, pero debo mencionar que el entorno de Windows tiene un gran mecanismo para detectar esto utilizando excepciones estructuradas (SEH) y páginas de protección. Dado que la pila solo crece según sea necesario, estas páginas de protección residen en áreas que no están asignadas. Si los asigna (desbordando la pila) se lanza una excepción.
Puede capturar esta excepción SEH y llamar a _resetstkoflw para restablecer la pila y continuar en su camino alegre. No es ideal, pero es otro mecanismo para al menos saber que algo salió mal cuando las cosas golpean el ventilador. * nix podría tener algo similar que no conozco.
Recomiendo limitar el tamaño máximo de asignación envolviendo la asignación y rastreando internamente. Si fuera realmente duro al respecto, podría lanzar algunos centinelas de alcance en la parte superior de su función para rastrear cualquier asignación de asignación en el alcance de la función y verifique que la cantidad máxima permitida para su proyecto.
Además, además de no permitir pérdidas de memoria, la asignación no provoca la fragmentación de la memoria, lo cual es muy importante. No creo que la aloca sea una mala práctica si la usas inteligentemente, lo cual es básicamente cierto para todo. :-)
Un lugar donde alloca()
es especialmente peligroso que malloc()
es el núcleo: el núcleo de un sistema operativo típico tiene un espacio de pila de tamaño fijo codificado en uno de sus encabezados; no es tan flexible como la pila de una aplicación. Hacer una llamada a alloca()
con un tamaño injustificado puede hacer que el núcleo se bloquee. Ciertos compiladores advierten el uso de alloca()
(e incluso VLAs) en ciertas opciones que deberían alloca()
al compilar un código de kernel. Aquí, es mejor asignar memoria en el montón que no está arreglado por un disco duro. Límite codificado.
Un problema es que no es estándar, aunque es ampliamente compatible. En igualdad de condiciones, siempre usaría una función estándar en lugar de una extensión de compilador común.
Uno de los errores más memorables que tuve fue hacer con una función en línea que usaba alloca
. Se manifestó como un desbordamiento de pila (porque se asigna en la pila) en puntos aleatorios de la ejecución del programa.
En el archivo de cabecera:
void DoSomething() {
wchar_t* pStr = alloca(100);
//......
}
En el archivo de implementación:
void Process() {
for (i = 0; i < 1000000; i++) {
DoSomething();
}
}
Entonces, lo que sucedió fue la función DoSomething
línea del compilador y todas las asignaciones de pila ocurrieron dentro de la función Process()
y, por lo tanto, aumentaron la pila. En mi defensa (y no fui el que encontró el problema, tuve que irme y llorar a uno de los desarrolladores principales cuando no podía solucionarlo), no era una alloca
directa, era una cadena ATL. macros de conversión.
Así que la lección es: no utilice la alloca
en funciones que cree que podrían estar en línea.
alloca () es muy útil si no puede usar una variable local estándar porque su tamaño tendría que determinarse en tiempo de ejecución y puede garantizar absolutamente que el puntero que obtiene de alloca () NUNCA se usará después de que regrese esta función .
Puedes estar bastante seguro si
- No devuelva el puntero, o cualquier cosa que lo contenga.
- no almacene el puntero en ninguna estructura asignada en el montón
- No dejes que ningún otro hilo use el puntero.
El verdadero peligro proviene de la posibilidad de que alguien más viole estas condiciones más adelante. Teniendo esto en cuenta, es genial para pasar buffers a funciones que le dan formato al texto :)
alloca () es agradable y eficiente ... pero también está profundamente roto.
- comportamiento de ámbito roto (ámbito de función en lugar de ámbito de bloque)
- uso inconsistente con malloc (el puntero de alloca () -ted no debe liberarse, de ahora en adelante usted debe rastrear de dónde vienen los punteros a free () solo aquellos que obtuvo con malloc () )
- mal comportamiento cuando también se usa inlining (el alcance a veces va a la función de la persona que llama, dependiendo de si la persona que llama está en línea o no).
- sin verificación de límite de pila
- comportamiento indefinido en caso de falla (no devuelve NULL como malloc ... y lo que significa falla, ya que de todos modos no comprueba los límites de la pila ...)
- no ansi standard
En la mayoría de los casos, puede reemplazarlo utilizando variables locales y mayor tamaño. Si se usa para objetos grandes, ponerlos en el montón suele ser una idea más segura.
Si realmente lo necesitas, puedes usar VLA (no vla en C ++, demasiado malo). Son mucho mejores que alloca () en relación con el comportamiento y la consistencia del alcance. Como lo veo, VLA es una especie de alianza hecha correctamente.
Por supuesto, una estructura o matriz local que use un mayoritario del espacio necesario es aún mejor, y si no tiene una asignación de pila mayor con un simple malloc () es probable que esté en su sano juicio. No veo ningún caso de uso sensato en el que realmente necesite alloca () o VLA.
En mi humilde opinión, la aloca se considera una mala práctica porque todos temen agotar el límite de tamaño de pila.
Aprendí mucho leyendo este hilo y algunos otros enlaces:
- https://unix.stackexchange.com/questions/63742/what-is-automatic-stack-expansion
- Límite de asignación de pila para programas en una máquina Linux de 32 bits
- ulimit -s
Utilizo alloca principalmente para hacer que mis archivos C simples puedan compilarse en msvc y gcc sin ningún cambio, estilo C89, no #ifdef _MSC_VER, etc.
Gracias ! Este hilo me hizo registrarme en este sitio :)
La función de asignación es excelente y todos los detractores simplemente están propagando FUD.
void foo()
{
int x = 50000;
char array[x];
char *parray = (char *)alloca(x);
}
La matriz y la matriz son EXACTAMENTE iguales con EXACTAMENTE los mismos riesgos. Decir que uno es mejor que otro es una elección sintáctica, no técnica.
En cuanto a la elección de las variables de pila frente a las variables de pila, hay MUCHAS ventajas para los programas de ejecución prolongada que usan pila sobre pila para variables con tiempos de vida dentro del alcance. Evita la fragmentación del almacenamiento dinámico y puede evitar que su espacio de proceso crezca con espacio de almacenamiento no utilizado (inutilizable). No necesitas limpiarlo. Puede controlar la asignación de pila en el proceso.
¿Por qué es esto malo?
No creo que nadie haya mencionado esto: el uso de alloca en una función dificultará o deshabilitará algunas optimizaciones que de otro modo podrían aplicarse en la función, ya que el compilador no puede saber el tamaño del marco de pila de la función.
Por ejemplo, una optimización común de los compiladores de C es eliminar el uso del puntero de marco dentro de una función, los accesos de marco se realizan en relación con el puntero de pila; así que hay un registro más para uso general. Pero si se llama a alloca dentro de la función, la diferencia entre sp y fp será desconocida para parte de la función, por lo que esta optimización no se puede realizar.
Dada la rareza de su uso, y su estado sombrío como una función estándar, los diseñadores del compilador posiblemente deshabiliten cualquier optimización que pueda causar problemas con alloca, si se requiere más que un pequeño esfuerzo para que funcione con alloca.
No es muy bonito, pero si el rendimiento realmente importa, podría preasignar algo de espacio en la pila.
Si ya tiene el tamaño máximo de la memoria que bloquea su necesidad y desea mantener las comprobaciones de desbordamiento, podría hacer algo como:
void f()
{
char array_on_stack[ MAX_BYTES_TO_ALLOCATE ];
SomeType *p = (SomeType *)array;
(...)
}
En mi opinión, alloca (), cuando esté disponible, debe usarse solo de manera restringida. Al igual que el uso de "goto", un gran número de personas razonables tienen una fuerte aversión no solo al uso, sino también a la existencia de aloca ().
Para uso integrado, donde se conoce el tamaño de la pila y se pueden imponer límites mediante convenciones y análisis sobre el tamaño de la asignación, y donde el compilador no se puede actualizar para admitir C99 +, el uso de alloca () está bien, y he estado Se sabe que lo usan.
Cuando están disponibles, los VLA pueden tener algunas ventajas sobre alloca (): el compilador puede generar verificaciones de límite de pila que detectarán el acceso fuera de los límites cuando se use el acceso de estilo de matriz (no sé si algún compilador hace esto, pero puede se realizará), y el análisis del código puede determinar si las expresiones de acceso a la matriz están correctamente delimitadas. Tenga en cuenta que, en algunos entornos de programación, como automotriz, equipo médico y aviónica, este análisis debe realizarse incluso para matrices de tamaño fijo, tanto de asignación automática (en la pila) como de asignación estática (global o local).
En las arquitecturas que almacenan datos y direcciones de retorno / punteros de cuadro en la pila (por lo que sé, eso es todo), cualquier variable asignada a la pila puede ser peligrosa porque la dirección de la variable se puede tomar, y los valores de entrada sin marcar podrían permitir todo tipo de travesuras
La portabilidad es una preocupación menor en el espacio incrustado, sin embargo, es un buen argumento en contra del uso de alloca () fuera de circunstancias cuidadosamente controladas.
Fuera del espacio incrustado, he usado alloca (), principalmente dentro de las funciones de registro y formateo para mejorar la eficiencia, y en un escáner léxico no recursivo, donde las estructuras temporales (asignadas usando alloca () se crean durante la tokenización y la clasificación, luego una persistente el objeto (asignado a través de malloc ()) se llena antes de que se devuelva la función. El uso de alloca () para las estructuras temporales más pequeñas reduce considerablemente la fragmentación cuando se asigna el objeto persistente.
En realidad, alloca no está garantizado para usar la pila. De hecho, la implementación de alloca de gcc-2.95 asigna memoria del montón usando malloc. Además, esa implementación tiene errores, puede provocar una pérdida de memoria y algún comportamiento inesperado si lo llama dentro de un bloque con un uso adicional de goto. No, para decir que nunca se debe usar, pero a veces la alloca conlleva más gastos de los que se libera.
La mayoría de las respuestas aquí pasan por alto el punto: hay una razón por la que el uso _alloca()
es potencialmente peor que simplemente almacenar objetos grandes en la pila.
La principal diferencia entre el almacenamiento automático y _alloca()
es que este último tiene un problema adicional (grave): el bloque asignado no está controlado por el compilador , por lo que el compilador no tiene forma de optimizarlo o reciclarlo.
Comparar:
while (condition) {
char buffer[0x100]; // Chill.
/* ... */
}
con:
while (condition) {
char* buffer = _alloca(0x100); // Bad!
/* ... */
}
El problema con este último debe ser obvio.
Los procesos solo tienen una cantidad limitada de espacio de pila disponible, mucho menos que la cantidad de memoria disponible malloc()
.
Al usarlo alloca()
, aumentas considerablemente tus posibilidades de obtener un error de desbordamiento de pila (si tienes suerte, o un fallo inexplicable si no lo eres).
Si accidentalmente escribe más allá del bloque asignado con alloca
(debido a un desbordamiento del búfer, por ejemplo), sobrescribirá la dirección de retorno de su función, porque esa se encuentra "arriba" en la pila, es decir, después del bloque asignado.
La consecuencia de esto es doble:
El programa se bloqueará espectacularmente y será imposible decir por qué o dónde se estrelló (la pila probablemente se desenrollará en una dirección aleatoria debido al puntero del cuadro sobrescrito).
Hace que el desbordamiento del búfer sea mucho más peligroso, ya que un usuario malintencionado puede crear una carga útil especial que se colocará en la pila y, por lo tanto, puede terminar ejecutándose.
Por el contrario, si escribe más allá de un bloque en el montón, "simplemente" obtendrá corrupción del montón. El programa probablemente terminará inesperadamente pero desenrollará la pila correctamente, lo que reducirá la posibilidad de ejecución de código malicioso.
Un escollo con alloca
es que lo longjmp
rebobina.
Es decir, si guarda un contexto con setjmp
, luego alloca
algo de memoria, luego longjmp
al contexto, puede perder la alloca
memoria (sin ningún tipo de aviso). El puntero de la pila vuelve a estar donde estaba y, por lo tanto, la memoria ya no está reservada; Si llamas a una función o haces otra función alloca
, golpearás el original alloca
.
Para aclarar, a lo que me refiero específicamente aquí es a una situación en la que longjmp
no vuelve a salir de la función en la que alloca
tuvo lugar. Más bien, una función guarda el contexto con setjmp
; luego asigna memoria con alloca
y finalmente se lleva a cabo un longjmp en ese contexto. La alloca
memoria de esa función no está del todo liberada; sólo toda la memoria que asignó desde el setjmp
. Por supuesto, estoy hablando de un comportamiento observado; No se documenta tal requisito de ninguno alloca
que yo sepa.
El enfoque en la documentación suele ser el concepto de que la alloca
memoria está asociada con la activación de una función , no con ningún bloque; que múltiples invocaciones de alloca
solo tomar más memoria de pila que se libera cuando finaliza la función. No tan; La memoria está realmente asociada con el contexto del procedimiento. Cuando el contexto se restaura longjmp
, también lo es el alloca
estado anterior . Es una consecuencia de que el registro del puntero de pila se usa para la asignación y también (necesariamente) guardado y restaurado en el archivo jmp_buf
.
Por cierto, esto, si funciona de esa manera, proporciona un mecanismo plausible para liberar deliberadamente la memoria asignada alloca
.
Me he encontrado con esto como la causa raíz de un error.