PVS Studio.VS. Análisis estadístico de GCC 10. Mini-test independiente

Después de la aparición del artículo traducido sobre Análisis estático en GCC 10 , y la reacción esperada de los representantes del desarrollador del analizador estático comercial PVS-Studio que están aquí, pregunté: "¿Por qué los representantes se niegan a probar su producto con ejemplos tan simples para el análisis estático, y no se esconden? ¿Qué son? "
Andrey2008Sí, no me interesa. Capturó / no detectó un error sintético, esto no dice nada sobre las capacidades del analizador
¿Deberían de alguna manera ejecutar las pruebas unitarias de su producto y cómo, si no con ejemplos sintéticos tan simples?

En realidad, tuve que hacerlo yo mismo.

Prueba número 1. El ejemplo más simple de un error doble libre


Diagnosticado con:
V586 La función 'libre' se llama dos veces para desasignar el mismo espacio de memoria. Inspecciona el primer argumento. Verifique las líneas: 5, 6. 1_dbl_free.c 6

Pasó

Prueba número 2. longjmp () por free ()


Juramento incomprensible en una constante en malloc, pero se detectó un error: código inaccesible y memoria no utilizada: la función
V118 malloc () acepta una expresión peligrosa en la capacidad de un argumento. 2_longjump.c 13
V779 Código inalcanzable detectado. Es posible que haya un error presente. 2_longjump.c 15
V799 La variable 'ptr' no se usa después de que se le haya asignado memoria. Considere verificar el uso de esta variable. 2_longjump.c 13

Aprobado

Prueba número 3. Malloc () fugas y fopen () archivos no cerrados


Encontrado: la función
V118 malloc () acepta una expresión peligrosa en la capacidad de un argumento. 3_fopen.c 7
V773 El alcance de visibilidad del identificador de archivo 'f' se cerró sin cerrar el archivo. Una fuga de recursos es posible. 3_fopen.c 9
V773 El alcance de visibilidad del puntero 'p' se salió sin liberar la memoria. Una pérdida de memoria es posible. 3_fopen.c 9
V799 La variable 'p' no se usa después de que se le haya asignado memoria. Considere verificar el uso de esta variable. 3_fopen.c 7

Aprobado

Prueba número 4. Monitorear el uso de memoria después de liberarlo


Error detectado:
V774 El puntero 'n' se usó después de liberar la memoria. 4_use_after_free.c 9
V591 La función no nula debería devolver un valor. 4_use_after_free.c 11

Aprobado

Prueba número 5. Control de liberación de puntero sin almacenamiento dinámico (almacenamiento dinámico)


Se emitieron advertencias sin error:
V104 Conversión implícita de 'n' al tipo memsize en una expresión aritmética: sizeof (int) * n 5_free_nonheap.c 11
V799 La variable 'ptr' no se usa después de que se le haya asignado memoria. Considere verificar el uso de esta variable. 5_free_nonheap.c 11

Falló

Prueba número 6. Llamada no válida controlador de señal interna ()


Falló

Aunque este es un diagnóstico tan específico que no lo reprocharía.

Luego, revisé la lista de diagnósticos en GCC 10 y agregué ejemplos, por lo que realicé más pruebas con los códigos fuente.

Prueba número 7. Doble cierre de un archivo y liberación de un archivo cerrado *


PVS no detectó estos errores.
GCC 10 detectó doble cierre pero no detectó libre para un identificador cerrado.

#include <stdlib.h>
void closefile(FILE* f) {
	fclose(f);
}

void test(const char *filename) {
  FILE *f = fopen(filename, "r");
  void *p = malloc(1024);
  /* do stuff */
  closefile(f);
  fclose(f);
  free (p);
  free(f);  // <-  UB
}

Ha fallado

Prueba número 8. longjmp () en una pila obsoleta


PVS no notó nada, GCC10 funcionó correctamente

#include <setjmp.h>
#include <stdlib.h>
static jmp_buf env;
static int i;

static void inner(void) {
  longjmp(env, 1);
}

static void middle(void) {
  inner();
}

void outer(void) {
  i = setjmp(env);
}

void outer_x2(void) {
  outer();
  if (i == 0)
    middle();
}

Ha fallado

Prueba número 9. Regresar el puntero a la variable de pila


Ambos participantes fallaron, aunque en casos simples, GCC lo detecta, pero esta no es la función -fanalyzer (o puede que aún no se implemente).

#include<stdlib.h>

struct str1 {
    char buf[10];
};

struct str1 * ret(int sel)
{
    struct str1  var1, *pval;

    if(sel == 1)
        pval = &var1;
    else if(sel != 1)
        pval = (struct str1 *)malloc(1000);

    return pval;
}

Ha fallado

Prueba número 10. Tainted-array-index y diagnóstico de uso de valor no inicializado


Parece que todavía no funcionan en el fanalyzer GCC10 .

PVS atrapa esto, como se ha demostrado muchas veces.

Pasado

Conclusión


Definitivamente hay un análisis estático en PVS-Studio.

Aunque no sin algunos inconvenientes, vale la pena usarlo, especialmente porque se detectarán muchos errores humanos, no solo desde el campo del análisis estático.

All Articles