Pregunta

alloca() asigna memoria en la pila, en lugar de en el montón, como en el caso de malloc().Así que, cuando regrese de la rutina en la que se libera la memoria.Así que, en realidad, esto soluciona mi problema de liberar memoria asignada dinámicamente.Liberación de memoria asignada a través de malloc() es un gran dolor de cabeza y si de alguna manera no se genera todo tipo de problemas de memoria.

¿Por qué el uso de alloca() desalentado a pesar de las características anteriores?

¿Fue útil?

Solución

La respuesta está justo en el man página (al menos en Linux):

VALOR DE RETORNO La ubica() la función devuelve un puntero al principio de la espacio asignado.Si el la asignación de causas desbordamiento de la pila, el programa de comportamiento es indefinido.

Lo cual no quiere decir que nunca se debe utilizar.Uno de los sistemas operativos de los proyectos de trabajo en usa extensamente, y mientras no estás abusando de ella (alloca'ing enorme valores), está bien.Una vez que se pasa de la "pocos cientos de bytes" de la marca, es el momento de utilizar malloc y amigos, en su lugar.Usted todavía puede obtener la asignación de fallos, pero al menos tendrás una idea de que el fracaso en lugar de simplemente soplando fuera de la pila.

Otros consejos

Uno de los más memorables errores que yo tenía era que hacer con una función en línea que utiliza alloca.Éste se manifiesta como un desbordamiento de pila (porque asigna en la pila) en puntos aleatorios de la ejecución del programa.

En el archivo de encabezado:

void DoSomething() {
   wchar_t* pStr = alloca(100);
   //......
}

En el archivo de implementación:

void Process() {
   for (i = 0; i < 1000000; i++) {
     DoSomething();
   }
}

Lo que pasó fue que el compilador en línea DoSomething función y todas las asignaciones de pila se fueron sucediendo en el interior de Process() función y, por tanto soplado de la pila.En mi defensa (y yo no era la persona que encontró el problema;Tuve que ir y llorar a uno de los desarrolladores senior cuando no pude solucionarlo), no era recta alloca, fue uno de ATL de conversión de cadena de macros.

Así que la lección es no utilizar alloca en las funciones que usted piensa que podría estar en línea.

Antigua pregunta, pero nadie mencionó que debería reemplazarse por matrices de longitud variable.

char arr[size];

en lugar de

char *arr=alloca(size);

Está en el C99 estándar y existió como extensión del compilador en muchos compiladores.

alloca () es muy útil si no puede usar una variable local estándar porque su tamaño debería determinarse en tiempo de ejecución y puede garantiza absolutamente que el puntero que obtiene de alloca () NUNCA se usará después de que esta función regrese .

Puedes estar bastante seguro si

  • no devuelve el puntero ni nada que lo contenga.
  • no almacene el puntero en ninguna estructura asignada en el montón
  • no permita que ningún otro hilo use el puntero

El peligro real proviene de la posibilidad de que alguien más viole estas condiciones en algún momento posterior. Con eso en mente, es excelente para pasar buffers a funciones que les dan formato de texto :)

Como se señaló en esta publicación de grupo de noticias , hay algunas razones por qué usar alloca puede considerarse difícil y peligroso:

  • No todos los compiladores admiten <=>.
  • Algunos compiladores interpretan el comportamiento previsto de <=> de manera diferente, por lo que la portabilidad no está garantizada incluso entre los compiladores que lo admiten.
  • Algunas implementaciones tienen errores.

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.

  

todavía se desaconseja el uso de alloca, ¿por qué?

