Técnicas de depuración de CRT

Al depurar un programa que usa la biblioteca en tiempo de ejecución de C, estas técnicas de depuración pueden ser útiles.

Uso de la biblioteca de depuración de CRT

La biblioteca en tiempo de ejecución de C (CRT) proporciona una amplia compatibilidad con la depuración. Para usar una de las bibliotecas de depuración de CRT, debe vincular con /DEBUG y compilar con /MDd, /MTdo /LDd.

Las principales definiciones y macros para la depuración de CRT se pueden encontrar en el archivo de<crtdbg.h> encabezado.

Las funciones de las bibliotecas de depuración CRT se compilan con información de depuración (/Z7, /Zd, /Zi, /ZI (Formato de información de depuración)) y sin optimización. Algunas funciones contienen aserciones para comprobar los parámetros que se les pasan; además, se proporciona el código fuente. Con este código fuente, se pueden ejecutar las funciones CRT paso a paso para confirmar si las funciones se comportan como se esperaba y para comprobar si existen parámetros o estados de memoria incorrectos. (Algunas tecnologías de CRT son propietarias y no proporcionan código fuente para el control de excepciones, el punto flotante y otras rutinas).

Para obtener más información sobre las diversas bibliotecas en tiempo de ejecución que se pueden utilizar, vea Bibliotecas en tiempo de ejecución de C.

Macros para los informes

Para la depuración, puede usar las _RPTn macros y _RPTFn , definidas en<crtdbg.h>, para reemplazar el uso de printf instrucciones . No es necesario incluirlos en #ifdef directivas, ya que desaparecen automáticamente en la compilación de versión cuando _DEBUG no se define.

Macro Descripción
_RPT0, _RPT1, _RPT2, _RPT3, _RPT4 Escribe una cadena de mensaje y cero en cuatro argumentos. Para _RPT1 a través _RPT4de , la cadena de mensaje actúa como una cadena de formato de estilo printf para los argumentos.
_RPTF0, _RPTF1, _RPTF2, _RPTF3, _RPTF4 Igual que _RPTn, pero estas macros también generan el nombre de archivo y el número de línea donde se encuentra la macro.

Considere el ejemplo siguiente:

#ifdef _DEBUG
    if ( someVar > MAX_SOMEVAR )
        printf( "OVERFLOW! In NameOfThisFunc( ),
               someVar=%d, otherVar=%d.\n",
               someVar, otherVar );
#endif

Este código genera los valores de someVar y otherVar en stdout. Se puede utilizar la siguiente llamada a _RPTF2 para informar de estos mismos valores y, además, del nombre del archivo y el número de línea:

if (someVar > MAX_SOMEVAR) _RPTF2(_CRT_WARN, "In NameOfThisFunc( ), someVar= %d, otherVar= %d\n", someVar, otherVar );

Es posible que algunas aplicaciones necesiten informes de depuración que las macros proporcionadas con la biblioteca en tiempo de ejecución de C no proporcionan. En estos casos, puede escribir una macro diseñada específicamente para satisfacer sus propios requisitos. En uno de los archivos de encabezado, por ejemplo, podría incluir código como el siguiente para definir una macro denominada ALERT_IF2:

#ifndef _DEBUG                  /* For RELEASE builds */
#define  ALERT_IF2(expr, msg, arg1, arg2)  do {} while (0)
#else                           /* For DEBUG builds   */
#define  ALERT_IF2(expr, msg, arg1, arg2) \
    do { \
        if ((expr) && \
            (1 == _CrtDbgReport(_CRT_ERROR, \
                __FILE__, __LINE__, msg, arg1, arg2))) \
            _CrtDbgBreak( ); \
    } while (0)
#endif

Una llamada a ALERT_IF2 podría realizar todas las funciones del printf código:

