Anuncios

Bienvenidos sean a este post, hoy veremos uno de los posibles analisis a realizar para depurar nuestro codigo..

Anuncios

Los analisis estaticos tienen la particularidad de que evaluan la calidad de un programa sin necesidad de ejecutarlo. Si bien puede ser realizado examinando el codigo fuente con herramientas automaticas e inspecciones de codigo, nos centraremos en las automaticas.

Anuncios

Estas herramientas son diseñadas para analizar un conjunto de codigo contra uno o multiples conjuntos de reglas de programacion o guias. Por lo general, se utiliza analisis de codigo estatico, analisis estatico, o analisis de codigo estatico indistintamente. Si examinamos la base del codigo entero con cualquier path posible de ejecucion, podremos encontrar una gran cantidad de bugs antes de las fases de testing. Sin embargo, esto tendra algunas limitaciones:

  • Esto puede producir alarmas de falsos positivos y falsos negativos
  • Solo se aplican las reglas que fueron implementadas por el algoritmo de escaneo, y algunas de ellas pueden ser interpretadas subjetivamente
  • No puede encontrar vulnerabilidades al momento de ejecucion
  • Puede proveer un falso sentido de seguridad donde creemos que todos esta bien direccionado
Anuncios

Existen muchas herramientas de analisis de codigo y entre ellas podemos incluir a Clang, Clian, CppCheck, Eclipse, Visual Studio y g++, por nombrar algunas. Este ultimo posee las opciones -Wall, -Weffc++ y -Wextra. Hablemos un poco sobre ellas.

Anuncios
-Wall

Esto activa todo tipo de avisos, Warnings, los cuales son cuestionables para algunos usuarios. Estos avisos son faciles de evitar o modificar, inclusive en conjuncion con macros. Pero su particularidad mas grandes es que permite activar algunos avisos mejores descriptos para C/C++ y Objetive-C.

Anuncios
-Wextra

Este se encarga de examinar algunos avisos que no contempla la opcion anterior. Este mostrara los siguientes mensajes de avisos:

  • Un puntero es comparado contra un entero cero con los operadores <, <=, > o >=
  • Un no-enumerador o enumerador aparecen en una expresion condicional
  • Bases virtuales ambiguas
  • Suscribir un array de tipo registro
  • Usar la direccion de una variable de tipo register
  • Un constructor de copia de una clase derivada no inicia su clase base
Anuncios
-Weffc++

Chequea las violaciones de alguna de las guias sugeridas en Efectivo y Mas efectivo C++ por Scott Meyers. Estas guias pueden incluir lo siguiente:

  • Definir un constructor de copia y un operador de asignacion para clases con asignacion de memoria dinamica
  • Preferir iniciacion sobre asignacion en constructores
  • Hacer destructores virtuales en clases base
  • Tener un operador = que devuelve un *this
  • No intenta devolver una referencia cuando debes devolver un objeto
  • Distinguir entre las formas de prefijo y posfijo de los operadores para incrementar y decrementar
  • Nunca sobrecargar los operadores &&, ||, . o ,
Anuncios

Para poder ver estos tres tipos de opciones, vamos a crear un ejemplo y para ello usaremos el siguiente codigo:

#include <iostream>

int *get_puntero(void)
{
    return 0;
}

int &get_valor() {
    int x = 5;
    return x;
}

int main()
{
    int *x = get_puntero();
    if( x> 0 ){
        *x = 5;
   }
   else{
       std::cout << "x is null" << std::endl;
   }

   int &y = get_valor();
   std::cout << y << std::endl;
   return 0;
}
Anuncios

En este codigo tenemos dos funciones para obtener un puntero y un valor, las cuales seran llamadas en el main y mostraremos algunos mensajes en la consola. No nos interesa tanto el funcionamiento sino mas bien como reacciona al compilarlo solo y con las opciones antes detalladas. Comencemos compilandolo como si fuera un programa normal:

$ g++ -g depurar.cpp -o depurar
Anuncios

En versiones anteriores a la 12.2.0, por lo menos la que tengo en mi equipo, nos lo compila sin problemas pero al momento de ejecutarlo nos devolvera un error. Prueben de pasar a la opcion -Wall y -Weffc++ en la compilacion:

$ g++ -Wall depurar.cpp -o depurar
Anuncios
$ g++ -Weffc++ depurar.cpp -o depurar
Anuncios

En cualquiera de los dos casos, nos devolvera un mensaje de notificacion al compilarlo:

depurar.cpp: In function ‘int& get_valor()’:
depurar.cpp:10:12: warning: reference to local variable ‘x’ returned [-Wreturn-local-addr]
int x = 5;
 ^
Anuncios

Como pueden observar ahora nos da una notificacion de que no se puede compilar porque se devuelve una referencia a una variable local. Esto es asi porque al ser una variable local, cuando salgamos de la funcion esta se elimina y no existira mas y no tiene ningun sentido que hagamos una referencia a una variable que ya no existe. Prueben de correr la opcion restante de la siguiente manera:

$ g++ -Wextra -o depurar depurar.cpp
Anuncios

Al igual que antes no lo compilara y nos devolvera lo siguiente:

$ g++ -Wextra -o depurar depurar.cpp
depurar.cpp: In function ‘int& get_valor()’:
depurar.cpp:10:12: warning: reference to local variable ‘x’ returned [-Wreturn-local-addr]
   10 |     return x;
      |            ^
depurar.cpp:9:9: note: declared here
    9 |     int x = 5;
      |         ^
depurar.cpp: In function ‘int main()’:
depurar.cpp:16:11: error: ordered comparison of pointer with integer zero (‘int*’ and ‘int’)
   16 |     if( x > 0 ){
      |         ~~^~~
$
Anuncios
Anuncios

Como pueden ver nos muestra mas detallado porque se produce el error de crear una referencia de una variable que ya no existe al momento de ser utilizada. Asi como tambien la comparacion de un puntero con entero cero. Este no solo hace la verificacion de los primeros puntos contemplados en -Wall y -Weffc++ sino que tambien nos verifica a los punteros para evitar otros errores. Tengan en cuenta que esto es para versiones viejas de compiladores, para versiones mas nuevas la opcion -Wextra es agregada automaticamente por este y si ocurre un error nos lo mostrara inmediatamente:

$ g++ -o depurar depurar.cpp
depurar.cpp: In function ‘int& get_valor()’:
depurar.cpp:10:12: warning: reference to local variable ‘x’ returned [-Wreturn-local-addr]
   10 |     return x;
      |            ^
depurar.cpp:9:9: note: declared here
    9 |     int x = 5;
      |         ^
depurar.cpp: In function ‘int main()’:
depurar.cpp:16:11: error: ordered comparison of pointer with integer zero (‘int*’ and ‘int’)
   16 |     if( x > 0 ){
      |         ~~^~~
$
Anuncios

Ya con esto tenemos una base de como realizar un analisis estatico, obviamente con otras herrramientas se pueden obtener mas datos asi como poder realizar otras acciones pero g++ tambien da muy buenas pistas de porque puede fallar, inclusive en algunas circunstancias nos sugiere para reemplazar una libreria erronea o mal escrita.

Anuncios

En resumen, hoy hemos visto a analisis estatico, que es, para que sirve, con cuales herramientas podemos usarlo, asi como algunas opciones para usarlo desde el compilador de g++, asi como tambien ahora lo realiza la version mas actual al momento de crear este post. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50