Supervisión continua del análisis de pila a lo largo del desarrollo de software

Aunque el software integrado es cada vez más complejo, con millones de líneas de código, el objetivo de desarrollar software sólido, correcto y de alto rendimiento permanece invariable. El software de alto rendimiento debe optimizar los recursos de CPU y memoria disponibles, lo que supone un reto en sistemas integrados con una capacidad de memoria restringida, especialmente la memoria RAM. Es importante evaluar el uso de RAM realizando análisis de pila y montón. Estimar manualmente la carga de pila y montón se convierte en una tarea difícil para equipos de desarrollo, incluso en programas pequeños. Una estimación incorrecta puede provocar desbordamientos de pila y comportamientos indefinidos. Esa es la razón por la que algunos estándares de codificación aplican prácticas recomendadas sobre el uso de asignación de memoria y evitar así costes innecesarios. No obstante, la pila sigue siendo un componente de RAM necesario, y debe utilizarse de manera óptima.

¿Por qué realizar análisis de pila en sistemas integrados?

Un desbordamiento de pila se produce cuando el tamaño de la pila disponible es insuficiente para las demandas del código. Sin embargo, se desperdicia memoria cuando el entorno está configurado con una pila más grande de lo necesario. En el caso de las aplicaciones críticas para la seguridad, es imperativo estimar el uso de pila en el peor de los casos y de manera continua y sistemática, para evitar la escasez de RAM durante la ejecución del software.

Riesgo de estimación incorrecta del uso de pila.

Riesgo de estimación incorrecta del uso de pila.

¿Cómo se realiza la estimación con análisis de pila?

Estimación manual del uso de pila

Si bien la estimación manual del análisis de pila puede resultar útil, supone un reto en sistemas más complejos. Requiere un conocimiento exhaustivo de la profundidad de las llamadas a funciones, y detalles sobre todas las variables locales y el tamaño de los marcos de interrupción que ocurren en cualquier momento durante la ejecución, entre otros aspectos. Este procedimiento lleva mucho tiempo y es propenso a errores. Teniendo en cuenta que las herramientas de análisis estático de código pueden realizar el cálculo rápidamente, no es necesario hacerlo manualmente.

Uso de analizadores estáticos de código

Los equipos de desarrollo pueden predecir el uso de pila con un analizador estático de código. Las herramientas de análisis pueden analizar las profundidades de las llamadas a funciones, estimaciones de pila en variables locales y parámetros de retorno, interrupciones anidadas y el tamaño de las interrupciones que ocurren durante la ejecución. La ventaja de emplear un analizador estático de código es que se encarga de infracciones de reglas de codificación, errores en tiempo de ejecución y la complejidad de la codificación, junto con la estimación del análisis de pila. El cálculo se ejecuta en cuestión de minutos y ahorra el tiempo que llevaría calcular el consumo de pila manualmente.

Pruebas y mediciones en plataformas objetivo

Los analizadores estáticos pueden estimar el consumo de pila durante el desarrollo. No obstante, es mejor obtener resultados sobre el consumo de pila real en el hardware físico. Muchos entornos de desarrollo incluyen prestaciones de emulación de hardware y permiten realizar análisis de pila en tiempo real. Es importante realizar análisis de pila en el hardware real y crear escenarios de desbordamiento para realizar pruebas de doble seguridad. Pero, ¿cuándo se debe realizar análisis de pila con herramientas de análisis estático y cuándo en plataformas objetivo reales?

¿Cuándo se debe realizar análisis de pila?

