segmentation retropie raspberry dumped c++ c segmentation-fault stack-overflow

c++ - retropie - ¿Puede un desbordamiento de la pila generar un error diferente a la segmentación?



segmentation fault retropie (4)

Otras respuestas han cubierto bastante bien el lado de la PC. Voy a tocar algunos de los problemas en el mundo integrado.

El código incrustado tiene algo similar a una segfault. El código se almacena en algún tipo de almacenamiento no volátil (generalmente flash en estos días, pero algún tipo de ROM o PROM en el pasado). Escribir para esto necesita operaciones especiales para configurarlo; los accesos normales a la memoria pueden leer pero no escribir en él. Además, los procesadores integrados generalmente tienen grandes lagunas en sus mapas de memoria. Si el procesador recibe una solicitud de escritura para la memoria que es de solo lectura, o si recibe una solicitud de lectura o escritura para una dirección que no existe físicamente, el procesador generalmente lanzará una excepción de hardware. Si tiene un depurador conectado, puede verificar el estado del sistema para encontrar qué salió mal, como con un volcado del núcleo.

Sin embargo, no hay garantía de que esto ocurra por un desbordamiento de pila. La pila se puede colocar en cualquier lugar de la RAM, y esto generalmente estará junto a otras variables. El resultado del desbordamiento de la pila generalmente será corromper esas variables.

Si su aplicación también usa montón (asignación dinámica), entonces es común asignar una sección de memoria donde la pila comienza en la parte inferior de esa sección y se expande hacia arriba, y el montón comienza en la parte superior de esa sección y se expande hacia abajo. Claramente, esto significa que los datos asignados dinámicamente serán la primera víctima.

Si no tiene suerte, puede que ni siquiera note cuándo sucede, y luego necesita averiguar por qué su código no se comporta correctamente. En el caso más irónico, si los datos que se sobrescriben son punteros, entonces aún puede obtener una excepción de hardware cuando el puntero intente acceder a la memoria no válida, pero esto ocurrirá un tiempo después del desbordamiento de la pila y la suposición natural será que es un error en tu código.

El código incrustado tiene un patrón común para tratar esto, que es "filtrar" la pila inicializando cada byte a un valor conocido. Algunas veces el compilador puede hacer esto; o a veces puede necesitar implementarlo usted mismo en el código de inicio antes de main (). Puedes mirar hacia atrás desde el final de la pila para encontrar dónde ya no está establecido en este valor, en cuyo punto conoces la marca máxima para el uso de la pila; o si todo es incorrecto, entonces sabrá que tiene un desbordamiento. Es común (y una buena práctica) para las aplicaciones integradas sondear esto continuamente como una operación en segundo plano, y poder informarlo para fines de diagnóstico.

Después de haber hecho posible rastrear el uso de la pila, la mayoría de las compañías establecerán un margen aceptable para el peor de los casos para evitar desbordamientos. Esto es típicamente entre 75% y 90%, pero siempre habrá algo de repuesto. Esto no solo permite la posibilidad de que haya un peor caso peor que no haya visto todavía, sino que también hace la vida más fácil para el desarrollo futuro cuando se necesita agregar un nuevo código que utiliza más stack.

En un programa compilado (digamos C o C ++, pero supongo que esta pregunta podría extenderse a cualquier lenguaje que no sea VM-ish con una pila de llamadas): muy a menudo cuando se desborda la pila, se obtiene un error de segmentación :

El desbordamiento de pila es [a] causa, el resultado es una falla de segmentación.

Sin embargo, este siempre es el caso? ¿Puede un desbordamiento de la pila generar otros tipos de comportamiento del programa / sistema operativo?

También estoy preguntando sobre sistemas operativos que no son de Linux, que no son Windows y hardware que no es X86. (Por supuesto, si no tiene protección de memoria de hardware o soporte de sistema operativo para ello (por ejemplo, MS-DOS), entonces no existe una falla de segmentación, estoy preguntando sobre casos en los que podría obtener una falla de segmentación, pero sucede algo más )

Nota: Suponga que, aparte del desbordamiento de la pila, el programa es válido y no intenta acceder a las matrices más allá de sus límites, punteros inválidos de desreferencia, etc.


Sí, incluso en un sistema operativo estándar (Linux) y hardware estándar (x86).

void f(void) { char arr[BIG_NUMBER]; arr[0] = 0; // }

Tenga en cuenta que en x86, la pila crece, por lo que estamos asignando al comienzo de la matriz para desencadenar el desbordamiento. Los descargos de responsabilidad habituales se aplican ... el comportamiento exacto depende de más factores de los que se discuten en esta respuesta, incluidos los detalles de su compilador de C.

Si BIG_NUMBER apenas es lo suficientemente grande como para desbordarse, se encontrará con el protector de pila y obtendrá un error de segmentación. Para eso está el protector de pila, y puede ser tan pequeño como una sola página de 4 KiB (pero no más pequeño, y este tamaño de 4 KiB se usa antes de Linux 4.12) o puede ser más grande (1 MiB predeterminado en Linux 4.12 , vea mm: gran espacio de protección de la pila ), pero siempre tiene un tamaño particular.

Si BIG_NUMBER es lo suficientemente grande, el desbordamiento puede omitir el protector de la pila y aterrizar en otra parte de la memoria, potencialmente la memoria que es válida. Esto puede hacer que su programa se comporte de manera incorrecta pero no se bloquee, lo cual es básicamente el peor de los casos: queremos que nuestros programas se cuelguen cuando son incorrectos en lugar de hacer algo no deseado.


es una de las muchas razones del comportamiento indefinido de un programa. En este caso, puede obtener un resultado esperado o un error de segmentación, o su disco duro podría ser borrado, etc. No espere ningún comportamiento definido porque es un comportamiento indefinido.


Una cosa es lo que sucede en el tiempo de ejecución cuando desborda la pila, lo que puede ser muchas cosas. Incluyendo pero no limitado a; falla de segmentación, sobreescribiendo variables que siguen a cualquier cosa que desborde, causando una instrucción ilegal, nada en absoluto y mucho más. El "viejo" artículo clásico Smashing The Stack For Fun and Profit describe muchas maneras en que uno puede "divertirse" con estas cosas.

Otra cosa es lo que puede suceder en el momento de la compilación. Tanto en C como en C ++, escribir más allá de una matriz o exceder el tamaño de la pila es Undefined Behavior y cuando un programa contiene UB en cualquier lugar, el compilador básicamente puede hacer lo que quiera con cualquier parte de tu programa. Y los compiladores modernos se están volviendo muy agresivos en la explotación de UB con fines de optimización, a menudo suponiendo que UB nunca sucede, lo que les lleva simplemente a eliminar el código que contiene UB o hacer que una rama sea tomada siempre o nunca porque la alternativa causaría UB. Algunas veces el compilador introducirá un viaje en el tiempo o llamará a una función que nunca fue llamada en el código fuente y muchas, muchas otras cosas que pueden causar un comportamiento de tiempo de ejecución realmente confuso.

Ver también:

Lo que todo programador de C debe saber sobre el comportamiento indefinido # 1/3

Lo que todo programador de C debe saber sobre el comportamiento indefinido # 2/3

Lo que todo programador de C debe saber sobre el comportamiento indefinido # 3/3

Una guía para el comportamiento indefinido en C y C ++, parte 1

Una guía para el comportamiento indefinido en C y C ++, parte 2

Una guía para el comportamiento indefinido en C y C ++, Parte 3