X
BLOG

Análisis de código estático para transferir código a plataformas de 64 bits

Análisis de código estático para transferir código a plataformas de 64 bits Tiempo de leer: 3 minutos

En mi Publicación anterior, Presenté un proceso que puede aplicar para preparar la aplicación para el proceso de transferencia de 64 bits:

Realice pruebas de mutación a través de la detección de errores de memoria en tiempo de ejecución
Utilice análisis estático para identificar código propenso a errores y no portátil
Repita la detección de errores de memoria en tiempo de ejecución
Realizar pruebas unitarias (opcional)

En esta publicación, analizaremos más de cerca algunos análisis de código estático reglas que quizás desee verificar en el paso 2.

Reglas que exponen código propenso a errores

  • Nunca devuelva una referencia a un objeto local o un puntero desreferenciado inicializado por "nuevo" dentro de la función. Devolver una referencia a un objeto local puede provocar daños en la pila. Devolver un puntero desreferenciado inicializado por "nuevo" dentro de la función podría causar una pérdida de memoria.
  • Nunca convierta una constante en no constante. Esto puede socavar la integridad de los datos al permitir que cambien los valores que se supone que son constantes. Esta práctica también reduce la legibilidad del código porque no puede asumir que las variables const sean constantes.
  • Si una clase tiene funciones virtuales, tendrá un destructor virtual. Este estándar evita pérdidas de memoria en clases derivadas. Una clase que tiene funciones virtuales está pensada para usarse como clase base, por lo que debe tener un destructor virtual para garantizar que se llamará al destructor cuando se haga referencia al objeto derivado a través de un puntero a la clase base.
  • Las funciones públicas de miembros devolverán identificadores constantes a los datos de miembros.
  • Cuando proporciona identificadores no constantes para los datos de los miembros, socava la encapsulación al permitir que las personas que llaman modifiquen los datos de los miembros fuera de las funciones de los miembros.
  • Un puntero a una clase no se convertirá en un puntero de una segunda clase a menos que herede de la segunda. Esta conversión descendente "no válida" puede resultar en punteros salvajes, problemas de corrupción de datos y otros errores.
  • No acceda directamente a datos globales desde un constructor.

El orden de inicialización de los objetos estáticos definidos en diferentes unidades de compilación no está definido en la definición del lenguaje C ++. Por lo tanto, acceder a datos globales desde un constructor puede resultar en la lectura de objetos no inicializados.

Para obtener más reglas, consulte las obras de Scott Meyers, Martin Klaus y Herb Sutter.

Reglas que exponen el código de difícil puerto

Después de localizar y reparar este código propenso a errores, comience a buscar el código que funcione bien en su plataforma / arquitectura actual, pero que podría no adaptarse bien. Algunas reglas que son aplicables a la mayoría de los proyectos de portabilidad de 64 bits incluyen:

  • Utilice tipos estándar cuando corresponda. Considere usar size_t en lugar de "int", por ejemplo. Utilice uint64_t si desea un entero sin signo de 64 bits. Esta práctica no solo ayudará a identificar y prevenir errores actuales en el código, sino que también ayudará con el esfuerzo de transferencia en el futuro cuando el código se transfiera a procesadores de 128 bits.
  • Revise todos los usos existentes de tipos de datos largos en el código fuente. Si los valores que se mantendrán en tales variables, campos y parámetros encajarán en el rango de 2Gig-1 a –2Gig o 4Gig a 0, entonces probablemente sea mejor usar int32_t o uint32_t, respectivamente.
  • Examine todos los casos de asignación restringida. Evite tales asignaciones porque la asignación de un valor largo a un int dará como resultado el truncamiento del valor de 64 bits.
  • Encuentra modelos que se estrechan. Utilice conversiones de reducción en expresiones, no operandos.
  • Encuentra moldes de long * a int *. En un entorno de 32 bits, estos podrían haberse utilizado indistintamente. Examine todas las instancias de asignaciones de punteros incompatibles.
  • Busque conversiones de int * a long *. En un entorno de 32 bits, estos podrían haberse utilizado indistintamente. Examine todas las instancias de asignaciones de punteros incompatibles.
  • Busque valores largos que se inicialicen con int literales. Evite tales inicializaciones porque las constantes integrales pueden representarse como tipos de 32 bits incluso cuando se utilizan en expresiones con tipos de 64 bits.
  • Busque int literales en operaciones binarias para las que el resultado se asigna a un valor largo. Se desea una multiplicación de 64 bits si el resultado es un valor de 64 bits.
  • Encuentre las constantes int utilizadas en expresiones de 64 bits. Utilice valores de 64 bits en expresiones de 64 bits.
  • Encuentre usos de expresiones multiplicativas que no contengan un tipo de 64 bits en ninguno de los operandos. Para que las expresiones integrales produzcan resultados de 64 bits, al menos uno de los operandos debe tener un tipo de datos de 64 bits con signo o sin signo.
  • Use sufijos apropiados en constantes literales enteras y flotantes si su compilador lo permite. Por ejemplo:


        unsigned int j = 123u;

unsigned long k = 456UL;

etc.

***

Crédito de la imagen:  quapan

Escrito por

Parasoft

Las herramientas de prueba de software automatizadas líderes en la industria de Parasoft respaldan todo el proceso de desarrollo de software, desde que el desarrollador escribe la primera línea de código hasta las pruebas unitarias y funcionales, hasta las pruebas de rendimiento y seguridad, aprovechando los entornos de prueba simulados en el camino.

Reciba las últimas noticias y recursos sobre pruebas de software en su bandeja de entrada.

Prueba Parasoft