I had a memory leak in my big program, detected by the Visual Studio CRT debug system. I reduced my program to the following, with still shows a memory leak.
#include "stdafx.h"
#include "crtdbg.h"
int main()
{
int tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag(tmp | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
int* k = new int(8);
delete k;
return 0;
}
When I run it in my Visual Studio 2012 system, I see the following:
Detected memory leaks!
Dumping objects ->
{65} normal block at 0x00663008, 4424 bytes long.
Data: <X #f > 58 CF 14 00 90 23 66 00 01 00 00 00 00 00 00 00
{64} normal block at 0x00662390, 4 bytes long.
Data: < > 00 C3 14 00
Object dump complete.
If I remove the allocation and deallocation, the leaks don't appear. If I replace the allocation and deallocation by any standard library feature that uses memory allocation (e.g. std::string k), the leaks appear.
Why do the memory leaks appear? How can I remove them?
I tried debugging my problem by setting _crtBreakAlloc to 64; the system stopped at a place that is supposed to help me (see stack trace below). But I don't know what to do with this info.
> test_it.exe!_heap_alloc_dbg_impl(unsigned int nSize, int nBlockUse, const char * szFileName, int nLine, int * errno_tmp) Line 393 C++
test_it.exe!_nh_malloc_dbg_impl(unsigned int nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine, int * errno_tmp) Line 239 C++
test_it.exe!_nh_malloc_dbg(unsigned int nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine) Line 302 C++
test_it.exe!malloc(unsigned int nSize) Line 56 C++
test_it.exe!_PlatformSpecificMalloc() Unknown
test_it.exe!MemoryLeakWarningPlugin::ignoreAllLeaksInTest(void) Unknown
test_it.exe!operator new(unsigned int) Unknown
test_it.exe!MemoryLeakWarningPlugin::getGlobalDetector(void) Unknown
test_it.exe!std::error_condition::value(void) Unknown
test_it.exe!operator new(unsigned int) Unknown
test_it.exe!main() Line 9 C++
My system is:
Microsoft Visual Studio Professional 2012
Version 11.0.61030.00 Update 4
Visual C++ 2012 04938-004-0034007-02224
Windows 7
Your call stack suggests that there is another memory leak tool being used, besides the Visual C++ runtime functions.
Using google takes me to this link: https://github.com/auser/cpputest/blob/master/src/CppUTest/MemoryLeakWarningPlugin.cpp
So possibly, cppuTest is being applied to your simple project without you being aware of it.
I suggest you create a brand new Win32 Console application, copy and paste your code, and retest. Make sure that the new project has no additional dependencies.
Just tried it with clean VS 2012 installation with Deleaker installed. No leaks shown. And no output from CRT in the final.
What is MemoryLeakWarningPlugin mentioned in the stack trace? Seems it's a part CppUTest (I did Google a bit).
I think either MemoryLeakWarningPlugin leaks itself or it breaks CRT diagnostic system somehow.
Related
I am getting a memory leak when I run try to read from Clipboard.
Sample code:
void SomeFunction()
{
OpenClipboard(nullptr);
HGLOBAL hglb = GetClipboardData(CF_TEXT);
char* ch = static_cast<char*>(GlobalLock(hglb));
CString rawClipboardData(ch);
GlobalUnlock(hglb);
CloseClipboard();
}
It is the middle row above which causes the memory leak according to Visual Studio. This row:
CString rawClipboardData(ch);
If I do not run it, there is no leak reported.
But if I do run it I get the following debug output in visual studio output window:
Detected memory leaks!
Dumping objects ->
f:\dd\vctools\vc7libs\ship\atlmfc\src\strcore.cpp(158) : {75645} normal block at 0x00000000072C89A0, 52 bytes long.
Data: <`x > 60 78 F7 D3 FE 07 00 00 0D 00 00 00 0D 00 00 00
Object dump complete.
Any ideas?
UPDATE: Added OpenClipboard(nullptr) in code above. Also in real code there are nullptr-checks. Just keeping it clean here to reduce amount of guard-clause code.
GlobalLock(hglb) should be a LPTSTR so I would assume that the leak is caused by the cast to char*. For Unicode platforms, TCHAR is defined as synonymous with the WCHAR type.
you should be able to do something like
CString rawClipboardData = GlobalLock(hglb);
If not then
CString rawClipboardData;
LPTSTR lptstr = GlobalLock(hglb);
rawClipboardData = lptstr;
will definitely work
I'm on windows, qt 4.7. part of my code takes a FILE* from a file which is open for reading by another part of the system (legacy, C). I open a QTextStream as follows:
// file currently opened (readonly), and partially read
FILE *infile = function_to_get_file_pointer();
QTextStream is(infile, QIODevice::ReadOnly);
The second line crashes when built in release mode but is fine in debug. I can step through the debug version and see the QFile that is opened internally by QTextStream.
The most I've managed to get out of the windows call stack in release mode at the time of the crash is below:
ntdll.dll!77450226()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!77450142()
msvcr80.dll!_lock_file(_iobuf * pf=0x71962148) Line 241 + 0xa bytes C
msvcr80.dll!_ftelli64(_iobuf * stream=0x71962148) Line 51 + 0x8 bytes C
QtCore4.dll!6708b87d()
QtCore4.dll!67099294()
QtCore4.dll!6713d491()
which could be a red herring but look like something's gone wrong trying to lock the file. Prior to this, I have enabled debug output for my code so I know that it is the QTextStream creation that is causing the problem.
I welcome any suggestions!
After some further digging, I have found that the file, although ASCII, is originally fopened with "rb" in order to stop the win32 CRT converting line endings from \r\n to \n.
I assumed this would be confusing Qt so modified the fopen to use "r" only. Then a comment below linked to here which shows that the FILE* should be opened in binary mode, e.g. "rb", so this is not a problem.
Trying tezrigs suggestion below, freopen on the FILE* gives the following:
msvcr100.dll!_crt_debugger_hook(int _Reserved=8633404) Line 65 C
msvcr100.dll!_call_reportfault(int nDbgHookCode=2, unsigned long dwExceptionCode=3221226519, unsigned long dwExceptionFlags=1) Line 167 + 0x6 bytes C++
msvcr100.dll!_invoke_watson(const wchar_t * pszExpression=0x00000000, const wchar_t * pszFunction=0x00000000, const wchar_t * pszFile=0x00000000, unsigned int nLine=0, unsigned int pReserved=8633376) Line 155 + 0xf bytes C++
msvcr100.dll!_invalid_parameter(const wchar_t * pszExpression=0x00000000, const wchar_t * pszFunction=0x00000000, const wchar_t * pszFile=0x00000000, unsigned int nLine=0, unsigned int pReserved=0) Line 110 + 0x14 bytes C++
msvcr100.dll!_invalid_parameter_noinfo() Line 121 + 0xc bytes C++
msvcr100.dll!_freopen_helper(_iobuf * * pfile=0x0083bc3c, const char * filename=0x00000000, const char * mode=0x013ee350, _iobuf * str=0x71962148, int shflag=64) Line 31 + 0x1f bytes C
msvcr100.dll!freopen(const char * filename=0x00000000, const char * mode=0x013ee350, _iobuf * str=0x71962148) Line 111 C
The exception code passed to _call_report_fault is 0x0000417 - Fatal Error: Unknown Software Exception, which isn't much help..
OK: more detail, and some self contained, replicable code (myfile.txt must be over 1000 chars long):
#include <QtCore/QCoreApplication>
#include "qtextstream.h"
#include <iostream>
int main(int argc, char *argv[])
{
// QCoreApplication a(argc, argv);
std::cin.get();
FILE *myfile = fopen("myfile.txt", "rb");
int c;
for(int i=0; i < 1000; i++)
c = getc(myfile);
fflush(myfile);
long pos = ftell(myfile);
QTextStream is(myfile, QIODevice::ReadOnly);
while(!is.atEnd())
{
QString in_line = is.readLine();
std::cout << in_line.toStdString();
}
fseek(myfile, pos, SEEK_SET);
fclose(myfile);
return 0;
}
All the following in release mode:
This lets me attach a debugger if I run outside visual studio. If I run in outside visual studio, it crashes.
If I attach to it once it has started from outside visual studio, it crashes on construction of QTextStream.
If I start it from inside visual studio with shift-F5 (i.e. running outside the debugger) it writes the contents of the file to the display.
likewise, when running under the debugger, it works as expected.
It is down to the dlls. I have a locally compiled set of dlls (created with MSVC2010) and using them to replace those in the main product solves the problem. Ditto with the test code. The release code was using Qt compiled with 2005, using msvcr80.
All credit to #KarstenKoop - feel free to post your answer here. The problem was due to Qt dlls that were using msvcr80.dll while the rest of the application was compiled using visual studio 2010 and thus using msvcr100.dll
This link explains the perils of mixing visual studio versions quite nicely
I have an C++ application that has a main thread and a Poco::Timer to trigger a callback which writes to a file using Poco::FileOutputStream:
FileOutputStream file("test.txt", ios::binary); <-- *Access violation reading location here*
file.write(reinterpret_cast<char *>(&data), sizeof(data));
file.close();
The code always failed at the first line, here is the call stack:
testProject.exe!std::ctype::widen(char _Byte=' ') Line 1716 + 0xf bytes C++
testProject.exe!std::basic_ios >::widen(char _Byte=' ') Line 126 C++
testProject.exe!std::basic_ios >::init(std::basic_streambuf > * _Strbuf=0x038ef700, bool _Isstd=false) Line 135 + 0xa bytes C++
testProject.exe!std::basic_ostream >::basic_ostream >(std::basic_streambuf > * _Strbuf=0x038ef700, bool _Isstd=false) Line 54 C++
testProject.exe!Poco::FileOutputStream::FileOutputStream(const std::basic_string,std::allocator > & path="c:\Projects\TestProject\test.txt", int mode=32) Line 93 + 0xa3 bytes C++
testProject.exe!OPC_Server::OnTimer(Poco::Timer & timer={...}) Line 3656 + 0x13 bytes C++
testProject.exe!Poco::TimerCallback::invoke(Poco::Timer & timer={...}) Line 212 + 0x14 bytes C++
testProject.exe!Poco::Timer::run() Line 197 + 0x19 bytes C++
testProject.exe!Poco::PooledThread::run() Line 200 + 0x15 bytes C++
testProject.exe!Poco::`anonymous namespace'::RunnableHolder::run() Line 57 + 0x17 bytes C++
testProject.exe!Poco::ThreadImpl::runnableEntry(void * pThread=0x00db6afc) Line 207 + 0x20 bytes C++
testProject.exe!_callthreadstartex() Line 348 + 0xf bytes C
testProject.exe!_threadstartex(void * ptd=0x00db6d00) Line 331 C
Tracing into the stack, the timer thread seemed having problem reading the initialization _Byte at the top of the call stack in xlocale internal header:
_Elem __CLR_OR_THIS_CALL widen(char _Byte) const
{ // widen char
return (do_widen(_Byte)); <-- failed: Access violation reading location
}
Second entry in the stack in ios standard header:
_Elem __CLR_OR_THIS_CALL widen(char _Byte) const
{ // convert _Byte to character using imbued locale
const _Ctype& _Ctype_fac = _USE(getloc(), _Ctype);
return (_Ctype_fac.widen(_Byte)); <-- call the top of the stack
}
Third entry in the stack in ios standard header:
protected:
void __CLR_OR_THIS_CALL init(_Mysb *_Strbuf = 0,
bool _Isstd = false)
{ // initialize with stream buffer pointer
_Init(); // initialize ios_base
_Mystrbuf = _Strbuf;
_Tiestr = 0;
_Fillch = widen(' '); <-- call the second entry
But very strangely, the same code runs fine without any error when being used on the main thread.
Is there any permission settings that I need to set for the Poco::Timer to be able to function properly? Or am I missing something very obvious? Thanks for any help.
EDIT: ----------------------
Poco version: 1.7.3
Platform: windows
It turns out that the application exits immediately after the timer is created, but the exit is not cleanly done so it appears that the app is still running and the timer is still ticking, when actually some of the resource has already been released, which causes the error.
MS's _tmain() does something extra than main() apparently.
Sorry it is not _tmain(), but _tmainCRTStartup that is calling _tmain(). When _tmain() exits, other clean up code is run, my project isn't terminated somehow and the application appears still "running".
I'm working on a large C++ project under Visual Studio 2010 and think that there are some memory leaks inside. I tried the approach with including crtdbg.h but it does not help much as I don't see where the leaks occured. Defining new has 2 pitfalls: First it needs to be done in every cpp file which is not really an option, and 2nd it breaks with e.g. Boost. Using new(nothrow) or anything that uses boosts "has_new_operator.h" breaks this. [EDIT: It fails to compile as the redefined "new" has no overloads for something like "nothrow" or the "boost magic"] (Unless one defines "new" after all boost headers including headers referencing boost)
Last but not least: I have singletons. They are implemented using subclasses of the singleton template and a static function variable. One of them is a config container where one registers settings (pairs of strings and ints that are than stored in maps) Since the mem leak dump is called before deallocation of the singleton instance I get a massive amount of leaks for all those strings and the singleton itself.
Any way to have only the real leaks shown or make it dump after static object deallocation?
Which free tools can handle this case?
I have used the Visual Leak Detector with quite positive results. It is small and neat, and can be built into your project (assuming you have a running Debug configuration) in a matter of seconds:
https://vld.codeplex.com/
If set-up correctly (which can be done using the installer) then you only have to
#include <vld.h>
in one of your .cpp files for each module - that's it, the header will do the linking for you. You don't have to put it everywhere. Internally the tool uses the CrtDbg, so you have to have a debug build running in order for it to work.
It gives you debugger or text output after each run (if configured using a config file), even when not run through a debugger. It is not the most powerfull tool, but these usually cost some coin ;)
EDIT: There is a possibility to enable the VLD also in non-debug configurations by defining VLD_FORCE_ENABLE before including the header. But the results may be tempered with then.
EDIT: I have tried a fresh installation of VLD. Note that for VS2013 compilers the v2.4rc2 version must be used (or anything greater v2.3). Version v2.3 only works up until VS2010 compilers.
After installation I created a new project and set-up my include- and library-directories to include the respective VLD folders. After that I used the following code to test memleak reports of singletons (note that this code doesn't make sense, it just proves a point):
#include <iostream>
#include <string>
#include <sstream>
#include <map>
// Uncomment this, if you want VLD to work in non-debug configurations
//#define VLD_FORCE_ENABLE
#include <vld.h>
class FooSingleton {
private:
std::map<std::string, std::string*>
_map;
FooSingleton() {
}
public:
static FooSingleton* getInstance(void) {
/* THIS WOULD CAUSE LEAKS TO BE DETECTED
SINCE THE DESTRUCTOR WILL NEVER BE CALLEd
AND THE MAP IS NOT CLEARED.
*/
// FooSingleton* instance = new FooSingleton;
// return instance;
static FooSingleton instance;
return &instance;
}
void addString(const std::string& val) {
_map.insert(std::make_pair(val, new std::string(val)));
}
~FooSingleton(void) {
auto it = _map.begin();
auto ite = _map.end();
for(; it != ite; ++it) {
delete it->second;
}
}
};
int main(int argc, char** argv) {
FooSingleton* fs = FooSingleton::getInstance();
for(int i = 0; i < 100; ++i) {
std::stringstream ss;
ss << i << "nth string.";
fs->addString(ss.str());
}
return 0;
}
With this code, the VLD does not report any leaks because the static auto-variable in getInstance() will be destructed upon exit and the elements in the map will be deleted. This must be done nevertheless, even if it's a singleton, otherwise the leaks will be reported. But in this case:
Visual Leak Detector Version 2.3 installed.
Aggregating duplicate leaks.
Outputting the report to the debugger and to D:\dev\projects\tmp\memleak\memleak\memory_leak_report.txt
No memory leaks detected. Visual Leak Detector is now exiting.
If the code in the getInstance() is changed to the commented version, then the singleton is never cleared up and the following leaks (amongst others) is reported:
---------- Block 11 at 0x008E5928: 52 bytes ----------
Leak Hash: 0x973608A9 Count: 100
Call Stack:
c:\program files (x86)\microsoft visual studio 10.0\vc\include\xmemory (36): memleak.exe!std::_Allocate<std::_Tree_nod<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > *,std::less<std::basic_string<char,std::char_traits<char>,std::alloca + 0x15 bytes
c:\program files (x86)\microsoft visual studio 10.0\vc\include\xmemory (187): memleak.exe!std::allocator<std::_Tree_nod<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > *,std::less<std::basic_string<char,std::char_traits<char>,std::alloca + 0xB bytes
c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree (560): memleak.exe!std::_Tree_val<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,s + 0xD bytes
c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree (588): memleak.exe!std::_Tree_val<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,s + 0x8 bytes
c:\program files (x86)\microsoft visual studio 10.0\vc\include\xtree (756): memleak.exe!std::_Tree<std::_Tmap_traits<std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::basic_string<char,std::char_traits<char>,std::allocator<char> > *,std::less<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std:: + 0x17 bytes
d:\dev\projects\tmp\memleak\memleak\main.cpp (33): memleak.exe!FooSingleton::addString + 0xA9 bytes
d:\dev\projects\tmp\memleak\memleak\main.cpp (51): memleak.exe!main + 0x37 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (555): memleak.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): memleak.exe!mainCRTStartup
0x76BF919F (File and line number not available): KERNEL32.DLL!BaseThreadInitThunk + 0xE bytes
0x7739A22B (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x84 bytes
0x7739A201 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x5A bytes
Data:
C0 53 8E 00 30 67 8E 00 C0 53 8E 00 98 58 8E 00 .S..0g.. .S...X..
30 6E 74 68 20 73 74 72 69 6E 67 2E 00 CD CD CD 0nth.str ing.....
0C 00 00 00 0F 00 00 00 CD CD CD CD 48 56 8E 00 ........ ....HV..
01 00 CD CD
You can clearly see the Count: 100 for this block of code, which is correct.
I also edited my vld.ini file in the installation directory to have the following set to be enabled:
AggregateDuplicates = yes
ReportTo = both
These make sure that a) all duplicate leaks are squashed together to one report with a leak-count (as above, otherwise there would be 100 entries) and the other so that a report-file is dumped in the directory of the application.
So for singletons it works fine as long as you use the static auto-variable approach you are using and do your cleanup in the destructor.
EDIT: Also, the instrumentation can be disabled at specific code pieces. If the above code would be modified like this:
void addString(const std::string& val) {
VLDDisable();
_map.insert(std::make_pair(val, new std::string(val)));
VLDEnable();
}
The leaks will never be profiled and not tracked.
You can get memory leaks source from crtdebug. it won't help you with the boost allocations, unless you compile boost (or any library) in the same way, but for the rest, it will show you allocation file and line.
This is how you use properly the crtdebug.h:
in the top of your stdafx.h (or any PCH file) add the following lines:
#ifdef DEBUG
//must define both _CRTDBG_MAP_ALLOC and _CRTDBG_MAP_ALLOC_NEW
#define _CRTDBG_MAP_ALLOC
#define _CRTDBG_MAP_ALLOC_NEW
#include <stdlib.h>
#include <crtdbg.h>
//if you won't use this macro you'll get all new as called from crtdbg.h
#define DEBUG_NEW new( _CLIENT_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
Now in the beginning of your main or winmain or any entry point to your program add the following lines:
//register memory leak check at end of execution:
//(if you use this you won't need to use _CrtDumpMemoryLeaks at the end of your main)
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
//set report mode:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
Now here a small test I've made:
After a new console program from VS10 called "test":
My stdafx.h:
#pragma once
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#define _CRTDBG_MAP_ALLOC_NEW
#include <stdlib.h>
#include <crtdbg.h>
#define DEBUG_NEW new( _CLIENT_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
and my test.cpp is:
#include "stdafx.h"
void CheckMemoryLeak()
{
char *ptr=new char[100];
int n=900;
sprintf(ptr,"%d",n);
}
int _tmain(int argc, _TCHAR* argv[])
{
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
CheckMemoryLeak();
return 0;
}
Output is:
'tests.exe': Loaded 'C:\Users\shr\Documents\Visual Studio 2010\Projects\tests\Debug\tests.exe', Symbols loaded.
'tests.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll', Cannot find or open the PDB file
'tests.exe': Loaded 'C:\Windows\SysWOW64\kernel32.dll', Cannot find or open the PDB file
'tests.exe': Loaded 'C:\Windows\SysWOW64\KernelBase.dll', Cannot find or open the PDB file
'tests.exe': Loaded 'C:\Windows\SysWOW64\msvcr100d.dll', Symbols loaded.
Detected memory leaks!
Dumping objects ->
c:\users\shr\documents\visual studio 2010\projects\tests\tests\tests.cpp(9) : {97} client block at 0x01003288, subtype 0, 100 bytes long.
Data: <900 > 39 30 30 00 CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
The program '[1600] tests.exe: Native' has exited with code 0 (0x0).
I recently experienced a memory leak issue. I troubleshooted the issue for quite a long time and subsequently found out that throwing an exception (I use my own exception classes) causes this memory leak. The code of throwing the exception is as following:
HINSTANCE lib = LoadLibrary(path.c_str());
if(!lib)
{
DWORD werror = GetLastError();
ostringstream stream;
stream << werror;
string errstring = "Error " + stream.str();
errstring.append(" - " + libraryName);
throw LibraryLoadException(MOD_ERROR_LIB_LOAD, errstring.c_str());
}
The resulting output looks like:
Detected memory leaks!
Dumping objects ->
{351} normal block at 0x0044D208, 32 bytes long.
Data: <Error 126 - note> 45 72 72 6F 72 20 31 32 36 20 2D 20 6E 6F 74 65
{347} normal block at 0x0043BD98, 8 bytes long.
Data: <4 > > 34 F2 3E 00 00 00 00 00
{344} normal block at 0x0043FDE8, 32 bytes long.
Data: <126 > 31 32 36 CD CD CD CD CD CD CD CD CD CD CD CD CD
{302} normal block at 0x004409D8, 8 bytes long.
Data: <4 > > 34 F3 3E 00 00 00 00 00
{301} normal block at 0x0043FAF0, 8 bytes long.
Data: <P > > 50 F3 3E 00 00 00 00 00
Object dump complete.
As seen in the output of the visual studio leak CrtDbg, there are actual values of the objects used in the if block. All these objects including the exception itself (and all its attributes) are allocated on stack, though, so there cannot be a fault of me forgetting to deallocate something on heap.
I empirically tested this and the leak is definitely caused by the objects in the if block (after removing several objects like the string, DWORD and the stream the leaks grow fewer).
Can anyone tell me what am I doing (or what is) wrong over here?
Thank You in advance
As for the comments asking for more detailed code, here is the method causing memory leak:
void ModuleLoader::load(std::string libraryName, std::string type, void(CALLBACK * receiveData)(Message))
{
path = s2ws(libraryName); // conversion to wide string
HINSTANCE lib = LoadLibrary(path.c_str());
if(!lib)
{
DWORD werror = GetLastError();
ostringstream stream;
stream << werror;
string errstring = "Error " + stream.str();
errstring.append(" - " + libraryName);
throw LibraryLoadException(MOD_ERROR_LIB_LOAD, errstring.c_str());
}
DllModule *module = new DllModule(libraryName, lib);
module->setModType(type);
try
{
startModule(module, receiveData);
moduleMap.insert(std::pair<std::string, DllModule *>(type, module));
}
catch (ProbeCoreException e)
{
delete module;
throw e;
}
}
It is a method of a singleton class that loads dynamic modules, defined as following:
class ModuleLoader
{
// Function pointer definitions
typedef void (*StopFuncPointer)();
typedef int (*StartFuncPointer)(void(CALLBACK * receiveData)(Message));
typedef void (*SetDataFunctionPointer)(Message);
private:
std::map<std::string, DllModule *> moduleMap; // map of loaded modules
std::wstring path;
std::wstring s2ws(const std::string &s);
void startModule(DllModule * module, void(CALLBACK * receiveData)(Message));
void stopModule(DllModule * module);
// singleton functions
ModuleLoader() {}; // private constructor
ModuleLoader(ModuleLoader const&);
void operator = (ModuleLoader const&);
public:
void load(std::string libraryName, std::string type, void(CALLBACK * receiveData)(Message));
void unload(std::string libraryType);
void unloadAll();
vector<DllModule> getLoadedModules();
int containsModuleType(string modType);
HINSTANCE getModuleLibraryByType(std::string type);
// singleton getInstance function
static ModuleLoader & getInstance()
{
static ModuleLoader instance;
return instance;
}
};
The s2ws method converts a common string to wide string (i post it just in case):
std::wstring ModuleLoader::s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
I checked many times and deallocating heap objects when the exception is thrown should be carried out at all levels of the application.
Furthermore, if I do remove the DWORD, ostringstream and string objects (allocated on stack), the memory leaks grow fewer...so it HAS to be in connection with these as well. I cannot imagine how removing this part of the code should help heap memory deallocation elsewhere:
DWORD werror = GetLastError();
ostringstream stream;
stream << werror;
string errstring = "Error " + stream.str();
errstring.append(" - " + libraryName);
OK, I managed to reduce the leaks to just two of original 5:
Dumping objects ->
{312} normal block at 0x0045FDC8, 8 bytes long.
Data: <( ( > 28 ED 28 00 00 00 00 00
{311} normal block at 0x0045F810, 8 bytes long.
Data: <D ( > 44 ED 28 00 00 00 00 00
Object dump complete.
I used _CrtSetBreakAlloc(x) function with the x being a number of the leak (e.g. 311 or 312 in the case like above) and found out, where is the unallocated memory allocated. It is really difficult to believe it, but the allocations really occured on these lines:
string errstring = "Error " + stream.str();
and
errstring.append(" - " + libraryName);
I removed the leaks by making the string and stream dynamically allocated on heap, then creating the exception and storing it in a temporary variable, subsequently deallocating the string and stream variables and finally throwing the exception itself:
DWORD werror = GetLastError();
ostringstream *stream = new ostringstream();
*stream << werror;
string *errstring = new string("Error ");
errstring->append(stream->str());
errstring->append(" - ");
errstring->append(libraryName);
ProbeCoreException e = LibraryLoadException(MOD_ERROR_LIB_LOAD,
errstring->c_str());
delete errstring;
delete stream;
throw e;
The last two allocations occur (once again unbelievably) during passing string parameters to the "load" function itself:
loader.load("notexisting.dll", "TEST", &callbackFunction);
I was contemplating about the leaks occuring due to the class being a singleton, the class was created according to leak-proof singleton rules, though, mentioned here:
C++ Singleton design pattern
It seems that the only chance how to get rid of the resting leaks is to pass string pointers even as parameters and then dealloc them explicitly...