Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why does MFC call _CrtDumpMemoryLeaks ?!?

291 views
Skip to first unread message

Martin T.

unread,
Jul 11, 2008, 9:28:23 AM7/11/08
to
(I think this applies to mfc & C++ & debugging, hence the 3 NG)

OK, maybe this'll be some kind of rant, but I really don't get it and it
would really be nice to know what the rationale behind the "built-in"
memory leak detection of MFC is, when any user could provide it on his
own without false memory leaks ...

Explanation:
The Run-Time Library provides for Debug Routines that (among other
things) allow reporting of memory-leaks.
It is possible to enable *automatic* reporting for the CRT by calling
the function _CrtSetDbgFlag(...) with the _CRTDBG_LEAK_CHECK_DF flag.
If you choose to enable this *automatic* check in your C++ program, the
CRT will happily (and most correctly) report all left-over memory via
_CrtDumpMemoryLeaks *after* basically all non-system DLLs have been
unloaded.

Enter MFC:
For reasons unknown to me (but probably historical or some such $%&$)
/if/ your Application links against the MFC DLL /then/ within the d'tor
of a class called _AFX_DEBUG_STATE (atlmfc/src/mfc/dumpinit.cpp, ln 123)
MFC will call _CrtDumpMemoryLeaks and afterwards disable the reporting
on process-end:
###################
_AFX_DEBUG_STATE::~_AFX_DEBUG_STATE()
{
#ifndef _AFX_NO_DEBUG_CRT
_CrtDumpMemoryLeaks();
int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(nOldState & ~_CRTDBG_LEAK_CHECK_DF);

ASSERT(_CrtSetReportHook2(_CRT_RPTHOOK_REMOVE,_AfxCrtReportHook) != -1);
_CrtSetDumpClient(pfnOldCrtDumpClient);
#endif // _AFX_NO_DEBUG_CRT
}
###################

Not only is this completely unnecessary, as you could (if you so wished)
tell the CRT to dump it on process end - oh no! It is quite horrible if
you use a 3rd party C++ DLL that happens to hold memory in global static
objects that will only be destroyed when this DLL is unloaded and does
*not* link against MFC.
That is because in all my test cases any user-supplied DLL (project
dependency, via Linker-Input:lib) is always unloaded *after* the MFC-DLL
(mfc80ud.dll in my case).
In this scenario the stupid call of _CrtDumpMemoryLeaks from the MFC
cleanup code will report all this memory as leaks, even though it *will*
be cleaned up --- it just happens that the code had the cheek to not use
MFC.

* You can't work around it, as you cannot change DLL (static)
load/unload order.
* You can't work around it, as you cannot use a C++ DLL with
LoadLibrary/FreeLibrary.
* You can't work around it, as you cannot tell MFC not to report this
false memleaks and use the CRT mechanism instead.
* You can't work around it, as your main application needs to use MFC.
* You can't work around it, as the 3rd party DLL cannot, in general, be
made to link against MFC (thereby forcing a later unload of mfc80ud.dll)
* You can't even ignore the MFC dump and additionally use the CRT dump
as MFC will switch it off after it dumped!

Bah!


So ... I'm stuck with a program that dumps 2000 memory leaks at
MFC-cleanup that are false and will obscure any real (and possibly
problematic) memleaks I would like to find ...

It would be interesting to hear from someone who knows a rational behind
the MFC code or has some general thoughts how to get around it or to
hear why I'm completely mistaken :)


cheers,
Martin

Carl Daniel [VC++ MVP]

unread,
Jul 11, 2008, 9:45:26 AM7/11/08
to
Martin T. wrote:
> (I think this applies to mfc & C++ & debugging, hence the 3 NG)
>
> OK, maybe this'll be some kind of rant, but I really don't get it and
> it would really be nice to know what the rationale behind the
> "built-in" memory leak detection of MFC is, when any user could
> provide it on his own without false memory leaks ...
>
> * You can't work around it, as you cannot change DLL (static)
> load/unload order.

Actually, you probably can - If you call LoadLibrary on the MFC DLL
yourself, that should push it to the back of the unload order since it's
refcount won't go to zero.

-cd


Doug Harrison [MVP]

unread,
Jul 11, 2008, 12:34:08 PM7/11/08
to