No percibo tal consenso. Muchos profesionales fuertes; algunas desventajas:

  • C99 proporciona matrices de longitud variable, que a menudo se utilizarían preferentemente como la notación más coherente con las matrices de longitud fija y en general intuitiva
  • muchos sistemas tienen menos espacio de memoria / dirección general disponible para la pila que para el montón, lo que hace que el programa sea ligeramente más susceptible al agotamiento de la memoria (a través del desbordamiento de la pila): esto puede verse como bueno o malo - una de las razones por las que la pila no crece automáticamente de la forma en que lo hace el montón es para evitar que los programas fuera de control tengan el mismo impacto adverso en toda la máquina
  • cuando se utiliza en un ámbito más local (como un bucle while o for) o en varios ámbitos, la memoria se acumula por iteración / ámbito y no se libera hasta que sale la función: esto contrasta con las variables normales definidas dentro del alcance de una estructura de control (por ejemplo, for {int i = 0; i < 2; ++i) { X } acumularía alloca - memoria solicitada en X, pero la memoria para una matriz de tamaño fijo se reciclaría por iteración).
  • los compiladores modernos no suelen inline funciones que llaman a malloc, pero si los fuerza, WonderfulObject_DestructorFree(ptr) sucederá en el contexto de las personas que llaman (es decir, la pila no se liberará hasta que la persona que llama regrese)
  • hace mucho tiempo WonderfulObject* p = WonderfulObject_AllocConstructor(); pasó de una función / pirateo no portátil a una extensión estandarizada, pero puede persistir cierta percepción negativa
  • la vida útil está vinculada al alcance de la función, que puede o no adaptarse mejor al programador que el control explícito de p
  • tener que usar WonderfulObject_AllocConstructor alienta a pensar en la desasignación: si se gestiona mediante una función de contenedor (por ejemplo, free), la función proporciona un punto para las operaciones de limpieza de implementación (como cerrar descriptores de archivos, liberar punteros internos o haciendo algunos registros) sin cambios explícitos en el código del cliente: a veces es un buen modelo para adoptar consistentemente
    • en este estilo de programación pseudo-OO, es natural querer algo como alloca(), eso es posible cuando el " constructor " es una función que devuelve realloc - memoria ed (ya que la memoria permanece asignada después de que la función devuelve el valor que se almacenará en <=>), pero no si " constructor " utiliza <=>
      • una versión macro de <=> podría lograr esto, pero " las macros son malvadas " en el sentido de que pueden entrar en conflicto entre sí y con código no macro y crear sustituciones no deseadas y los consiguientes problemas difíciles de diagnosticar
    • faltan <=> operaciones pueden ser detectadas por ValGrind, Purify, etc. pero faltan " destructor " las llamadas no siempre se pueden detectar en absoluto: un beneficio muy tenue en términos de cumplimiento del uso previsto; algunas implementaciones <=> (como las de GCC) usan una macro en línea para <=>, por lo que la sustitución en tiempo de ejecución de una biblioteca de diagnóstico de uso de memoria no es posible de la forma en que lo es para <=> / <=> / <=> ( por ejemplo, cerca eléctrica)
  • algunas implementaciones tienen problemas sutiles: por ejemplo, desde 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 el medio del espacio para los argumentos de función.

  •   
  

Sé que esta pregunta está etiquetada con C, pero como programador de C ++ pensé que usaría C ++ para ilustrar la utilidad potencial de <=>: el código a continuación (y aquí en ideone ) crea un vector que rastrea tipos polimórficos de diferentes tamaños que están asignados en pila (con vida útil vinculada al retorno de la función) en lugar del 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
    }
}

Todas las otras respuestas son correctas. Sin embargo, si lo que desea asignar usando alloca() es razonablemente pequeño, creo que es una buena técnica que es más rápida y más conveniente que usar malloc() o no.

En otras palabras, alloca( 0x00ffffff ) es peligroso y puede causar desbordamiento, exactamente tanto como char hugeArray[ 0x00ffffff ];. Sea precavido y razonable y estará bien.

Todos ya han señalado lo importante que es el posible comportamiento 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 a ellos (desbordando la pila) se genera una excepción.

Puede capturar esta excepción SEH y llamar a _resetstkoflw para restablecer la pila y continuar felizmente. No es ideal, pero es otro mecanismo para al menos saber que algo ha salido mal cuando las cosas golpean al ventilador. * nix podría tener algo similar de lo que no estoy al tanto.

