alloca()
asigna memoria en la pila en lugar de en el montón, como en el caso de malloc()
. Entonces, cuando regreso de la rutina, la memoria se libera. Entonces, en realidad esto resuelve mi problema de liberar memoria asignada dinámicamente. La liberación de la memoria asignada malloc()
es un gran dolor de cabeza y, si de alguna manera se pierde, conduce a todo tipo de problemas de memoria.
¿Por qué se alloca()
desaconseja el uso a pesar de las características anteriores?
free
(lo que obviamente es una ventaja), no poder alinearlo (obviamente, las asignaciones del montón son mucho más pesadas), etc. La única razón para evitarloalloca
es para tamaños grandes. Es decir, desperdiciar toneladas de memoria de pila no es una buena idea, además tiene la posibilidad de un desbordamiento de pila. Si este es el caso, considere usarmalloca
/freea
alloca
es que la pila no se puede fragmentar como el montón. Esto podría resultar útil para aplicaciones duras de estilo de ejecución permanente en tiempo real, o incluso aplicaciones críticas para la seguridad, ya que la WCRU puede analizarse estáticamente sin recurrir a agrupaciones de memoria personalizadas con su propio conjunto de problemas (sin localidad temporal, recurso subóptimo) utilizar).Respuestas:
La respuesta está ahí en la
man
página (al menos en Linux ):Lo que no quiere decir que nunca debe usarse. Uno de los proyectos de OSS en los que trabajo lo usa ampliamente, y siempre y cuando no esté abusando de él (
alloca
con grandes valores), está bien. Una vez que pasa la marca de "unos cientos de bytes", es hora de usarmalloc
y amigos, en su lugar. Es posible que aún obtenga fallas de asignación, pero al menos tendrá alguna indicación de la falla en lugar de simplemente volar la pila.fuente
alloca()
no tienen el mismo miedo a los arreglos locales o la recursión (de hecho, muchas personas que gritarán elogiarán laalloca()
recursión porque "se ve elegante") . Estoy de acuerdo con el consejo de Shaun ("alloca () está bien para asignaciones pequeñas"), pero no estoy de acuerdo con la mentalidad de que enmarca a alloca () como un mal único entre los 3: ¡son igualmente peligrosos!Uno de los errores más memorables que tuve fue hacer con una función en línea que usé
alloca
. Se manifestó como un desbordamiento de la pila (porque se asigna en la pila) en puntos aleatorios de la ejecución del programa.En el archivo de encabezado:
En el archivo de implementación:
Entonces, lo que sucedió fue la
DoSomething
función en línea del compilador y todas las asignaciones de pila ocurrían dentro de laProcess()
función y, por lo tanto, explotaban la pila. En mi defensa (y no fui yo quien descubrió el problema; tuve que ir a llorar a uno de los desarrolladores principales cuando no pude solucionarlo), no fue directoalloca
, fue una conversión de cadenas ATL macrosEntonces, la lección es: no utilizar
alloca
en funciones que cree que podrían estar en línea.fuente
Antigua pregunta, pero nadie mencionó que debería reemplazarse por matrices de longitud variable.
en vez de
Está en el estándar C99 y existió como extensión del compilador en muchos compiladores.
fuente
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 garantizar absolutamente que el puntero que obtiene de alloca () NUNCA se usará después de que esta función regrese .
Puedes estar bastante seguro si
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 ideal para pasar buffers a funciones que les dan formato de texto :)
fuente
alloca()
asigna memoria que dura hasta el final de la función. Esto significa que no parece haber una traducción directa y conveniente al VLA def() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }
. Si cree que es posible traducir automáticamente los usos de losalloca
usos de VLA pero requiere más que un comentario para describir cómo, puedo hacerle una pregunta.Como se señaló en esta publicación de grupos de noticias , hay algunas razones por las cuales el uso
alloca
puede considerarse difícil y peligroso:alloca
.alloca
diferente, por lo que la portabilidad no está garantizada incluso entre los compiladores que lo admiten.fuente
alloca()
requiere registros separados para mantener el puntero de pila y el puntero de marco. En las CPU x86> = 386, el puntero de la pilaESP
se puede usar para ambos, liberando, aEBP
menos quealloca()
se use.f(42, alloca(10), 43);
podría bloquearse debido a la posibilidad de que el puntero de la pila se ajustealloca()
después de al menos uno de los argumentos.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.
fuente
No percibo tal consenso. Muchos profesionales fuertes; algunas desventajas:
while
ofor
) o en varios ámbitos, la memoria se acumula por iteración / ámbito y no se libera hasta que la función finaliza: esto contrasta con las variables normales definidas en el ámbito de una estructura de control (p. ej.for {int i = 0; i < 2; ++i) { X }
acumularía laalloca
memoria -ed solicitada en X, pero la memoria para una matriz de tamaño fijo se reciclaría por iteración).inline
funcionan esa llamadaalloca
, pero si los fuerzaalloca
, sucederá en el contexto de las personas que llaman (es decir, la pila no se lanzará hasta que la persona que llama regrese)alloca
pasó de una función / pirateo no portátil a una extensión estandarizada, pero puede persistir cierta percepción negativamalloc
el control explícitomalloc
alienta a pensar en la desasignación: si se administra a través de una función de contenedor (por ejemploWonderfulObject_DestructorFree(ptr)
), entonces la función proporciona un punto para las operaciones de limpieza de implementación (como cerrar descriptores de archivos, liberar punteros internos o hacer algunos registros) sin cambios explícitos en el cliente código: a veces es un buen modelo para adoptar consistentementeWonderfulObject* p = WonderfulObject_AllocConstructor();
eso, eso es posible cuando el "constructor" es una función que devuelvemalloc
memoria (ya que la memoria permanece asignada después de que la función devuelve el valor que se almacenaráp
), pero no si el "constructor" usaalloca
WonderfulObject_AllocConstructor
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 consecuentes problemas difíciles de diagnosticarfree
las operaciones pueden ser detectados por valgrind, Purificar, etc, pero faltan las llamadas "Destructor" no siempre se pueden detectar en absoluto - un beneficio muy tenue en cuanto a la aplicación de uso previsto; algunasalloca()
implementaciones (como las GCC) usan una macro en línea paraalloca()
, por lo que no es posible la sustitución en tiempo de ejecución de una biblioteca de diagnóstico de uso de memoria de la forma en que es paramalloc
/realloc
/free
(por ejemplo, cerca eléctrica)Sé que esta pregunta está etiquetada con C, pero como programador de 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 en pila (con vida útil vinculada al retorno de la función) en lugar del montón asignado.fuente
Todas las otras respuestas son correctas. Sin embargo, si lo que desea asignar
alloca()
es razonablemente pequeño, creo que es una buena técnica que es más rápida y conveniente que usarlamalloc()
o no.En otras palabras,
alloca( 0x00ffffff )
es peligroso y es probable que cause un desbordamiento, exactamente tanto comochar hugeArray[ 0x00ffffff ];
es. Sé prudente y razonable y estarás bien.fuente
Muchas respuestas interesantes a esta "vieja" pregunta, incluso algunas respuestas relativamente nuevas, pero no encontré ninguna que mencione esto ...
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
alloca()
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 viejo como para permitir la inclusión de funciones que se usanalloca()
en ese caso, debería actualización, o a menos que usealloca()
bucles internos, en cuyo caso no debería ... usaralloca()
bucles internos).He trabajado en entornos de escritorio / servidor y sistemas integrados. Muchos sistemas embebidos no usan un 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.
alloca()
(o VLA) puede ser la herramienta adecuada para el trabajo.He visto una y otra vez que 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 asigna de forma ciega un búfer de 1024 bytes "solo para estar seguro" cuando generalmente solo usará 16 o menos de ellos, y solo en muy casos raros pueden usar más.) Una alternativa es usar
alloca()
o VLA y asigne solo la cantidad de espacio de pila que necesite su función, 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 eliges usar
alloca()
...Según otras respuestas en esta página, parece que los VLA deberían ser seguros (no combinan las asignaciones de pila si se invocan desde un bucle), pero si está usando
alloca()
, tenga cuidado de no usarlo dentro de un bucle y haga asegúrese de que su función no se pueda alinear si existe alguna posibilidad de que se invoque dentro del ciclo de otra función.fuente
alloca()
es cierto, pero lo mismo puede decirse de las pérdidas de memoriamalloc()
(¿por qué no usar un GC entonces? Uno podría discutir).alloca()
cuando se usa con cuidado puede ser realmente útil para disminuir el tamaño de la pila.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 detectar 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 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 verificar la sanidad contra 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. :-)
fuente
alloca()
puede exigir tanto espacio que el stackpointer aterriza en el montón. Con eso, un atacante que puede controlar el tamañoalloca()
y los datos que ingresan en ese búfer puede sobrescribir el montón (lo cual es muy malo).alloca () es agradable y eficiente ... pero también está profundamente roto.
En la mayoría de los casos, puede reemplazarlo utilizando variables locales y tamaños mayores. 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. Como lo veo, los VLA son un tipo 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 utilizando malloc simple () probablemente sea sensato. No veo ningún caso de uso sensato en el que realmente necesites alloca () o VLA.
fuente
alloca
no crea un nombre, solo un rango de memoria, que tiene vida útil .alloca
omalloc
ofree
directamente. Digo cosas como{stack|heap}_alloc_{bytes,items,struct,varstruct}
y{stack|heap}_dealloc
. Entonces,heap_dealloc
solo llamafree
ystack_dealloc
es un no-op. De esta manera, las asignaciones de la pila se pueden degradar fácilmente a asignaciones de montón, y las intenciones también son más claras.Este es el por qué:
No es que alguien escriba este código, pero el argumento de tamaño que está pasando
alloca
casi seguramente proviene de algún tipo de entrada, que podría apuntar maliciosamente a que su programa llegue aalloca
algo tan grande como eso. 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 declaraste un búfer local pequeño de tamaño fijo?Prácticamente todo el código que usa
alloca
y / o C99 vlas tiene errores graves que provocarán bloqueos (si tiene suerte) o un compromiso de privilegios (si no tiene tanta suerte).fuente
alloca
. Dijiste que casi todo el código que lo usa tiene un error, pero estaba planeando usarlo; normalmente ignoraría tal afirmación, pero de ti no lo haré. Estoy escribiendo una máquina virtual y me gustaría asignar variables que no escapen de la función en la pila, en lugar de dinámicamente, debido a la enorme aceleración. ¿Hay una alternativa? enfoque que tiene las mismas características de rendimiento? Sé que puedo acercarme a los grupos de memoria, pero aún así no es tan barato. ¿Qué harías?*0 = 9;
¡INCREÍBLE! Supongo que nunca debería usar punteros (o al menos desreferenciarlos). Err, espera. Puedo probar para ver si es nulo. Hmm Supongo que también puedo probar el tamaño de la memoria que quiero asignaralloca
. Hombre extraño. Extraño.*0=9;
no es válido C. En cuanto a probar el tamaño que pasaalloca
, ¿probarlo con qué? No hay forma de conocer el límite, y si solo va a probarlo con un pequeño tamaño fijo seguro conocido (por ejemplo, 8k), también podría usar una matriz de tamaño fijo en la pila.small_constant * log(user_input)
entonces probablemente tengamos suficiente memoria.No creo que nadie haya mencionado esto: el uso de alloca en una función obstaculizará 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 cuadro dentro de una función; en su lugar, los accesos de cuadro se hacen 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 del compilador posiblemente deshabiliten cualquier optimización que pueda causar problemas con alloca, si tomaría más que un poco de esfuerzo para que funcione con alloca.
ACTUALIZACIÓN: Dado que se han agregado matrices locales de longitud variable a 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.
fuente
Un escollo con
alloca
eso es que lolongjmp
rebobina.Es decir, si guarda un contexto con
setjmp
, a continuación,alloca
algo de memoria, a continuación,longjmp
al contexto, es posible que pierda laalloca
memoria. El puntero de la pila vuelve a estar donde estaba y, por lo tanto, la memoria ya no está reservada; si llama a una función o hace otraalloca
, golpeará el originalalloca
.Para aclarar, a lo que me refiero específicamente aquí es a una situación en la que
longjmp
no vuelve de la función dondealloca
tuvo lugar. Más bien, una función guarda contexto consetjmp
; luego asigna memoria conalloca
y finalmente tiene lugar un longjmp en ese contexto. Laalloca
memoria de esa función no está completamente liberada; solo toda la memoria que asignó desde elsetjmp
. Por supuesto, estoy hablando de un comportamiento observado; no se documenta tal requisito de ningunoalloca
que yo sepa.El enfoque en la documentación generalmente está en el concepto de que la
alloca
memoria está asociada con la activación de una función , no con ningún bloque; que las invocaciones múltiples dealloca
solo toman más memoria de pila que se libera cuando la función termina. No tan; la memoria está realmente asociada con el contexto del procedimiento. Cuando el contexto se restaura conlongjmp
, también lo es elalloca
estado anterior . Es una consecuencia del registro del puntero de pila en sí mismo utilizado para la asignación, y también (necesariamente) guardado y restaurado en eljmp_buf
.Por cierto, esto, si funciona de esa manera, proporciona un mecanismo plausible para liberar deliberadamente la memoria que se le asignó
alloca
.Me he encontrado con esto como la causa raíz de un error.
fuente
longjmp
retrocede y lo hace para que el programa olvide todo lo que sucedió en la pila: todas las variables, llamadas a funciones, etc. Yalloca
es como una matriz en la pila, por lo que se espera que sean golpeadas como todo lo demás en la pila.man alloca
dio la siguiente oración: "Debido a que el espacio asignado por alloca () se asigna dentro del marco de la pila, ese espacio se libera automáticamente si la función return se salta mediante una llamada a longjmp (3) o siglongjmp (3)". Por lo tanto, está documentado que la memoria asignada conalloca
se golpea después de alongjmp
.longjmp
. La función de destino aún no ha regresado. Lo ha hechosetjmp
,alloca
y luegolongjmp
. Ellongjmp
puede rebobinar elalloca
estado a lo que era en elsetjmp
momento. Es decir, el puntero movido poralloca
sufre el mismo problema que una variable local que no ha sido marcadavolatile
.setjmp
entoncesalloca
, y luegolongjmp
, es normal quealloca
se rebobine. ¡El objetivo de todolongjmp
es volver al estado en el que se guardósetjmp
!Un lugar donde
alloca()
es especialmente peligroso quemalloc()
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 aalloca()
un tamaño injustificado puede hacer que el núcleo se bloquee. Ciertos compiladores advierten el uso dealloca()
(e incluso VLA para ese 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á fijada por un límite codificado.fuente
alloca()
no es más peligroso queint foo[bar];
dondebar
hay algún número entero arbitrario.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 de su bloque asignado.La consecuencia de esto es doble:
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 de marco sobrescrito).
Hace que el desbordamiento del búfer sea muchas veces 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" se daña el montón. El programa probablemente terminará inesperadamente pero desenrollará la pila correctamente, reduciendo así la posibilidad de ejecución de código malicioso.
fuente
alloca
.alloca
en comparación conmalloc
(por lo tanto, no es un búfer de tamaño fijo en la pila).Lamentablemente, lo verdaderamente increíble
alloca()
falta en el tcc casi increíble. Gcc tienealloca()
.Siembra la semilla de su propia destrucción. Con retorno como el destructor.
Al igual
malloc()
que devuelve un puntero no válido en caso de error que segfault en los sistemas modernos con una MMU (y con suerte reiniciará los que no lo tengan).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 una falla predeterminada (si tiene una MMU).
Tenga en cuenta que
malloc()
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 usarlo
malloc()
uso globales y les asigno NULL. Si el puntero no es NULL, lo libero antes de usarlomalloc()
.También puede usar
realloc()
como caso general si desea copiar cualquier dato existente. Debe comprobar el puntero antes de determinar si va a copiar o concatenar después derealloc()
.3.2.5.2 Ventajas de alloca
fuente
Los procesos solo tienen una cantidad limitada de espacio de pila disponible, mucho menos que la cantidad de memoria disponible
malloc()
.Al usarlo
alloca()
, aumenta dramáticamente sus posibilidades de obtener un error de desbordamiento de pila (si tiene suerte, o un bloqueo inexplicable si no lo tiene)fuente
No es muy bonito, pero si el rendimiento realmente importa, puede 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, puede hacer algo como:
fuente
La función alloca es excelente y todos los detractores simplemente están difundiendo FUD.
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?
fuente
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, para decir que nunca deberías usarlo, pero algunas veces alloca conduce a más sobrecarga de la que libera de ti.
fuente
alloca
. ¿Cómo habría limpiado la memoria cuandolongjmp
se usa para abandonar marcos que lo hicieronalloca
? ¿Cuándo alguien usaría gcc 2.95 hoy?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:
Uso 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 :)
fuente
En mi opinión, alloca (), donde 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 por el uso, sino también por la existencia de alloca ().
Para uso incrustado, donde se conoce el tamaño de la pila y se pueden imponer límites por convención 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 conocido por usarlo.
Cuando esté disponible, los VLA pueden tener algunas ventajas sobre alloca (): el compilador puede generar comprobaciones de límite de pila que capturará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 puede hacer), 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 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 las arquitecturas que almacenan datos y 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 los valores de entrada no verificados 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 formateo para mayor eficiencia, y en un escáner léxico no recursivo, donde las estructuras temporales (asignadas usando alloca () se crean durante la tokenización y clasificación, luego persiste object (asignado a través de malloc ()) se rellena 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.
fuente
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
_alloca()
el último es que tiene un problema adicional (grave): el compilador no controla el bloque asignado, por lo que el compilador no puede optimizarlo ni reciclarlo.Comparar:
con:
El problema con este último debería ser obvio.
fuente
alloca
(sí, digo VLA, porquealloca
es más que un simple creador de matrices de tamaño estático)?No creo que nadie haya mencionado esto, pero alloca también tiene algunos problemas de seguridad graves 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. .
fuente