Análisis estático y detección de errores en tiempo de ejecución en plataformas de 64 bits
por Parasoft
14 de octubre de 2010
3 min leer
En mi publicaciones anteriores, Cubrí una estrategia de cuatro pasos para preparar la aplicación para el proceso de transferencia de 64 bits:
- Aplicar pruebas de mutación para realizar la detección de errores en tiempo de ejecución
- Use el análisis de código estático para identificar código propenso a errores y no portátil
- Detección de errores de tiempo de ejecución repetida
- Realizar pruebas unitarias (Opcional)
Para concluir este tema, me gustaría presentar una estrategia para identificar defectos en el procesador de 64 bits:
- Vuelva a compilar el código en el procesador de 64 bits
- Repetición: código de análisis estático inspección
- Vincular y construir
- Haz que la aplicación se ejecute
- Repetir la detección de errores en tiempo de ejecución
Paso 1: vuelva a compilar el código en el procesador de 64 bits
Vuelva a compilar su aplicación en el procesador de 64 bits. Si tiene problemas para compilarlo, resuelva todas las peculiaridades relacionadas con las variaciones del compilador. También es posible que desee crear reglas de análisis de código estático que identifiquen automáticamente el código asociado con estas peculiaridades para que pueda evitar que estos problemas de compilación ocurran en el futuro.
Algunas reglas a considerar son aquellas que señalan código difícil de transferir (a 64 bits) y propenso a errores. Por ejemplo, considere los siguientes ejemplos (se proporcionan más detalles en este post):
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.
- 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.
- Si una clase tiene funciones virtuales, tendrá un destructor virtual. Este estándar evita pérdidas de memoria en clases derivadas.
- 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.
Se puede crear un conjunto de reglas personalizado seleccionando las reglas críticas necesarias solo para esta tarea en particular. Se pueden agregar más reglas más adelante, según sea necesario.
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.
- Revise todos los usos existentes de tipos de datos largos en el código fuente.
- 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.
Paso 2: Repita la inspección del código de análisis estático
Una vez que vuelva a compilar el código, vuelva a realizar un análisis de código estático para verificar si el nuevo código cumple con todos los estándares de codificación apropiados. En este punto, cada cambio que debería haberse hecho pero que no se hizo es un error. ¡Corrija estos errores inmediatamente! No desea buscar estos errores mientras se ejecuta la aplicación.
Paso 3: vincular y construir
Vincula tu aplicación e intenta construirla.
Paso 4: Ejecute la aplicación
En este punto, debería intentar ejecutar su código. Si tiene problemas para ejecutar el código en el procesador de 64 bits, utilice un marco de prueba unitaria para ejecutar la función de código por función; de esa manera, puede eliminar exactamente lo que en el código no es portátil. Pruebe la función y luego solucione el problema. Continúe este proceso hasta que se esté ejecutando toda la aplicación.
Paso 5: Repita la detección de errores en el tiempo de ejecución
Una vez que la aplicación se está ejecutando, querrá repetir la detección de errores en tiempo de ejecución porque es probable que el proceso de transferencia cause algunos problemas nuevos que no se pudieron detectar antes del puerto (por ejemplo, nuevos problemas de corrupción de memoria o comportamientos diferentes). Si la detección de errores en tiempo de ejecución expone problemas, corrija todos los errores relacionados con la portabilidad.
***
Fotografía: Jurvetson
¿Querer aprender más? Eche un vistazo a nuestro Parasoft Insure ++en la página del producto para ver cómo la detección de errores en tiempo de ejecución puede exponer la corrupción de la memoria, pérdidas de memoria, acceso fuera de los límites de la matriz, punteros no válidos y otros defectos.