2009-07-27 9 views
8

En software integrado, ¿cómo maneja un desbordamiento de pila de forma genérica? Me encuentro con algún procesador que se protege en forma de hardware como los procesadores AMD recientes. Existen algunas técnicas en Wikipedia, pero ¿son esos enfoques realmente prácticos?Manejo de desbordamientos de pila en sistemas integrados

¿Alguien puede dar un enfoque claro sugerido que funciona en todos los casos en los procesadores integrados de 32 bits de hoy?

+1

¿Qué procesador integrado, específicamente? Realmente no existe una solución genérica que todos los procesadores implementen de la misma manera, ya que cada uno es bastante diferente. –

+0

Alrogitmo o técnica independiente del procesador. La técnica utilizada por un hacker en el entorno de la PC, se puede aplicar jugando con punteros y bloqueando su sistema en un sw incrustado. Describe cómo proteger la dirección de retorno en su área de pila ... –

+1

¿Por desbordamiento de pila se entiende cuando la pila de memoria se agota por una pila de llamadas demasiado grande? p.ej. una función recursiva demasiados niveles profundos? La protección de las direcciones de retorno se trata más de prevenir desbordamientos de búfer en la pila que "desbordamientos de pila". –

Respuesta

1

¿Se produce un desbordamiento de la pila debido a que la pila de memoria se ha agotado demasiado? p.ej. una función recursiva demasiados niveles profundos.

Existen técnicas para detectar un desbordamiento de pila mediante la colocación de datos conocidos después de la pila para que pueda detectarse si la pila creció demasiado y sobrescribirlo.

Existen herramientas de análisis de código fuente estático como GnatStack, StackAnalyzer de AbsInt y Bound-T que se pueden usar para determinar o adivinar el tamaño máximo de la pila en tiempo de ejecución.

2

Mientras que el desbordamiento de pila incrustado puede ser causado por funciones recursivas que se salgan de control, también puede ser causado por el uso erróneo del puntero (aunque esto podría considerarse otro tipo de error) y el funcionamiento normal del sistema con una pila de tamaño insuficiente. En otras palabras, si no perfila el uso de su pila, puede ocurrir fuera de un defecto o situación de error.

Antes de poder "manejar" el desbordamiento de la pila, debe identificarlo. Un buen método para hacer esto es cargar la pila con un patrón durante la inicialización y luego controlar cuánto del patrón desaparece durante el tiempo de ejecución. De esta forma, puedes identificar el punto más alto que ha alcanzado la pila.

El algoritmo de verificación de patrón debería ejecutarse en la dirección opuesta al crecimiento de la pila. Entonces, si la pila crece de 0x1000 a 0x2000, entonces la verificación de patrones puede comenzar en 0x2000 para aumentar la eficiencia. Si su patrón fue 0xAA y el valor de 0x2000 contiene algo distinto de 0xAA, usted sabe que probablemente haya tenido algún desbordamiento.

También debería considerar colocar un búfer RAM vacío inmediatamente después de la pila, de modo que si detecta un desbordamiento, puede cerrar el sistema sin perder datos. Si su pila es seguida inmediatamente por los datos de pila o SRAM, identificar un desbordamiento significará que ya ha sufrido daños. Su buffer lo protegerá por un poco más de tiempo. En un micro de 32 bits, debe tener suficiente RAM para proporcionar al menos un pequeño búfer.

+0

El uso de pila también se incrementará mediante el uso de variables automáticas (especialmente matrices grandes) y por interrupciones. Este último en particular es difícil de evaluar de antemano, por lo que puede requerir la ejecución de su código por un tiempo, como se menciona en la respuesta de Craig McQueen. –

+0

Muy cierto, y hasta ese punto, escribir a mano el prólogo de interrupción lo ayudará a controlar la cantidad de datos que necesitará enviar a la pila para cada interruptor de contexto de interrupción. Algunos micros incluso te permiten desactivar las interrupciones de software anidado, lo que te permitirá calcular aún más cuál es el peor uso de la pila de casos debido a las interrupciones. – dls

+0

... y evite todos los _otros_ problemas que las interrupciones anidadas pueden causar! –

11

Lo ideal es escribir el código con el uso de la pila estática (sin llamadas recursivas). A continuación, se puede evaluar el uso de pila máxima:

  1. análisis estático (utilizando herramientas)
  2. medición del uso de pila mientras se ejecuta el código con la cobertura de código completo (o tan alto como sea posible la cobertura de código hasta que tenga un grado razonable de confianza usted ha establecido la extensión del uso de la pila, siempre y cuando su código rara vez ejecutado no use particularmente más pila que las rutas de ejecución normales)

