2

I am working on a Windows command-line program written in C using Visual Studio Express 2013 for Windows Desktop. When compiled in Debug mode, I would really like my program to detect memory leaks and print them on the standard error or standard output so they are in my face.

By calling _CrtDumpMemoryLeaks, I am able to get memory leak information printed out to the Debug output in Visual Studio (which you can find under the Output pane). Based on the MSDN documentation, I would think that I can add a call to _CrtSetDumpClient in order to get access to the data being dumped and then print it to stderr.

Here is the code I am using to test this issue:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <stdio.h>
#include <crtdbg.h>

void dumpClient(void * userPortion, size_t blockSize)
{
    printf("memory leak: %d\n", blockSize);
}

int main(int argc, char ** argv)
{
    printf("hello\n");
    _CrtSetDumpClient(&dumpClient);
    malloc(44);
    _CrtDumpMemoryLeaks();
    return 0;
}

I made a new Visual C++ Win32 Console Application project in Visual Studio, stuck this code into the project, disabled precompiled headers, made sure that the IDE was in Debug mode, and built. If I run it by pressing F5 (the Start Debugging command), then I can see the following output in the Debug window of Visual Studio, which is good:

Detected memory leaks!
Dumping objects ->
c:\users\david\documents\scraps\test_vc++\testvc\testvc.cpp(15) : {81} normal block at 0x0120A500, 44 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.
The program '[3868] TestVC.exe' has exited with code 0 (0x0).

However, if I set a breakpoint inside dumpClient, I can see that it is never being called. Also, if I run the program from a Command Prompt, it just prints hello. The expected output that I would hope to see is:

hello
memory leak: 44

Does anyone know why the dumpClient function is not being called at all?

David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • 1
    You created a "normal" leak, not a special one that was tagged as a "client" allocation by your code. Normal leaks are reported through the _CrtSetReportHook() hook. – Hans Passant Aug 05 '14 at 00:49

2 Answers2

2

TL;DR You may call _malloc_dbg(44, _CLIENT_BLOCK, filename, line) instead of malloc.

By looking at dbgheap.c, you can see that the only way your function can be called is there:

if (_BLOCK_TYPE(pHead->nBlockUse) == _CLIENT_BLOCK)
{
    _RPT3(_CRT_WARN, "client block at 0x%p, subtype %x, %Iu bytes long.\n",
        (BYTE *)pbData(pHead), _BLOCK_SUBTYPE(pHead->nBlockUse), pHead->nDataSize);

    if (_pfnDumpClient && !__crtIsBadReadPtr(pbData(pHead), pHead->nDataSize))
    {
        (*_pfnDumpClient)((void *)pbData(pHead), pHead->nDataSize);
    }
    else
    {
        _printMemBlockData(plocinfo, pHead);
    }
}

So you must have _BLOCK_TYPE(pHead->nBlockUse) == _CLIENT_BLOCK.

When calling malloc, you only allocate _NORMAL_BLOCKs.

You may call _malloc_dbg(44, _CLIENT_BLOCK, filename, line) instead. http://msdn.microsoft.com/en-us/library/faz3a37z.aspx

Then your function will be called.

Of course Microsoft could have mentionned this in the _CrtSetDumpClient documentation, but it would've been too easy ;)

ThreeStarProgrammer57
  • 2,906
  • 2
  • 16
  • 24
  • Thanks! If I look at crtdbg.h (which comes with Visual Studio) I can see how `malloc(s)` is defined to be `_malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)`. I wonder why they did it that way. I also see they did something similar with `free(s)`, so I'd probably have to make my own preprocessor macro for malloc and free to get this working properly. – David Grayson Aug 05 '14 at 02:39
  • FYI, dbgheap.c can be found in `C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src` – David Grayson Aug 05 '14 at 02:41
0

As per MSDN documentation

_CrtSetDumpClient: Installs an application-defined function to 
 dump _CLIENT_BLOCK type memory blocks 

The keyword here being _CLIENT_BLOCK. The various types of blocks on heap are documented here. A simple malloc call creates a _NORMAL_BLOCK and hence your function is not called.

parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85