Cada minuto de inactividad de la producción de forma general le costará dinero a la compañía. Si su aplicación tiene un obstáculo grave que causa la rotura de la pila, está de viaje. ¡Aprenda qué es la destrucción de pilas por adelantado y qué se puede hacer al respecto!
Que es Stack Smashing?
Trabajando como ingeniero de aseguramiento de la calidad, tarde o temprano uno se encontrará con el término aplastamiento de pila. Como desarrollador, es probable que se descubra este término inclusive antes, especialmente si se ha ingresado un error en el código, lo que provoca una pila rota. Es relativamente fácil (como en ‘algo fácil’) para que un desarrollador cometa un error que introduzca la rotura de pilas. Como usuario, cuando aprenda a romper pilas, es probable que el daño ya esté hecho.
La rotura de la pila puede ocurrir involuntariamente, a modo de ejemplo, cuando el desarrollador introdujo un error que provocó la rotura de la pila, o maliciosamente, un atacante que de alguna manera intenta desbordar o corromper la pila de un programa.
Stack smashing es una definición con una definición un tanto vaga que puede apuntar a varios problemas y puede provenir de una gama de fuentes. Los dos problemas más importantes que pueden provocar la rotura de la pila son; 1) escribir / sobreasignar demasiados datos en una parte determinada de la pila, sobrescribiendo así otra parte de la pila, y 2) donde alguna fuente externa (maliciosa o no) sobrescribió la pila de otro programa, aún cuando esto es mucho menos común .
Entonces, ¿qué es una pila? Este además es una definición vagamente definido. En términos generales, una pila se refiere a una pila de procesamiento de programas, una pila de funciones definidas en un programa / código de software dado.
Comience imaginando una pila de azulejos de baño apilados, listos para ser utilizados por un alicatador. Ésta es una representación bastante buena de una pila de computadoras, con algunas modificaciones. Si cada mosaico estuviera un poco desplazado del anterior, sería una imagen mejor, y pronto veremos por qué.
Imagínese que cada mosaico apilado es una función en el programa de computadora. La función más básica está en la parte inferior y podría ser, a modo de ejemplo, la main()
función en un programa C o C ++. C y C ++ son dos lenguajes de programación que usan la pila de forma extensiva.
Cada una de estas funciones en el programa C / C ++ tendrá un nombre y probablemente un conjunto de variables entrantes y salientes. En términos simplificados, imagine si una de esas variables tenía una longitud de 10 caracteres y alguna otra función escribió accidentalmente 100 caracteres en esa variable. Esto puede dañar toda la pila.
En términos del ejemplo de azulejos anterior, imagina a alguien con un martillo golpeando el primer azulejo con demasiada fuerza y rompiendo así todos los demás azulejos. Eh voila; pila rompiendo 😉
La analogía funciona debido a que, así como todos los mosaicos ahora están rotos en nuestra imagen de memoria ficticia, una pila rota resultará en ‘funciones rotas’ Si tu pretendes. Cada desplazamiento de mosaico es una función anidada más profundamente; más sobre funciones rotas en la próxima sección.
Depuración Pila (s) destrozada
Considerando que técnicamente una referencia a ‘funciones rotas’ puede no ser totalmente correcto, dicho de otra forma, es probable que solo haya una función rota, e inclusive puede que no haya una función rota cuando hay un ataque externo o un programa que funciona mal, es una magnífica manera de pensar en una pila rota.
De repente, los nombres de variables y funciones pueden ser alterados, y un backtrace (el flujo de funciones que tomó la computadora para llegar a una función dada que se bloqueó y (en nuestro ejemplo) rompió la pila) ya no tiene sentido.
En términos generales, cuando miramos un backtrace, tendrá un flujo claro de funciones que fueron llamadas. Aunque un programa que falla no se puede llamar inmediatamente ‘saludable’, en términos de retroceso / depuración, así es como se ve un retroceso ‘saludable’:
A pesar de esto, cuando una pila está dañada, la depuración se torna mucho más difícil. La pila puede verse así:
Este es un ejemplo de problema de rotura de pila que sucedió en MySQL, el servidor de base de datos (consulte el log.txt
adjunto a Error de MySQL 37815 para la salida completa) en 2008, lo que provocó que el demonio del servidor de base de datos (mysqld
) para terminar.
Mientras que la biblioteca del sistema operativo libc.so.6
, en esta circunstancia, parece haber manejado la pila rompiendo bastante bien (usando alguna funcionalidad de fortificación en el __fortify_fail
function), el problema existía en algún lugar del código y desde entonces se ha solucionado.
Tenga en cuenta además que en esta circunstancia, no vemos nombres de funciones resueltos, solo se nos muestra el nombre binario (curiosamente, el problema parece haber estado en el cliente (mysql
) causando que el servidor (mysqld
) para terminar) que es mysql
, junto con una dirección de memoria de la función: mysql[0x8051565]
, mysql[0x80525c7]
y mysql(main+0x4f8)[0x8053198]
.
Regularmente, cuando usamos símbolos de depuración (consulte a continuación un post sobre GDB que explica qué símbolos de depuración son en detalle), veríamos nombres de funciones con variables, e inclusive con algunos niveles de optimización / minificación binaria implementados, al menos lo haríamos ver los nombres de las funciones, como lo que vemos en el primer backtrace ‘saludable’ anterior.
A pesar de esto, en el caso de una pila rota, la salida de los nombres de las funciones, los nombres de las variables o los valores nunca está garantizada y, a menudo, se completa una palabrería 🙂 Inclusive podemos ver diferentes nombres de funciones o un pila destrozada (otra jerga utilizada a menudo por la gente de TI) de diferentes nombres de funciones que no disponen mucho sentido (y probablemente sean ficticios / falsos dado que la pila se sobrescribió de alguna manera).
Esto hace que sea más difícil tanto para el ingeniero de pruebas (que puede terminar con muchos resultados diferentes para un solo error, lo que complica el manejo del mecanismo de filtrado de errores conocidos) como para el desarrollador (que probablemente tendrá que utilizar un seguimiento paso a paso o un depurador de ejecución inversa como RR para descubrir el error en cuestión).
¿Qué hacer cuando te enfrentas a Stack Smashing?
Si se encuentra con la rotura de pilas, lo primero que debe hacer es comprender un poco mejor el problema y el entorno para conocer la fuente. Si tiene un servidor web popular expuesto en Internet con muchos usuarios de juegos que intentan ganar un torneo mientras el servidor además está extrayendo Bitcoin, querrá hacerse cargo la oportunidad de un juego sucio y averiguar si alguien se está metiendo con el servidor.
A pesar de esto, en la mayoría de los casos, el problema será solo un error de aplicación. Mientras digo ‘solo’, el problema puede ser muy importante, puede resultar en tiempo de inactividad de los servicios, puede costar mucho dinero y, para terminar, no se puede arreglar. A modo de ejemplo, un servidor de base de datos puede fallar de manera persistente cuando se inicia debido a que los datos están en un estado determinado en combinación con una deficiencia o limitación en el código.
Si tal situación se agrava al no romper la pila, o dicho de otra forma, al no poder generar un seguimiento limpio del problema, la depuración será más complicada y, en ocasiones, casi imposible. A pesar de esto, no temas, la misma depuración básica que con cualquier error o error / falla / problema de la aplicación sigue siendo la misma.
Lea detenidamente todos los archivos de registro antes, durante y después de que ocurriera el problema. Realice algunas copias de seguridad y después vuelva a intentar la operación. ¿Vuelve a fallar o no? Investigue los errores, las partes de la pila e inclusive los marcos (dicho de otra forma, las funciones de pila individuales que se muestran, como el do_the_maths
función en nuestro seguimiento de pila ‘saludable’ original) se puede colocar en sus motores de búsqueda favoritos.
Concatenar (con un espacio) los fotogramas bloqueados más selectivos (superiores) y buscar los mismos en línea a menudo le da un reporte de error existente para el problema al que se enfrenta. Aún así, en el caso de la rotura de la pila, es probable que estos marcos (nombres de funciones) se hayan estropeado y, por eso, ya no se puedan usar de la misma manera. Si ve un mensaje de afirmación (una afirmación instituida por el desarrollador en el código) de cualquier tipo, búsquelo además.
Siempre registre un nuevo reporte de error si el problema aún no parece estar registrado en línea (¡puede estar ayudando a otros que están viendo lo mismo!) Y proporcione tanta información sobre el problema como pueda hallar. Cada día se registran en línea cientos de informes de errores contra tantas aplicaciones. Con suerte, el equipo de soporte de su aplicación de destrucción de pilas está habilitada para ayudarlo rápidamente.
Además puede que le guste leer nuestro post Depuración con GDB: Introducción a continuación, dado que se basa en cómo se pueden depurar los programas C y C ++ (y otros) con el depurador de GDB. Además explica con más detalle los conceptos de una pila.