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
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
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
Though I never tried it, the second one should help with those DLLs you
can't modify.
--
Doug Harrison
Visual C++ MVP
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
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
>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.