The rationale is that it was a mistake. (The real question is, "Why won't
they fix it?") For a workaround for those non-MFC DLLs you mentioned, see
if these threads help:

http://groups.google.com/group/microsoft.public.vc.debugger/msg/6b90e68f21529e56

http://groups.google.com/group/microsoft.public.vc.mfc/browse_frm/thread/73493ddec165a5cb/e651b944da9c619d?#e651b944da9c619d

Though I never tried it, the second one should help with those DLLs you
can't modify.

--
Doug Harrison
Visual C++ MVP

Martin T.

unread,
Jul 14, 2008, 3:55:41 AM7/14/08
to
Doug Harrison [MVP] wrote:
> On Fri, 11 Jul 2008 15:28:23 +0200, "Martin T." <0xCDC...@gmx.at> wrote:
>
>> .......

>>
>> It would be interesting to hear from someone who knows a rational behind
>> the MFC code or has some general thoughts how to get around it or to
>> hear why I'm completely mistaken :)
>
> The rationale is that it was a mistake. (The real question is, "Why won't
> they fix it?")

I think this actually is a relly big question, especially with the noise
Microsoft made with the "MFC Update Powered By BCGSoft" / "... the
Visual C++ team decided to reinvest in MFC ..."
Since people are working on it anyways, fix it fcs!
(Haven't tried it with VS 2008.)

> For a workaround for those non-MFC DLLs you mentioned, see
> if these threads help:
>
> http://groups.google.com/group/microsoft.public.vc.debugger/msg/6b90e68f21529e56
>
> http://groups.google.com/group/microsoft.public.vc.mfc/browse_frm/thread/73493ddec165a5cb/e651b944da9c619d?#e651b944da9c619d
>
> Though I never tried it, the second one should help with those DLLs you
> can't modify.
>

Thank you, thank you, thank you :-)
I really can't think why that thread never turned up in my google
searches, esp. since I tried to solve this problem twice during the last
few months. (I guess I haven't google'd groups after I found the
_AFX_DEBUG_STATE code, though)

http://groups.google.com/group/microsoft.public.vc.mfc/browse_frm/thread/73493ddec165a5cb/e651b944da9c619d?#e651b944da9c619d
really solves the problem.
Might I add two points:
* On my Visual Studio 2005 I have to use a symbol from the DLL I create
to hold the MemoryLeakDetector object or otherwise the linker will not
load the DLL.
* I have added trace messages to to the ctor and dtor of the class:
_RPT0(_CRT_WARN, "== MemoryLeakDetector ==\n");

Allow me to re-post the code below and confirm that this is indeed
working with Visual Studio 2005.

cheers,
Martin

[ HEADER ]
#pragma once

#ifdef _DEBUG

#ifdef IGNORE_MFC_LEAKS_EXPORTS
#define IGNORE_MFC_LEAKS_API __declspec(dllexport)
#else
#define IGNORE_MFC_LEAKS_API __declspec(dllimport)
#endif

IGNORE_MFC_LEAKS_API int use_ignore_mfc_leaks(void);

#endif // _DEBUG

[ CPP ]
// ignore_mfc_leaks.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "ignore_mfc_leaks.h"
#include <crtdbg.h>
#include <string.h>

#ifdef _DEBUG

// Dummy function to make sure the DLL is loaded:
IGNORE_MFC_LEAKS_API int use_ignore_mfc_leaks(void)
{
return 0;
}

static _CRT_REPORT_HOOK prevHook;
static bool SwallowReport;

class MemoryLeakDetector
{
public:
MemoryLeakDetector();
virtual ~MemoryLeakDetector();
};

int ReportingHook( int reportType, char* userMessage, int* retVal );


MemoryLeakDetector::MemoryLeakDetector()
{
_RPT0(_CRT_WARN,
"===============MemoryLeakDetector=====================\n");

//don't swallow assert and trace reports
SwallowReport = false;
//change the report function
prevHook = _CrtSetReportHook(ReportingHook);
}

//this destructor is called after mfc has died
MemoryLeakDetector::~MemoryLeakDetector()
{
//make sure that there is memory leak detection at the end of the program
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) |
_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF);

//reset the report function to the old one
_CrtSetReportHook(prevHook);
_RPT0(_CRT_WARN, "=============== ~
MemoryLeakDetector=====================\n");
}

static MemoryLeakDetector MLD; //this lives as long as this translation
unit

int ReportingHook( int reportType, char* userMessage, int* retVal )
{
//_CrtDumpMemoryLeaks() outputs "Detected memory leaks!\n" and calls
//_CrtDumpAllObjectsSince(NULL) which outputs all leaked objects,
//ending this (possibly long) list with "Object dump complete.\n"
//In between those two headings I want to swallow the report.

if ((strcmp(userMessage,"Detected memory leaks!\n") == 0) ||
SwallowReport) {
if (strcmp(userMessage,"Object dump complete.\n") == 0)
SwallowReport = false;
else
SwallowReport = true;
return true; //swallow it
}
else
return false; //give it back to _CrtDbgReport()
};

#endif // _DEBUG

Martin T.

unread,
Jul 14, 2008, 3:59:58 AM7/14/08
to

I have tried calling LoadLibrary(_T("mfc80ud.dll")); and
LoadLibrary(_T("mfc80DEU.dll")); in main() but the MFC DLL still will be
unloaded before a user-supplied statically linked DLL.

cheers,
martin

Doug Harrison [MVP]

unread,
Jul 14, 2008, 12:18:15 PM7/14/08
to
On Mon, 14 Jul 2008 09:55:41 +0200, "Martin T." <0xCDC...@gmx.at> wrote:

>I really can't think why that thread never turned up in my google
>searches, esp. since I tried to solve this problem twice during the last
>few months.

Google Groups search has been on the fritz for a long, long time now. It's
incomplete and inconsistent.

0 new messages