Recomiendo limitar su tamaño máximo de asignación envolviendo alloca y rastreándolo internamente. Si usted fuera realmente duro al respecto, podría colocar 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 la sanidad, verifique esto con la cantidad máxima permitida para su proyecto.

Además, además de no permitir pérdidas de memoria, alloca no causa fragmentación de memoria, lo cual es bastante importante. No creo que alloca sea una mala práctica si la usas de manera inteligente, lo cual es básicamente cierto para todo. :-)

alloca () es agradable y eficiente ... pero también está profundamente roto.

  • comportamiento de alcance roto (alcance de función en lugar de alcance de bloque)
  • El uso
  • inconsistente con malloc ( alloca () no debe liberarse, por lo tanto, debe seguir de dónde provienen los punteros a free () solamente los que tienes con malloc () )
  • mal comportamiento cuando también usa inlining (el alcance a veces va a la función de llamador dependiendo de si el destinatario está en línea o no).
  • sin verificación de límites de pila
  • comportamiento indefinido en caso de falla (no devuelve NULL como malloc ... y qué significa falla ya que no verifica los límites de la pila de todos modos ...)
  • no estándar ansi

En la mayoría de los casos, puede reemplazarlo utilizando variables locales y tamaño mayor. Si se usa para objetos grandes, ponerlos en el montón suele ser una idea más segura.

Si realmente lo necesita C, puede usar VLA (sin vla en C ++, muy mal). Son mucho mejores que alloca () con respecto al comportamiento del alcance y la consistencia. A mi modo de ver, VLA son una especie de alloca () hecho a la derecha.

Por supuesto, una estructura local o matriz que utiliza un espacio importante del espacio necesario es aún mejor, y si no tiene una asignación de montón tan importante, usar malloc simple () probablemente sea sensato. No veo ningún caso de uso sensato en el que realmente necesites alloca () o VLA.

Muchas respuestas interesantes a esta " old " pregunta, incluso algunas respuestas relativamente nuevas, pero no encontré ninguna que mencione esto ...

  

Cuando se usa correctamente y con cuidado, el uso constante de alloca()   (quizás en toda la aplicación) para manejar pequeñas asignaciones de longitud variable   (o C99 VLA, donde esté disponible) puede conducir a una pila general más baja   crecimiento que una implementación equivalente que utiliza un tamaño demasiado grande   matrices locales de longitud fija. Entonces <=> puede ser bueno para su pila si lo usa con cuidado.

Encontré esa cita en ... OK, hice esa cita. Pero realmente, piénsalo ...

@j_random_hacker tiene mucha razón en sus comentarios bajo otras respuestas: Evitar el uso de <=> a favor de matrices locales de gran tamaño no hace que su programa sea más seguro contra desbordamientos de pila (a menos que su compilador sea lo suficientemente antiguo como para permitir la inclusión de funciones que use <=> en cuyo caso debe actualizar, o a menos que use <=> bucles internos, en cuyo caso no debería ... no usar <=> bucles internos).

He trabajado en entornos de escritorio / servidor y sistemas integrados. Muchos sistemas embebidos no usan ningún montón (ni siquiera se vinculan para soportarlo), 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 siempre se reinicia durante años a la vez, 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. Por lo tanto, los programadores integrados tienen pocas alternativas.

<=> (o VLAs) puede ser la herramienta adecuada para el trabajo.