Pero incluso con eso, aún desea tener un medio de detectando y luego manejo desbordamiento de pila si se produce, si es posible, para mayor robustez. Esto puede ser especialmente útil durante la fase de desarrollo del proyecto.Algunos métodos a detectan overflow:

  1. Si el procesador es compatible con una memoria de lectura/escritura de interrupción (es decir, memoria de acceso punto de interrupción de interrupción) entonces puede ser configurado para apuntar en la mayor medida de la zona de pila.
  2. En la configuración del mapa de memoria, configure un bloque de RAM pequeño (o grande) que sea un área de "protección de pila". Llénalo con valores conocidos. En el software integrado, regularmente (siempre que sea razonablemente posible) verifique el contenido de esta área. Si alguna vez cambia, asume un desbordamiento de la pila.

Una vez que lo haya detectado, necesitará manejarlo él. No sé de muchas maneras en que el código se puede recuperar con gracia de un desbordamiento de pila, porque una vez que ha sucedido, la lógica de su programa casi seguramente se invalida. Así que todo lo que puede hacer es

  1. registrar el error
    1. tala de error es muy útil, porque de lo contrario los síntomas (el arranque repentino) puede ser muy difícil de diagnosticar.
    2. Advertencia: la rutina de registro debe poder ejecutarse de manera confiable incluso en un escenario de pila dañada. La rutina debe ser simple. Es decir. con una pila corrupta, probablemente no pueda intentar escribir en EEPROM utilizando su elegante tarea de fondo de escritura EEPROM. Tal vez solo registre el error en una estructura que esté reservada para este propósito, en una memoria RAM no inicial, que luego se puede verificar después de reiniciar.
  2. reinicio (o tal vez apagado, especialmente si el error se repite varias veces)
    1. alternativa puede utilizarse: reiniciar sólo la tarea en particular, si está utilizando un RTOS, y el sistema está diseñado de modo que el daño de pila está aislado y todas las otras tareas pueden manejar esa tarea reiniciándose. Esto tomaría una seria consideración de diseño.
+0

+1 para el inicio de sesión y/o el enfoque de reinicio – Gabe

+0

+1 Excelente respuesta. –

+0

¿Hay alguna forma de medir el uso de la pila (no estática) envolviendo cada llamada a la función y verificando el puntero de la pila en el contenedor? Estoy preocupado por el caso en que un desbordamiento de pila cae en bss o datos y hace cambios sin estropear el "protector de pila". – CodePoet

1

Si está utilizando un procesador con una unidad de gestión de memoria el hardware puede hacer esto para usted con sobrecarga de software mínimo. La mayoría de los procesadores modernos de 32 bits los tienen y más y más microcontroladores de 32 bits los incluyen también.

Configure un área de memoria en la MMU que se utilizará para la pila. Debe estar delimitado por dos áreas de memoria donde la MMU no permite el acceso. Cuando su aplicación se esté ejecutando, recibirá una excepción/interrupción tan pronto como desborde la pila.

Dado que se produce una excepción en el momento en que ocurre el error, usted sabe exactamente en qué parte de la aplicación la pila se dañó. Puedes ver la pila de llamadas para ver exactamente cómo llegaste a donde estás. Esto hace que sea mucho más fácil encontrar su problema que tratar de descubrir cuál es el problema al detectar su problema mucho después de que sucedió.

Lo he usado con éxito en los procesadores PPC y AVR32. Cuando empiezas a utilizar una MMU, sientes que es una pérdida de tiempo porque te llevaste bien sin ella durante muchos años, pero una vez que ves las ventajas de una excepción en el lugar exacto donde ocurre tu problema de memoria, nunca volverás. Una MMU también puede detectar cero accesos al puntero si no permite el acceso a la memoria al parque inferior de su ram.

Si está utilizando un RTOS su MMU protege la memoria y las pilas de otras tareas los errores en una tarea no deberían afectarlos.Esto significa que también podría reiniciar fácilmente su tarea sin afectar las otras tareas.

Además de esto, un procesador con una MMU generalmente también tiene mucho RAM, su programa tiene muchas menos probabilidades de desbordar su pila y no necesita ajustar todo para lograr que su aplicación se ejecute correctamente con una pequeña huella de memoria.

Una alternativa a esto sería utilizar las funciones de depuración del procesador para provocar una interrupción en el acceso a la memoria al final de la pila. Esto probablemente será muy específico del procesador.

Cuestiones relacionadas