
Estaba previsto que después de escribir un artículo "Es una lástima las opiniones sobre los analizadores de código estático", hablemos y abandonemos el tema con calma. Pero inesperadamente, este artículo provocó una respuesta tormentosa. Desafortunadamente, la discusión salió mal y ahora haremos un segundo intento de explicar nuestra visión de la situación.
Anécdota-analogía
Entonces, todo comenzó con el artículo " Es una lástima las opiniones sobre los analizadores de código estático ". Ella comenzó a ser discutida activamente sobre algunos recursos y esta discusión es muy similar a la siguiente anécdota antigua.
Compramos una motosierra japonesa para unos duros leñadores siberianos.Historia uno a uno. La gente miró el código:
Los leñadores se reunieron en círculo y decidieron probarlo.
La trajeron, le dieron un árbol.
"Cremallera", dijo el japonés vio.
"Oh, joder ..." - dijeron los leñadores.
Le deslizaron un árbol más grueso. "¡Vzh-zh-zhik!" - dijo la sierra.
"¡Vaya, mierda!" - dijeron los leñadores.
Le deslizaron un grueso cedro en su interior. "VZH-ZH-ZH-ZH-ZH-ZH-ZHIK !!!" - dijo la sierra.
"¡¡Vaya, joder !!" - dijeron los leñadores.
Le deslizaron un trozo de hierro. "¡GRIETA!" - dijo la sierra.
"¡¡¡Sí, joder !!!" - ¡Dijeron en tono de reproche los severos leñadores de Siberia! Y salieron a talar el bosque con hachas ...
if (A[0] == 0)
{
X = Y;
if (A[0] == 0)
....
}
Y comenzaron a inventar situaciones en las que podría estar justificado, lo que significa que la advertencia del analizador PVS-Studio es falso positivo. El razonamiento entró en el curso sobre el cambio de memoria entre dos comprobaciones, que surge de:
- trabajo de corrientes paralelas;
- manejadores de señales / interrupciones;
- la variable X es una referencia al elemento A [0] ;
- hardware, como realizar operaciones DMA;
- etc.
Y habiendo comentado que no todas las situaciones que el analizador puede entender, se fueron a talar el bosque con hachas. Es decir, encontramos una excusa por la que es posible seguir sin utilizar el analizador de código estático en nuestro trabajo.
Nuestra visión de la situación
Este enfoque es contraproducente. Una herramienta imperfecta puede resultar útil y su uso es económicamente viable.
Sí, cualquier analizador estático genera falsos positivos. Y no se puede hacer nada al respecto. Sin embargo, esta desgracia está muy exagerada. En la práctica, los analizadores estáticos se pueden configurar y utilizar de diversas formas para suprimir y trabajar con falsos positivos (consulte 1 , 2 , 3 , 4 ). Además, aquí conviene recordar el artículo "Los falsos positivos son nuestros enemigos, pero pueden seguir siendo tus amigos ".
Sin embargo, incluso esto no es lo principal. ¡No tiene sentido considerar casos especiales de código exótico!¿Puede confundir el analizador con un código complejo? Sí tu puedes. Sin embargo, para uno de esos casos, habrá cientos de activadores del analizador útiles. Se pueden encontrar y corregir muchos errores en una etapa muy temprana. Y uno o dos falsos positivos pueden suprimirse de forma segura y dejar de prestarles atención.
Y nuevamente PVS-Studio tiene razón
Aquí el artículo podría estar terminado. Sin embargo, algunos pueden considerar que la sección anterior no son consideraciones racionales, sino que intenta ocultar las debilidades y deficiencias de la herramienta PVS-Studio. Entonces tienes que continuar.
Considere el código compilado concreto que incluye declaraciones de variables:
void SetSynchronizeVar(int *);
int foo()
{
int flag = 0;
SetSynchronizeVar(&flag);
int X, Y = 1;
if (flag == 0)
{
X = Y;
if (flag == 0)
return 1;
}
return 2;
}
El analizador PVS-Studio emite razonablemente una advertencia: V547 Expression 'flag == 0' siempre es verdadera.
Y el analizador tiene toda la razón. Si alguien comienza a despotricar que una variable puede cambiar en otro hilo, en un manejador de señales, etc., entonces simplemente no comprende los lenguajes C y C ++. No puedes escribir de esa manera.
Para fines de optimización, el compilador tiene derecho a descartar la segunda comprobación y tendrá toda la razón. Desde el punto de vista del idioma, una variable no puede cambiar. Su cambio de fondo no es más que un comportamiento indefinido.
Para que el cheque permanezca en su lugar, la variable debe declararse volátil :
void SetSynchronizeVar(volatile int *);
int foo()
{
volatile int flag = 0;
SetSynchronizeVar(&flag);
....
}
El analizador PVS-Studio lo sabe y ya no emite una advertencia para dicho código .
Aquí volvemos a lo comentado en el primer artículo . No hay ningún problema. Pero hay críticas o malentendidos por qué el analizador tiene derecho a emitir una advertencia.
Nota para los lectores más meticulosos
Algunos lectores pueden volver al ejemplo sintético del primer artículo:
char get();
int foo(char *p, bool arg)
{
if (p[1] == 1)
{
if (arg)
p[0] = get();
if (p[1] == 1) // Warning
return 1;
}
// ....
return 3;
}
Y agregue volátiles :
char get();
int foo(volatile char *p, bool arg)
{
if (p[1] == 1)
{
if (arg)
p[0] = get();
if (p[1] == 1) // Warning :-(
return 1;
}
// ....
return 3;
}
Después de eso, es justo decir que el analizador aún emite la advertencia V547 La expresión 'p [1] == 1' es siempre cierta.
Hurra, finalmente se ha demostrado que el analizador todavía está mal :). ¡Esto es un falso positivo!
Como puede ver, no estamos ocultando ningún defecto. Al analizar el flujo de datos en busca de elementos de matriz, este volátil desafortunado se perdió. El defecto ya se ha encontrado y solucionado. La corrección estará disponible en la próxima versión del analizador. No habrá falsos positivos.
¿Por qué no se identificó este error antes? Porque, de hecho, este es nuevamente un código irreal que no se encuentra en proyectos reales. En realidad, hasta ahora, no nos hemos encontrado con dicho código, aunque hemos comprobado muchos proyectos de código abierto .
¿Por qué el código es poco realista? Primero, en la práctica, habrá algún tipo de función de temporización o retardo entre las dos verificaciones. En segundo lugar, nadie en su sano juicio, a menos que sea absolutamente necesario, crea matrices que constan de elementos volátiles. Trabajar con una matriz de este tipo es una caída enorme en el rendimiento.
Resumamos. Es fácil crear ejemplos en los que falla el analizador. Pero desde un punto de vista práctico, las fallas identificadas prácticamente no afectan la calidad del análisis del código y la cantidad de errores reales detectados. Después de todo, el código de las aplicaciones reales es solo un código que el analizador y la persona pueden entender al mismo tiempo, y no un acertijo o acertijo. Si el código es un rompecabezas, entonces no hay tiempo para analizadores :).
Gracias por su atención.

Enlaces adicionales
- Cómo implementar un analizador de código estático en un proyecto heredado y no desmotivar al equipo .
- Configuraciones de diagnóstico adicionales .
- Características del analizador PVS-Studio por el ejemplo de EFL Core Libraries, 10-15% de falsos positivos .
- Inyecte análisis estático en su proceso, en lugar de buscar errores con él .

Si desea compartir este artículo con una audiencia de habla inglesa, utilice el enlace de traducción: Andrey Karpov. Parte 2: Opiniones molestas sobre los analizadores estáticos .