El análisis de pila es un proceso continuo en el ciclo de desarrollo de software. Estimar el uso de pila solo al final del ciclo de desarrollo de software puede poner en riesgo todo el esfuerzo invertido en el desarrollo. Además, solucionar los problemas en una fase avanzada del ciclo de desarrollo puede llevar mucho tiempo y causar confusión a la hora de determinar si se deben realizar cambios de diseño en hardware o en software. Los hitos más importantes para realizar análisis de pila son:

  • Cuando se incorporan nuevas funcionalidades

    Cada funcionalidad nueva conlleva un aumento del uso de pila. Los equipos de desarrollo deben vigilar el uso de pila con cada nueva funcionalidad.
    1. Realice análisis de pila, depure y corrija código complejo: Después de cada implementación de funcionalidades importante, los equipos de desarrollo pueden emplear un analizador estático en un componente o módulo de software específico localmente para evaluar el aumento de consumo de pila entre el software base y el software implementado.
    2. Supervise el análisis de pila durante todo el proceso de desarrollo: El equipo de control de calidad y el personal responsable de productos pueden usar un analizador estático para realizar estimaciones de pila en el flujo de integración continua (CI) y visualizar los resultados en paneles. Este proceso ayuda a realizar un seguimiento del análisis de pila durante el ciclo de desarrollo de software.
    3. Aplique prácticas recomendadas para mantener un uso mínimo de pila: Las puertas de calidad ayudan a evitar infracciones de pautas de codificación de MISRA™ y AUTOSAR que imponen el uso condicional de asignaciones dinámicas de memoria.
  • Antes del lanzamiento del software

    Las estimaciones de pila con analizadores estáticos proporcionan una prueba contundente de que la supervisión del consumo de pila se realiza de forma eficiente. Antes de cada lanzamiento de software, ejecute un análisis de pila en plataformas objetivo reales bajo cargas operativas estándar, cargas mínimas y cargas máximas para obtener un panorama completo del uso de la pila. Verificar los procedimientos de doble seguridad para eventos de desbordamiento y subdesbordamiento de la pila resulta crucial.

¿Cómo se usa Polyspace en estimación de pila?

Polyspace Code Prover™ realiza estimaciones conservadoras y optimistas sobre el tamaño más grande y más pequeño de variables locales en cada función para determinar el uso máximo y mínimo de pila tanto en nivel funcional como programático. El análisis tiene en cuenta el tamaño de los valores de retorno de la función, el tamaño de los parámetros de la función, el tamaño de las variables locales, y el espacio interno adicional introducido para la alineación de la memoria.

Métricas de código de análisis de pila en Polyspace.

Métricas de código de análisis de pila en Polyspace.

Para comprender y depurar el uso excesivo de la pila, los equipos de desarrollo pueden ejecutar Polyspace® localmente y revisar las profundidades de las llamadas a funciones para identificar la causa exacta del exceso de uso de pila y reducirlo optimizando los recursos disponibles.

Árbol de llamadas y estimación de pila superior para la función table_loop().

Árbol de llamadas y estimación de pila superior para la función table_loop().

Supervise el análisis de pila durante todo el proceso de desarrollo

Polyspace Access™ es un servidor de base de datos de resultados que presenta una interfaz gráfica de usuario en navegadores web. El proceso de integración continua puede desencadenar el análisis de pila en Polyspace Server™ para generar una estimación de uso de pila. Este resultado se puede cargar en la base de datos de resultados. Los equipos de control de calidad y el personal responsable de producto pueden observar continuamente el uso de pila en la interfaz gráfica, y tomar las medidas necesarias en caso de uso excesivo de los recursos de pila disponibles.

Estimación de pila por proyecto en Polyspace Access.

Estimación de pila por proyecto en Polyspace Access.

Como próximo paso, se pueden revisar las funciones con un mayor uso de pila, y asignarlas a equipos de desarrollo para que realicen una investigación y depuración en profundidad. Polyspace permite introducir comentarios, y establecer el estado y la gravedad de los resultados del análisis antes de asignarlos a personal de desarrollo en una herramienta de seguimiento de errores como Jira.

Estimación de pila en nivel de función y panel de revisión de resultados en Polyspace Access.

Estimación de pila en nivel de función y panel de revisión de resultados en Polyspace Access.

Aplique prácticas recomendadas para mantener un uso mínimo de la pila

