0

I've really been looking through similar posts, but couldn't really find anything that fits my issue.

I'm trying to make a basic program that makes queries with a MySQL database, and it all works fine, but I have a lot of memory leaks.

#include <cppconn/driver.h>

#include <crtdbg.h>

int main() {

    {
        sql::Driver* driver = get_driver_instance();
    }

    _CrtDumpMemoryLeaks();
    return 0;
}

This is a small snippet of what I'm using. The rest of it isn't really relevant, since I've observed that even this small bit of code yields a lot of memory leaks, as given by the _CrtDumpMemoryLeaks call.

I got the 64bit version and used the dynamically linked library. What I observed is that I also needed to link the boost library separately, so I downloaded it and put its "include" directory as well.

I'm using Visual Studio 2019 Community.

Any help would be greatly appreciated. Cheers!

This is the output after running the program.

Detected memory leaks!
Dumping objects ->
{193} normal block at 0x0000014FB1F74710, 16 bytes long.
 Data: < F  O           > 90 46 FA B1 4F 01 00 00 00 00 00 00 00 00 00 00 
{192} normal block at 0x0000014FB1FA4670, 88 bytes long.
 Data: < (  O    (  O   > 00 28 F6 B1 4F 01 00 00 00 28 F6 B1 4F 01 00 00 
{191} normal block at 0x0000014FB1F8CC30, 24 bytes long.
 Data: <  g             > 18 03 67 C5 FE 7F 00 00 01 00 00 00 01 00 00 00 
{190} normal block at 0x0000014FB1F8C7B0, 24 bytes long.
 Data: <  d             > A8 96 64 C5 FE 7F 00 00 02 00 00 00 01 00 00 00 
{189} normal block at 0x0000014FB1F5E280, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{188} normal block at 0x0000014FB1F57FE0, 168 bytes long.
 Data: <                > 00 00 00 00 D2 04 00 00 88 00 00 00 00 00 00 00 
{187} normal block at 0x0000014FB1F5F5A0, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{186} normal block at 0x0000014FB1F61720, 56 bytes long.
 Data: <                > 00 00 00 00 D2 04 00 00 18 00 00 00 00 00 00 00 
{185} normal block at 0x0000014FB1F71050, 48 bytes long.
 Data: <                > 00 00 00 00 D2 04 00 00 10 00 00 00 00 00 00 00 
{184} normal block at 0x0000014FB1F70DB0, 40 bytes long.
 Data: <        p   O   > 00 00 00 00 CD CD CD CD 70 10 F7 B1 4F 01 00 00 
{183} normal block at 0x0000014FB1F70D40, 48 bytes long.
 Data: <                > 00 00 00 00 D2 04 00 00 10 00 00 00 00 00 00 00 
{182} normal block at 0x0000014FB1F710C0, 40 bytes long.
 Data: <        `   O   > 00 00 00 00 CD CD CD CD 60 0D F7 B1 4F 01 00 00 
{181} normal block at 0x0000014FB1F64C10, 80 bytes long.
 Data: <h i     dRi     > 68 C6 69 C5 FE 7F 00 00 64 52 69 C5 FE 7F 00 00 
{180} normal block at 0x0000014FB1F743F0, 16 bytes long.
 Data: <         L  O   > 01 00 00 00 00 00 00 00 10 4C F6 B1 4F 01 00 00 
{179} normal block at 0x0000014FB1F5BF60, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{178} normal block at 0x0000014FB1F57280, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{177} normal block at 0x0000014FB1F55310, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{176} normal block at 0x0000014FB1F55560, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{175} normal block at 0x0000014FB1F5E560, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{174} normal block at 0x0000014FB1F55EE0, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{173} normal block at 0x0000014FB1F57530, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{172} normal block at 0x0000014FB1F57C50, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{171} normal block at 0x0000014FB1F57960, 104 bytes long.
 Data: <                > FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 
{170} normal block at 0x0000014FB1F744E0, 8 bytes long.
 Data: <8 d     > 38 94 64 C5 FE 7F 00 00 
{169} normal block at 0x0000014FB1F62560, 24 bytes long.
 Data: <0 d      D  O   > 30 8C 64 C5 FE 7F 00 00 E0 44 F7 B1 4F 01 00 00 
{168} normal block at 0x0000014FB1F743A0, 16 bytes long.
 Data: <  f     `%  O   > F0 FE 66 C5 FE 7F 00 00 60 25 F6 B1 4F 01 00 00 
{167} normal block at 0x0000014FB1F62800, 88 bytes long.
 Data: <pF  O   pF  O   > 70 46 FA B1 4F 01 00 00 70 46 FA B1 4F 01 00 00 
{166} normal block at 0x0000014FB1F74850, 16 bytes long.
 Data: < s              > 98 73 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
{162} normal block at 0x0000014FB1F65510, 80 bytes long.
 Data: < U  O    U  O   > 10 55 F6 B1 4F 01 00 00 10 55 F6 B1 4F 01 00 00 
{161} normal block at 0x0000014FB1F74F30, 16 bytes long.
 Data: <                > D8 D4 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
{160} normal block at 0x0000014FB1F73080, 120 bytes long.
 Data: < 0  O    0  O   > 80 30 F7 B1 4F 01 00 00 80 30 F7 B1 4F 01 00 00 
{159} normal block at 0x0000014FB1F74D00, 16 bytes long.
 Data: <                > F0 D4 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
{158} normal block at 0x0000014FB1F750C0, 16 bytes long.
 Data: <hs              > 68 73 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
{157} normal block at 0x0000014FB1F72FE0, 88 bytes long.
 Data: < /  O    /  O   > E0 2F F7 B1 4F 01 00 00 E0 2F F7 B1 4F 01 00 00 
{156} normal block at 0x0000014FB1F74350, 16 bytes long.
 Data: < X              > 00 58 E1 C5 FE 7F 00 00 00 00 00 00 00 00 00 00 
Object dump complete.

So it looks like a lot is leaking, only from calling that single method on the Driver class. The destructor is protected, so I can't call "delete" on it.

hiimsoba
  • 67
  • 1
  • 8
  • how do you know that? and what is the output? the leakage , if there is any at all of some bytes is not problematic, when you allocate some megabytes and can't free them, this gets problematic. but even then you can force the dumb of all memory. – nbk Apr 18 '20 at 21:50
  • 2
    Remember that when `main` returns, there are still global and static objects that remain in memory. Your call to `_CrtDumpMemoryLeaks` is useless if global / static objects have not had a chance to clean up after themselves. You need something more smart than putting a call inside `main` to detect memory leaks like this. – PaulMcKenzie Apr 18 '20 at 21:56

1 Answers1

1

This isn't really a memory leak, because you are checking "too early".

Here you can see how get_driver_instance is implemented:

static std::map< sql::SQLString, boost::shared_ptr<MySQL_Driver> > driver;

CPPCONN_PUBLIC_FUNC sql::mysql::MySQL_Driver * get_driver_instance()
{
    return get_driver_instance_by_name("");
}


CPPCONN_PUBLIC_FUNC sql::mysql::MySQL_Driver * get_driver_instance_by_name(const char * const clientlib)
{
    ::sql::SQLString dummy(clientlib);

    std::map< sql::SQLString, boost::shared_ptr< MySQL_Driver > >::const_iterator cit;

    if ((cit = driver.find(dummy)) != driver.end()) {
        return cit->second.get();
    } else {
        boost::shared_ptr< MySQL_Driver > newDriver;

        newDriver.reset(new MySQL_Driver(dummy));
        driver[dummy] = newDriver;

        return newDriver.get();
    }
}

You can see that a global variable driver is created, which is a map of shared_ptrs to the invidiual MySQL_Driver objects. get_driver_instance simply calls get_driver_instance_by_name("") which will return the driver driver[""] or create it if it doesn't exist.

In the shared_ptr documentation you can see that a shared_ptr will delete the pointer that was assigned to it when the shared_ptr itself is destructed. It will be destructed when the map driver is destructed, which will happen when your process is torn down - after main returns.

So, within main, the driver still exists (destructors haven't run yet), so _CrtDumpMemoryLeaks(); will report it as bogus leak.

This is basically the issue described here.

I'm not sure if there is a reliable way to run your code after the destructors though, because the order at which global destructors and atexit handlers run is not specified across different translation units.

Since you are on Windows, one idea would be to (ab)use thread-local storage callbacks, you could run code at the DLL_THREAD_DETACH step which should, as far as I know, run after the regular destructors and such. See this article. (I'm not sure about that though, so I'd be happy if someone could comment who knows this better than I do!)

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • That actually makes sense... had no idea that's what happens behind the scenes. Would using valgrind give me a better chance of looking for leaks instead? – hiimsoba Apr 18 '20 at 21:59
  • Yes, because it compares _all_ allocations and deallocations, also before/after `main`. – CherryDT Apr 18 '20 at 22:00
  • Thanks! Gotta figure out how to link everything without VS now, that shall be fun as well. – hiimsoba Apr 18 '20 at 22:01