ALERT_IF2(someVar > MAX_SOMEVAR, "OVERFLOW! In NameOfThisFunc( ),
someVar=%d, otherVar=%d.\n", someVar, otherVar );

Puede cambiar fácilmente una macro personalizada para notificar más o menos información a distintos destinos. Este enfoque es útil a medida que evolucionan los requisitos de depuración.

Creación de funciones de enlace de depuración

Puede escribir varios tipos de funciones de enlace de depuración personalizadas que permiten insertar el código en algunos puntos predefinidos dentro del procesamiento normal del depurador.

Funciones de enlace con los bloques de tipo cliente

Si desea validar o informar del contenido de los datos almacenados en bloques _CLIENT_BLOCK, puede escribir una función específicamente para ello. La función que escriba debe tener un prototipo similar al siguiente, tal como se define en<crtdbg.h>:

void YourClientDump(void *, size_t)

En otras palabras, la función de enlace debe aceptar un void puntero al principio del bloque de asignación, junto con un size_t valor de tipo que indica el tamaño de la asignación y devolver void. De lo contrario, su contenido está a tu altura.

Una vez que haya instalado la función de enlace mediante _CrtSetDumpClient, se llamará cada vez que se volque un _CLIENT_BLOCK bloque. Se puede, entonces, utilizar _CrtReportBlockType para obtener información del tipo o subtipo de los bloques volcados.

El puntero a la función a la que se pasa _CrtSetDumpClient es de tipo _CRT_DUMP_CLIENT, como se define en<crtdbg.h>:

typedef void (__cdecl *_CRT_DUMP_CLIENT)
   (void *, size_t);

Funciones de enlace de asignación

Se llama a una función de enlace de asignación, instalada mediante _CrtSetAllocHook, cada vez que se asigna, se reasigna o libera la memoria. Puede usar este tipo de enlace para muchos propósitos diferentes. Por ejemplo, puede usarlo para probar el modo en que una aplicación controla las situaciones de memoria insuficiente, como examinar pautas de asignación o registrar información de asignación para análisis posteriores.

Nota:

Tenga en cuenta la restricción sobre el uso de funciones de biblioteca en tiempo de ejecución de C en una función de enlace de asignación, que se describe en Asignaciones de enlaces de asignación y asignaciones de memoria de crt.

Una función de enlace de asignación debería tener un prototipo como este:

int YourAllocHook(int nAllocType, void *pvData,
        size_t nSize, int nBlockUse, long lRequest,
        const unsigned char * szFileName, int nLine )

El puntero al que se pasa _CrtSetAllocHook es de tipo _CRT_ALLOC_HOOK, como se define en<crtdbg.h>:

typedef int (__cdecl * _CRT_ALLOC_HOOK)
    (int, void *, size_t, int, long, const unsigned char *, int);

Cuando la biblioteca en tiempo de ejecución llama al enlace, el nAllocType argumento indica qué operación de asignación se va a realizar (_HOOK_ALLOC, _HOOK_REALLOCo _HOOK_FREE). En una operación de liberación o de reasignación, pvData tiene un puntero al artículo de usuario del bloque que se va a liberar. Pero en el caso de una asignación, este puntero es nulo porque la asignación no se ha producido. Los argumentos restantes contienen el tamaño de la asignación, su tipo de bloque, un número de solicitud secuencial y un puntero al nombre de archivo. Si está disponible, los argumentos también incluyen el número de línea en el que se realizó la asignación. Después de que la función de enlace realice cualquier análisis y otras tareas que desee su autor, debe devolver , TRUElo que indica que la operación de asignación puede continuar o FALSE, lo que indica que la operación debe producir un error. Un enlace simple de este tipo puede comprobar la cantidad de memoria asignada hasta ahora y devolver FALSE si esa cantidad superó un límite pequeño. A continuación, la aplicación experimentaría el tipo de errores de asignación que normalmente se producirían solo cuando la memoria disponible era baja. Mediante enlaces más complejos, se podrían registrar pautas de asignación, analizar el uso de la memoria o informar de situaciones específicas.

Enlaces de asignación y asignaciones de memoria de CRT

Una restricción importante en las funciones de enlace de asignación es que deben omitir _CRT_BLOCK explícitamente los bloques. Estos bloques son las asignaciones de memoria realizadas internamente por las funciones de la biblioteca en tiempo de ejecución de C si realizan alguna llamada a dichas funciones que asignan memoria interna. Pueden omitirse los bloques _CRT_BLOCK si se incluye código como el siguiente al inicio de la función de enlace de asignación:

if ( nBlockUse == _CRT_BLOCK )
    return( TRUE );

Si la función de enlace de asignación no omite los bloques _CRT_BLOCK, cualquier función de la biblioteca en tiempo de ejecución de C a la que se llame en el enlace puede hacer que el programa quede atrapado en un bucle sin fin. Por ejemplo, printf realiza una asignación interna. Si el código de enlace llama a printf, la asignación resultante hará que se vuelva a llamar al enlace, que llamará printf de nuevo, etc. hasta que se desborda la pila. Si necesita informar de las operaciones de asignación de _CRT_BLOCK, una forma de evitar esta restricción consiste en utilizar funciones de la API de Windows, en vez de funciones en tiempo de ejecución de C, para operaciones de formato y salida. Como las API de Windows no utilizan el montón de la biblioteca en tiempo de ejecución de C, no bloquearán el enlace de asignación en un bucle sin fin.

Si examina los archivos de origen de la biblioteca en tiempo de ejecución, verá que la función de enlace de asignación predeterminada ( _CrtDefaultAllocHook que simplemente devuelve TRUE), se encuentra en un archivo independiente propio, debug_heap_hook.cpp. Si desea que se llame al enlace de asignación incluso para las asignaciones realizadas por el código de inicio en tiempo de ejecución que se ejecuta antes de la función de la main aplicación, puede reemplazar esta función predeterminada por una de sus propias, en lugar de usar _CrtSetAllocHook.

Funciones de enlace de informe

Se llama a una función de enlace de informe, instalada mediante _CrtSetReportHook, cada vez _CrtDbgReport que genera un informe de depuración. Se puede utilizar, entre otras cosas, para filtrar informes que se concentran en determinados tipos de asignaciones. Una función de enlace de informe debe tener un prototipo como este ejemplo:

int AppReportHook(int nRptType, char *szMsg, int *retVal);

El puntero al que se pasa _CrtSetReportHook es de tipo _CRT_REPORT_HOOK, como se define en <crtdbg.h>:

typedef int (__cdecl *_CRT_REPORT_HOOK)(int, char *, int *);

Cuando la biblioteca en tiempo de ejecución llama a la función de enlace, el nRptType argumento contiene la categoría del informe (_CRT_WARN, _CRT_ERRORo _CRT_ASSERT), szMsg contiene un puntero a una cadena de mensaje de informe totalmente ensamblado y retVal especifica si _CrtDbgReport debe continuar la ejecución normal después de generar el informe o iniciar el depurador. (Un retVal valor de cero continúa la ejecución, un valor de 1 inicia el depurador).

Si el enlace controla completamente el mensaje en cuestión, de modo que no se requiera ningún informe adicional, debe devolver TRUE. Si devuelve FALSE, _CrtDbgReport notificará el mensaje normalmente.

En esta sección

  • Versiones de depuración de las funciones de asignación del montón

    Describe las versiones especiales de depuración de las funciones de asignación del montón, entre las que se incluyen: cómo asigna CRT las llamadas, las ventajas de llamarlas explícitamente, cómo evitar la conversión, realizar un seguimiento de los tipos independientes de asignaciones en bloques de cliente y los resultados de no definir _DEBUG.

  • Detalles del montón de depuración de CRT

    Describe la administración de memoria y el montón de depuración, los tipos de bloques del montón de depuración, las funciones de informes de estado del montón de montón de montón y cómo usar el montón de depuración para realizar un seguimiento de las solicitudes de asignación.

  • Búsqueda de pérdidas de memoria mediante la biblioteca CRT

    Explica técnicas para detectar y aislar pérdidas de memoria mediante el depurador y la biblioteca en tiempo de ejecución de C.

Consulte también