He visto el tiempo & amp; una vez más donde un programador crea un búfer asignado por pila & "; lo suficientemente grande como para manejar cualquier caso posible &"; En un árbol de llamadas profundamente anidado, el uso repetido de ese patrón (anti -?) Conduce a un uso exagerado de la pila. (Imagine un árbol de llamadas de 20 niveles de profundidad, donde en cada nivel por diferentes razones, la función sobreasigna ciegamente un búfer de 1024 bytes & Quot; solo para estar seguro & Quot; cuando generalmente solo usará 16 o menos de ellos, y solo en casos muy raros pueden usar más.) Una alternativa es usar <=> o VLAs y asignar solo el espacio de pila que su función necesite, para evitar cargar innecesariamente la pila. Afortunadamente, cuando una función en el árbol de llamadas necesita una asignación más grande de lo normal, otras en el árbol de llamadas todavía usan sus pequeñas asignaciones normales, y el uso general de la pila de aplicaciones es significativamente menor que si cada función sobreasignara ciegamente un búfer local .

Pero si elige usar <=> ...

Según otras respuestas en esta página, parece que los VLA deberían ser seguros (no combinan las asignaciones de pila si se llaman desde un bucle), pero si está usando <=>, tenga cuidado de no usarlo dentro de un bucle, y asegúrese de que asegúrese de que su función no se pueda insertar si existe alguna posibilidad de que se invoque dentro del bucle de otra función.

He aquí por qué:

char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;

No es que nadie iba a escribir este código, pero el tamaño del argumento que está pasando a alloca casi seguro que proviene de algún tipo de entrada, que podría maliciosamente por finalidad conseguir el programa para alloca algo enorme como eso.Después de todo, si el tamaño no se basa en la entrada o no tienen la posibilidad de ser grande, ¿por qué no acaba de declarar un pequeño, de tamaño fijo búfer local?

Prácticamente todos los códigos que utilizan alloca y/o C99 vlas tiene errores graves que va a dar lugar a accidentes (si tienes suerte) o el privilegio de compromiso (si no eres tan afortunado).

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 <=> con un tamaño injustificado puede hacer que el núcleo se bloquee. Ciertos compiladores advierten el uso de <=> (e incluso VLA para el caso) bajo ciertas opciones que deberían activarse al compilar un código de kernel; aquí, es mejor asignar memoria en el montón que no está arreglado por un hardware. límite codificado.

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 quot; encima de " en la pila, es decir, después de su bloque asignado.

 _ alloca block en la pila

La consecuencia de esto es doble:

  1. El programa se bloqueará espectacularmente y será imposible saber por qué o dónde se bloqueó (la pila probablemente se desenrollará en una dirección aleatoria debido al puntero del marco sobrescrito).

  2. 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, & "; solo &"; obtener un montón de corrupción. El programa probablemente terminará inesperadamente pero desenrollará la pila correctamente, reduciendo así la posibilidad de ejecución de código malicioso.

Una de ellas con alloca es que longjmp rebobina la misma.

Es decir, si guarda un contexto con setjmp, a continuación, alloca algo de memoria, a continuación, longjmp para el contexto, puede perder la alloca de memoria (sin ningún tipo de aviso).El puntero de la pila está de vuelta donde estaba y por lo que la memoria ya no está reservado;si se llama a una función o hacer otro alloca, usted va a darle una paliza a la original alloca.

Para aclarar, ¿de qué me estoy refiriendo específicamente a aquí es una situación en la que longjmp no retorno de la función en el alloca tuvo lugar!Más bien, en función guarda relación con setjmp;a continuación, asigna memoria con alloca y, finalmente, una longjmp se lleva a cabo a ese contexto.La función es alloca la memoria no es del todo libre;acaba de toda la memoria que se asigna desde el setjmp.Por supuesto, estoy hablando de un comportamiento observado;ese requisito no está documentada de cualquier alloca que yo sepa.

El enfoque en la documentación es generalmente en el concepto de que alloca la memoria se asocia con un la función la activación, no con cualquier bloque;que varias invocaciones de alloca sólo tienes que tomar más memoria de pila que es todo lo liberan cuando la función termina.No es así;la memoria es en realidad asociada con el procedimiento de contexto.Cuando el contexto es restaurado con longjmp, así es el antes alloca estado.Es una consecuencia del registro del puntero de pila se utiliza para la asignación, y también, necesariamente, guardado y restaurado en el jmp_buf.

