c++ - tools - static analysis software
¿Todavía necesitamos hacer análisis estático? (6)
Mi jefe cree que cualquier código que escribamos (en C / C ++) tiene que cumplir con los estándares especificados por una herramienta de análisis estático (como MISRA / Lint). Mi opinión sobre esto es que los compiladores están bien desarrollados hoy, ¿es realmente necesario?
La pregunta aquí es: ¿cuán efectivo es este análisis estático en estos días?
¿Siguen siendo necesarias las herramientas de análisis estático? Absolutamente. Las advertencias emitidas por los compiladores se están volviendo más sofisticadas, pero todavía existe la limitación de que un compilador generalmente funciona en un archivo fuente a la vez. Cada archivo se compila (* .c -> * .o), y los archivos de objetos resultantes se vinculan al final. Para realizar un análisis estático realmente efectivo, debe mirar todo el código base a la vez, analizar los archivos individuales y las interacciones entre ellos. Por lo general, los compiladores no están diseñados de esa manera, por lo que un compilador solo suele pasar por alto el tipo de cosas que detectan los analizadores estáticos. No querría construir esta funcionalidad en el compilador normal porque es un impacto de rendimiento bastante grande. Un análisis estático ejecutado en mi proyecto actual generalmente toma 4 veces el tiempo que toma una compilación normal. No desea esta sobrecarga adicional en cada compilación, por lo que es mejor combinarla en una herramienta especializada y separada que puede ejecutarse cuando sea necesario (o en el caso de algunos compiladores modernos, un conjunto separado de opciones de línea de comandos que están deshabilitados por defecto).
¿Qué tan efectivo es el análisis estático? Muy. Mi equipo encuentra una gran cantidad de problemas potenciales a través de herramientas de análisis estático, la mayoría de los cuales serían casi imposibles de encontrar utilizando otros métodos. Es particularmente bueno para encontrar problemas complejos que los humanos no son buenos para detectar, como aquellos que involucran la interacción entre múltiples variables locales y globales. Incluso si tiene una excelente cobertura de pruebas, los analizadores estáticos encontrarán todo tipo de cosas que son difíciles de encontrar solo con las pruebas. Esto es aún más cierto en el mundo integrado, donde las pruebas tienden a ser más difíciles y menos automatizadas. En mi experiencia, los analizadores estáticos incluso nos han mostrado problemas que ni siquiera sabíamos que necesitábamos probar en primer lugar.
Definitivamente recomendaría el uso de herramientas de análisis estático para cualquier proyecto de software no trivial. En realidad, ejecuto dos analizadores estáticos separados (uno está integrado en el conjunto de compiladores y el otro es una utilidad separada); Es posible que se sorprenda de lo que atrapará uno y el otro se perderá. Le recomiendo que cree un conjunto personalizado de reglas / pruebas para las ejecuciones de análisis en lugar de simplemente adoptar un conjunto de reglas como MISRA. Las necesidades de cada proyecto son diferentes, y muchas especificaciones de la industria como MISRA incluyen muchas cosas que no son necesarias para la mayoría de las personas. Mientras más cosas innecesarias revisen, más tiempo tomará analizar, más falsos positivos tendrá que analizar, etc. etc.
Además, el análisis estático es importante para generar métricas.
Esas métricas pueden mostrar: complejidad ciclomática, la profundidad de la herencia de su clase y muchas otras / gráfico de dependencias /% de comentarios y mucho ( Understand tiene una lista completa de características, por ejemplo).
Un buen punto también es que la mayoría de las herramientas de análisis estático le permiten agregar reglas específicas que pueden ser útiles si su proyecto / empresa tiene reglas de codificación.
También puede agregar un servidor de "Integración continua" que verifique su svn / git / otra rama de desarrollo todos los días y haga el análisis por la noche. De esta manera, al día siguiente puede corregir el código que no cumple con su conjunto de reglas.
Las buenas herramientas de análisis estático analizan cosas como la complejidad ciclométrica e incluso cosas como ''olores de código'' (consulte el libro Refactoring de Martin Fowler). Incluso los conteos de líneas en un archivo o en una función son indicios de que su código puede mejorarse. Aunque no creo que Lint cubra estas áreas.
No es que los compiladores no puedan hacer el análisis que hacen las herramientas de análisis estático. El problema es que el análisis de código estático toma una cantidad significativa de tiempo y generalmente no es necesario para cada compilación individual. Los compiladores generalmente están optimizados para un balance de calidad de código y tiempo de compilación. Si un compilador tropieza con un error en su código, se lo dirá, pero no tiene tiempo para buscar errores activamente.
Respuesta corta: sí.
Respuesta larga: los compiladores de hecho están mejorando en el análisis de ciertos tipos de "errores", pero la "profundidad" con la que trabajan es generalmente mucho menos que las herramientas adecuadas para esto. En particular, las herramientas que funcionan en unidades de compilación, como Coverity, que pueden comprender (por ejemplo) que una función puede devolver un puntero como NULL
, y si lo hace, su código se bloqueará porque no verifica si es NULL
antes de acceder al puntero.
Las herramientas de análisis estático también pueden verificar el uso del bloqueo, que el compilador generalmente no puede.
En cuanto a "qué tan efectivo" es, realmente depende de qué herramienta está utilizando, qué configuración y qué tan bien prueba el código. Por lo tanto, "la cobertura de código" entra en ello también. ¿Pasas por cada rama de tu código en tus pruebas? ¿Con cada valor posible que causa una diferencia en el comportamiento? Las herramientas de análisis estático pueden detectar errores que sus pruebas pueden no cubrir.
(Obviamente, si realmente tiene sentido en su negocio en particular es una discusión completamente diferente, es para que su jefe y sus jefes decidan)
Sí, agrega más confianza al código.
Las reglas MISRA se utilizan ampliamente en sistemas en tiempo real. el cumplimiento de MISRA (ejecutando la herramienta mal soportada) es requerido por muchos auditores de software.
También MISRA (o estándares similares) define algunas reglas engorrosas para evitar que el usuario haga cosas sofisticadas que podrían salir mal en algunos compiladores. Por ejemplo, la aritmética de punteros está prohibida por MISRA, pero ningún compilador lo advertirá.
EDITAR: Otro ejemplo: el siguiente código es hacer lo que muchas personas no esperan (x! = 1.1 debido a la precisión de punto flotante).
int main(int agrc, char** argv){
float x = 1.1;
if(x == 1.1)
printf("Yes!/n");
else
printf("OMG!/n");
return 0;
}
Esto no es detectado por los compiladores (lo probé en gcc 4.6 y clang 3.2). Pero es detectado por casi todas las herramientas de análisis estático.