This simple program illustrates most of the basic debugging features of the C run-time library, and the kind of debug output that results.
Build this sample as a Win32 console application. Your command line should look like the following:
cl -D_DEBUG /MTd -Od -Zi -W3 sample.c -link -verbose:lib -debug:full
In this example, sample.c
is the name of the sample application, and you should substitute the name of the sample file. In console applications such as the following examples, debugging is complicated by the fact that errors do not interrupt execution of the program, as they normally would when directed to a message window.
/******************************************************
* EXAMPLE 1 *
* This simple application illustrates the basic *
* debugging features of the C runtime libraries, *
* and the kind of debug output that these features *
* generate. *
******************************************************/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>
// This routine places comments at the head of a
// section of debug output
void OutputHeading( const char * explanation )
{
_RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}
// The following macros set and clear, respectively,
// given bits of the C runtime library debug flag, as
// specified by a bitmask.
#ifdef _DEBUG
#define SET_CRT_DEBUG_FIELD(a) \
_CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define CLEAR_CRT_DEBUG_FIELD(a) \
_CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define SET_CRT_DEBUG_FIELD(a) ((void) 0)
#define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif
void main( )
{
char *p1, *p2;
_CrtMemState s1, s2, s3;
// Send all reports to STDOUT
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
// Allocate 2 memory blocks, store a string in each
p1 = malloc( 34 );
strcpy( p1, "This is the p1 string (34 bytes)." );
p2 = malloc( 34 );
strcpy( p2, "This is the p2 string (34 bytes)." );
OutputHeading(
"Use _ASSERTE to check that the two strings are identical" );
_ASSERTE( strcmp( p1, p2 ) == 0 );
OutputHeading(
"Use a _RPT macro to report the string contents as a warning" );
_RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );
OutputHeading(
"Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
_CrtMemDumpAllObjectsSince( NULL );
free( p2 );
OutputHeading(
"Having freed p2, dump allocation information about p1 only" );
_CrtMemDumpAllObjectsSince( NULL );
// Store memory checkpoint in s1 memory-state
// structure
_CrtMemCheckpoint( &s1 );
// Allocate another block, pointed to by p2
p2 = malloc( 38 );
strcpy( p2, "This new p2 string occupies 38 bytes.");
// Store a 2nd memory checkpoint in s2
_CrtMemCheckpoint( &s2 );
OutputHeading(
"Dump the changes that occurred between two memory checkpoints" );
if ( _CrtMemDifference( &s3, &s1, &s2 ) )
_CrtMemDumpStatistics( &s3 );
// Free p2 again, store new memory checkpoint in s2
free( p2 );
_CrtMemCheckpoint( &s2 );
OutputHeading(
"Now the memory state at the two checkpoints is the same" );
if ( _CrtMemDifference( &s3, &s1, &s2 ) )
_CrtMemDumpStatistics( &s3 );
strcpy( p1, "This new p1 string is over 34 bytes" );
OutputHeading( "Free p1 after overwriting the end of the allocation" );
free( p1 );
// Set debug-heap flag so freed blocks are kept on
// the linked list, to catch any inadvertent use of
// freed memory
SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );
p1 = malloc( 10 );
free( p1 );
strcpy( p1, "Oops" );
OutputHeading( "Perform a memory check after corrupting freed memory" );
_CrtCheckMemory( );
// Use explicit calls to _malloc_dbg to save file
//name and line number information, and also to
// allocate Client type blocks for tracking
p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
strcpy( p1, "p1 points to a Normal allocation block" );
strcpy( p2, "p2 points to a Client allocation block" );
// You must use _free_dbg to free a Client block
OutputHeading(
"Using free( ) to free a Client block causes an assertion failure" );
free( p1 );
free( p2 );
p1 = malloc( 10 );
OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
_CrtDumpMemoryLeaks( );
// Set the debug-heap flag so that memory leaks are
//reported when the process terminates. Then, exit.
OutputHeading( "Program exits without freeing a memory block" );
SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}
Output
Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0
Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'
Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.
Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.
Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.
Now the memory state at the two checkpoints is the same:
**************************************************************************
Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.
Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.
Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse
Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.