Por cierto, este, si funciona de esa manera, proporciona un mecanismo plausible para deliberadamente liberar la memoria asignada con alloca.

Me he topado con este como la causa raíz de un error.

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 conocer el tamaño del marco de la pila de la función.

Por ejemplo, una optimización común por parte 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; entonces 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 hacer.

Dada la rareza de su uso, y su estado sombrío como función estándar, los diseñadores de compiladores posiblemente deshabiliten la optimización de any que podría causar problemas con alloca, si tomara más que un pequeño esfuerzo para que funcione con alloca.

ACTUALIZACIÓN: Dado que se han agregado matrices locales de longitud variable a C y C ++, y dado que presentan problemas de generación de código muy similares para el compilador como alloca, veo que la 'rareza de uso y el estado sombreado' no se aplica al mecanismo subyacente; pero aún sospecharía que el uso de alloca o VLA tiende a comprometer la generación de código dentro de una función que los usa. Agradecería cualquier comentario de los diseñadores del compilador.

Lamentablemente, el realmente impresionante alloca() falta en el casi impresionante tcc. Gcc tiene malloc().

  1. Siembra la semilla de su propia destrucción. Con retorno como destructor.

  2. Al igual que realloc() devuelve un puntero inválido en caso de falla que segfault en sistemas modernos con un MMU (y con suerte reiniciará aquellos sin).

  3. A diferencia de las variables automáticas, puede especificar el tamaño en tiempo de ejecución.

Funciona bien con recursividad. Puede usar variables estáticas para lograr algo similar a la recursividad de cola y usar solo algunas otras para pasar información a cada iteración.

Si presiona demasiado, tiene la seguridad de un defecto (si tiene una MMU).

Tenga en cuenta que <=> no ofrece más, ya que devuelve NULL (que también será predeterminado si se asigna) cuando el sistema no tiene memoria. Es decir. todo lo que puede hacer es rescatar o simplemente tratar de asignarlo de cualquier manera.

Para usar <=> yo uso globales y les asigno NULL. Si el puntero no es NULL, lo libero antes de usar <=>.

También puede usar <=> como caso general si desea copiar cualquier dato existente. Debe comprobar el puntero antes de calcular si va a copiar o concatenar después de <=>.

3.2.5.2 Ventajas de alloca

Los procesos solo tienen una cantidad limitada de espacio de pila disponible, mucho menos que la cantidad de memoria disponible para malloc().

Al usar alloca() aumenta drásticamente sus posibilidades de obtener un error de desbordamiento de pila (si tiene suerte, o un bloqueo inexplicable si no lo tiene).

No es muy bonito, pero si el rendimiento realmente importa, puedes preasignar algo de espacio en la pila.

Si ya tiene el tamaño máximo de la memoria bloqueando su necesidad y desea mantener las comprobaciones de desbordamiento, puede hacer algo como:

void f()
{
    char array_on_stack[ MAX_BYTES_TO_ALLOCATE ];
    SomeType *p = (SomeType *)array;

    (...)
}

En realidad, no se garantiza que alloca use la pila. De hecho, la implementación gcc-2.95 de alloca asigna memoria del montón usando el propio malloc. Además, esa implementación tiene errores, puede provocar una pérdida de memoria y un comportamiento inesperado si lo llama dentro de un bloque con un uso adicional de goto. No, decir que nunca deberías usarlo, pero algunas veces alloca conduce a más gastos generales de los que libera de ti.

La función alloca es excelente y todos los detractores simplemente están difundiendo FUD.

void foo()
{
    int x = 50000; 
    char array[x];
    char *parray = (char *)alloca(x);
}

Array y parray son EXACTAMENTE iguales con EXACTAMENTE los mismos riesgos. Decir que uno es mejor que otro es una opción sintáctica, no técnica.

En cuanto a la elección de las variables de pila frente a las variables de montón, hay MUCHAS ventajas para los programas de ejecución prolongada que usan pila sobre montón para variables con vidas dentro del alcance. Evita la fragmentación del montón y puede evitar aumentar su espacio de proceso con espacio de montón no utilizado (inutilizable). No necesitas limpiarlo. Puede controlar la asignación de la pila en el proceso.

