0

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

  • 1
    Please post a complete example, along with the `catch` clause where the exception is caught. – Sergey Kalinichenko Feb 15 '14 at 18:44
  • Where did "libraryName" come from? Is this code really standalone as you've posted, or is it part of a member function from a class or struct? If it is the latter, then memory leaks can be caused by the non-destruction of the object you've allocated that contains this function. – PaulMcKenzie Feb 15 '14 at 19:30

2 Answers2

0

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);
0

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...

Community
  • 1
  • 1