En código de producción, es obligatorio que no existan infracciones de estándares de codificación como MISRA C™, MISRA C++ y AUTOSAR C++, entre otros. Estos estándares de codificación prohíben asignar memoria dinámicamente, y recomiendan casos prácticos específicos para optimizar la asignación de memoria estática. Polyspace Bug Finder™ puede identificar infracciones de las prácticas recomendadas, que equipos de desarrollo y personal responsable de productos pueden supervisar localmente a través de Polyspace Access. Las siguientes reglas de codificación indican las prácticas recomendadas para la asignación de memoria estática que se pueden analizar con Polyspace Bug Finder.

Estándar de codificación

Regla

Descripción

MISRA C: 2004

20.4

No se permite utilizar asignación de memoria de montón dinámica.

MISRA C: 2012

21.3

No se permite utilizar las funciones <stdlib.h> de asignación y desasignación de memoria.

MISRA C++: 2008

18-4-1

No se permite utilizar asignación de memoria de montón dinámica.

AUTOSAR C++14

A18-5-1

No se permite utilizar las funciones malloc, calloc, realloc y free.

AUTOSAR C++14

A18-5-2

No se permite utilizar expresiones new o delete que no sean de colocación.

AUTOSAR C++14

A18-5-3

La forma de la expresión delete debe coincidir con la forma de la expresión new utilizada para asignar la memoria.

AUTOSAR C++14

A18-5-4

Si un proyecto tiene una versión dimensionada o no dimensionada del operador “delete” definida globalmente, se deben definir tanto las versiones dimensionadas como las no dimensionadas.

AUTOSAR C++14

A18-5-5

Las funciones de gestión de memoria deben garantizar lo siguiente: (a) comportamiento determinístico resultante de la existencia de un tiempo de ejecución en el peor de los casos; (b) evitar la fragmentación de la memoria; (c) evitar que se agote la memoria; (d) evitar asignaciones o desasignaciones no coincidentes, y (e) no dependencia de llamadas no determinísticas al kernel.

AUTOSAR C++14

A18-5-7

Si se utiliza implementación en tiempo no real de funciones de gestión de memoria dinámica en un proyecto, solo se debe asignar y desasignar memoria durante fases de programa en tiempo no real.

AUTOSAR C++14

A18-5-8

Los objetos que no sobrevivan a una función deben tener una duración de almacenamiento automática.

AUTOSAR C++14

A18-5-9

Las implementaciones personalizadas de funciones de asignación y desasignación de memoria dinámica deben cumplir con los requisitos semánticos especificados en el apartado correspondiente de “comportamiento requerido” del estándar C++.

AUTOSAR C++14

A18-5-10

Debe utilizarse new de colocación solo con punteros alineados correctamente a una capacidad de almacenamiento suficiente.

AUTOSAR C++14

A18-5-11

“operator new” y “operator delete” se deben definir conjuntamente.

El uso de pila crece con el aumento de las complejidades ciclomáticas del código, el número de llamadas a funciones anidadas y el número de variables de la función, entre otros factores. Polyspace ofrece control sobre numerosas variables que influyen en el uso de pila, y permite establecer un umbral de complejidad del código.

Establecimiento de umbrales de complejidad del código.

Establecimiento de umbrales de complejidad del código.

Polyspace Bug Finder ofrece muchas comprobaciones en tiempo de ejecución para asignaciones de memoria estáticas y dinámicas. Resolver todos los errores de alta, media y baja prioridad ayuda a reducir los riesgos relacionados con las asignaciones de memoria.

Comprobación de memoria estática y dinámica en tiempo de ejecución.

Comprobación de memoria estática y dinámica en tiempo de ejecución.

Se recomienda asignar un tamaño ligeramente mayor a la pila, independientemente del método utilizado para calcular el uso de la pila. Este enfoque ayuda a evitar vulnerabilidades del sistema debidas a un desbordamiento de pila que haya pasado desapercibido durante las pruebas.

La vulnerabilidad de desbordamiento de pila es uno de los principales motivos que provocan que muchas aplicaciones integradas muestren un comportamiento indefinido cuando se ejecutan. Utilizar la herramienta adecuada en el momento adecuado y seguir las prácticas recomendadas puede mejorar la confianza en el software frente a los desbordamientos de pila.