Search code examples
windowsvisual-studiovisual-c++c++-climanaged-c++

Visual C++ memory leak


I have a serial communication library I am creating, and it is a managed assembly, which comes with it's own rules (I do not fully understand them, I just change code when VS complains), and I have a memory leak that I cannot figure out.

This is the leak warning that I get (line 11 is the InfoContainer constructor in SerialComm::SerialComm()):

Detected memory leaks!
Dumping objects ->
SerialComm.cpp(11) : {144} normal block at 0x011468B8, 56 bytes long.
Data: <                > 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.

This is the .h file for the lib:

#include <windows.h>
#include <stdlib.h>
#include <atlstr.h>

public class InfoContainer {
public:
    ~InfoContainer();
    HANDLE handle;
    bool connected;
    COMSTAT status;
    DWORD errors;
    DCB connection_params;
    CStringA port_name;
};

public ref class SerialComm {
public:
    InfoContainer* info=0;
    SerialComm();
    ~SerialComm();
    bool OpenConnection(String^ Portname);
    int CloseConnection();
    bool WriteData(String^ toSend);
    String^ ReadData(int bytesToRead);
};

and these are the relevant .cpp sections:

SerialComm::SerialComm() {
    info = new (_NORMAL_BLOCK, __FILE__, __LINE__) InfoContainer();
    info->handle = 0;
}
SerialComm::~SerialComm() {
    CloseConnection();
    delete info;
}

bool SerialComm::OpenConnection(String ^ Portname) {
    info->port_name = Portname;

    //visual studio's valgrindish tool
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    _CrtDumpMemoryLeaks();


    info->handle = CreateFileA(
        info->port_name,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        0,
        NULL

    );
    if (info->handle == INVALID_HANDLE_VALUE) {
        ATLTRACE("Error: %d", GetLastError());
        printf("Error: %d\n", GetLastError());
        return false;
    }
    //
    //rest of connection code here
    //
}

int SerialComm::CloseConnection() {
    return CloseHandle(info->handle);
}

InfoContainer::~InfoContainer() {
    delete handle;
}

The reason I have to use an InfoContainer class and InfoContainer pointer in the main class is that some information I need to store is considered unmanaged code and so I cannot have it directly in the main class.

Thanks in advance!


Solution

  • The problem is _CrtDumpMemoryLeaks() is called before all objects are deleted.

    You need a finalizer. Following is the "golden pattern" when you write a class in C++/CLI:

    virtual ~SerialComm()
    {
        this->!SerialComm();
    }
    
    !SerialComm()
    {
    }
    

    Don't forget to add virtual to your destructor. The reason why virtual destructor is needed should be explained in any good C++ textbooks.