resueltos punteros programa pilas memoria manejo ejercicios ejemplos dinamicos dinamica dev colas codigo arreglos c++ error-handling crash stack-overflow

punteros - Cómo manejar o evitar un desbordamiento de pila en C++



programa de pilas en dev c++ (5)

En C ++, un desbordamiento de pila generalmente conduce a una falla irrecuperable del programa. Para los programas que necesitan ser realmente robustos, este es un comportamiento inaceptable, particularmente porque el tamaño de la pila es limitado. Algunas preguntas acerca de cómo manejar el problema.

  1. ¿Hay una manera de evitar el desbordamiento de pila por una técnica general. (Una solución escalable y robusta, que incluye tratar con bibliotecas externas que comen mucha pila, etc.)

  2. ¿Hay una manera de manejar los desbordamientos de pila en caso de que ocurran? Preferiblemente, la pila se desenrolla hasta que haya un manejador para lidiar con ese problema.

  3. Hay idiomas por ahí, que tienen hilos con pilas expandibles. ¿Es algo así posible en C ++?

Cualquier otro comentario útil sobre la solución del comportamiento de C ++ sería apreciado.


C ++ es un lenguaje poderoso, y con ese poder viene la capacidad de dispararte en el pie. No tengo conocimiento de ningún mecanismo portátil para detectar y corregir / abortar cuando se produce un desbordamiento de pila. Ciertamente, cualquier detección de este tipo sería específica de la implementación. Por ejemplo, g ++ proporciona -fstack-protector para ayudar a controlar el uso de tu pila.

En general, su mejor apuesta es ser proactivo para evitar las grandes variables basadas en la pila y tener cuidado con las llamadas recursivas.


El manejo de un desbordamiento de pila no es la solución correcta, en su lugar, debe asegurarse de que su programa no desborda la pila.

No asigne variables grandes en la pila (donde lo que es "grande" depende del programa). Asegúrese de que cualquier algoritmo recursivo termine después de una profundidad máxima conocida. Si un algoritmo recursivo puede repetir un número desconocido de veces o un gran número de veces, administre la recursión usted mismo (manteniendo su propia pila asignada dinámicamente) o transforme el algoritmo recursivo en un algoritmo iterativo equivalente

Un programa que debe ser "realmente robusto" no utilizará bibliotecas externas o de terceros que "comen mucha pila".

Tenga en cuenta que algunas plataformas notifican a un programa cuando ocurre un desbordamiento de pila y permiten que el programa maneje el error. En Windows, por ejemplo, se lanza una excepción. Esta excepción no es una excepción de C ++, sin embargo, es una excepción asíncrona. Mientras que una excepción de C ++ solo puede ser lanzada por una sentencia de throw , una excepción asincrónica puede ser lanzada en cualquier momento durante la ejecución de un programa. Sin embargo, esto se espera porque un desbordamiento de pila puede ocurrir en cualquier momento: cualquier asignación de función o de pila puede desbordar la pila.

El problema es que un desbordamiento de pila puede causar que se lance una excepción asíncrona incluso desde el código que no se espera que noexcept excepciones (por ejemplo, desde funciones marcadas como " noexcept o " throw() en C ++). Entonces, incluso si maneja esta excepción de alguna manera, no tiene forma de saber que su programa está en un estado seguro. Por lo tanto, la mejor manera de manejar una excepción asíncrona es no manejarla en absoluto (*) . Si se lanza uno, significa que el programa contiene un error.

Otras plataformas pueden tener métodos similares para "manejar" un error de desbordamiento de pila, pero es probable que cualquiera de estos métodos sufra el mismo problema: el código que se espera que no cause un error puede causar un error.

(*) Hay algunas excepciones muy raras.


Puede protegerse contra los desbordamientos de pila utilizando buenas prácticas de programación, como:

  1. Tenga mucho cuidado con la recursión, recientemente he visto un SO como resultado de la función recursiva CreateDirectory mal escrita, si no está seguro de que su código sea correcto al 100%, agregue una variable de protección que detendrá la ejecución después de N llamadas recursivas. O incluso mejor no escribas funciones recursivas.
  2. No cree grandes arreglos en la pila, esto podría ser arreglos ocultos, como una matriz muy grande como un campo de clase. Siempre es mejor usar vector.
  3. Tenga mucho cuidado con la aloca, especialmente si se incluye en alguna definición de macro. He visto numerosos SO resultantes de las macros de conversión de cadenas puestas en bucles que usaban alloca para asignaciones de memoria rápidas.
  4. Asegúrese de que el tamaño de su pila sea óptimo, esto es más importante en las plataformas incrustadas. Si el hilo no hace mucho, entonces dale una pila pequeña, de lo contrario, utiliza más grande. Sé que la reserva solo debe tomar un rango de direcciones, no memoria física.

Esas son las causas más importantes que he visto en los últimos años.

Para la búsqueda automática de SO, debe poder encontrar algunas herramientas de análisis de código estático.


Re: pilas expansibles. Podrías darte más espacio de pila con algo como esto:

#include <iostream> int main() { int sp=0; // you probably want this a lot larger int *mystack = new int[64*1024]; int *top = (mystack + 64*1024); // Save SP and set SP to our newly created // stack frame __asm__ ( "mov %%esp,%%eax; mov %%ebx,%%esp": "=a"(sp) :"b"(top) : ); std::cout << "sp=" << sp << std::endl; // call bad code here // restore old SP so we can return to OS __asm__( "mov %%eax,%%esp": : "a"(sp) :); std::cout << "Done." << std::endl; delete [] mystack; return 0; }

Esta es la sintaxis de ensamblador de gcc.


#include <iostream> using **namespace** std; class Complex { public: double *re, *im; Complex() { re = new double(r); im = new double(m); } Complex( ) { re = new double; im = new double; *re = *t.re; *im= *t.im; } ~Complex() { delete re, im; } }; int main() { double x, y, z; cin >> x >> y >> z; Complex n1(x,y); cout << *n1.re << "+" << *n1.im << "i "; Complex n2 = n1; cout << *n2.re << "+" << *n2.im << "i "; *n1.im = z; cout << *n2.re << "+" << *n2.im << "i "; cout << *n1.re << "+" << *n1.im << "i "; return 0; }