¿Por qué es esto malo?

En mi humilde opinión, alloca se considera una mala práctica porque todo el mundo tiene miedo de agotar el límite de tamaño de la pila.

Aprendí mucho leyendo este hilo y algunos otros enlaces:

Utilizo alloca principalmente para hacer que mis archivos C simples sean compilables en msvc y gcc sin ningún cambio, estilo C89, sin #ifdef _MSC_VER, etc.

¡Gracias! Este hilo me hizo registrarme en este sitio :)

En mi opinión, alloca (), donde esté disponible, debe usarse solo de manera restringida. Muy parecido al 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 alloca ().

Para uso integrado, donde se conoce el tamaño de la pila y se pueden imponer límites a través de 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 yo se sabe que lo usa.

Cuando esté disponible, los VLA pueden tener algunas ventajas sobre alloca (): el compilador puede generar comprobaciones de límite de pila que atraparán el acceso fuera de los límites cuando se usa el acceso de estilo de matriz (no sé si algún compilador hace esto, pero se puede hacer), y el análisis del código puede determinar si las expresiones de acceso a la matriz están delimitadas correctamente. Tenga en cuenta que, en algunos entornos de programación, como automoción, equipos médicos y aviónica, este análisis debe realizarse incluso para matrices de tamaño fijo, tanto automáticas (en la pila) como de asignación estática (global o local).

En arquitecturas que almacenan tanto datos como direcciones de retorno / punteros de trama 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 puede tomarse y la entrada no verificada los valores pueden permitir todo tipo de travesuras.

La portabilidad es menos preocupante en el espacio incrustado, sin embargo, es un buen argumento contra el uso de alloca () fuera de circunstancias cuidadosamente controladas.

Fuera del espacio incrustado, he usado alloca () principalmente dentro de las funciones de registro y formato para mayor eficiencia, y en un escáner léxico no recursivo, donde se crean estructuras temporales (asignadas usando alloca () durante la tokenización y clasificación, entonces se rellena un objeto persistente (asignado a través de malloc ()) antes de que regrese la función. El uso de alloca () para las estructuras temporales más pequeñas reduce en gran medida la fragmentación cuando se asigna el objeto persistente.

La mayoría de las respuestas aquí en gran medida pierden el punto: hay una razón por la cual usar _alloca() es potencialmente peor que simplemente almacenar objetos grandes en la pila.

La principal diferencia entre el almacenamiento automático y <=> es que este último sufre un problema (grave) adicional: el bloque asignado no está controlado por el compilador , por lo que no hay forma de que el compilador para optimizarlo o reciclarlo.

Comparar:

while (condition) {
    char buffer[0x100]; // Chill.
    /* ... */
}

con:

while (condition) {
    char* buffer = _alloca(0x100); // Bad!
    /* ... */
}

El problema con este último debería ser obvio.

No creo que nadie haya mencionado esto, pero alloca también tiene algunos problemas de seguridad serios que no necesariamente están presentes con malloc (aunque estos problemas también surgen con cualquier matriz basada en pila, dinámica o no). Dado que la memoria está asignada en la pila, los desbordamientos / desbordamientos del búfer tienen consecuencias mucho más graves que con solo malloc.

En particular, la dirección de retorno de una función se almacena en la pila. Si este valor se corrompe, se puede hacer que su código vaya a cualquier región ejecutable de la memoria. Los compiladores hacen todo lo posible para dificultar esto (en particular al aleatorizar el diseño de la dirección). Sin embargo, esto es claramente peor que un desbordamiento de pila, ya que el mejor de los casos es un SEGFAULT si el valor de retorno está dañado, pero también podría comenzar a ejecutar una memoria aleatoria o, en el peor de los casos, alguna región de memoria que comprometa la seguridad de su programa. .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top