Strange leak in C++11 code using Juce Core [not a juce bug]


#1

Hello,

Searching for a leak in some code, I found out the following:

The following code leaks when linked to juce_core.cpp (with VS2012):

#include <thread>

void theThread()
{
}

int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
{
    std::thread * thread = new std::thread(theThread);

    thread->join();

    delete thread;

    return 0;
}

Why should this code be affected by juce_core? (or how could this code affect juce_core)?

Whatever, there seems to be something fishy with threads somewhere...

Any help would be appreciated! :)

Thanks! -Mathieu

The thread 0x5b4 has exited with code 0 (0x0).
Detected memory leaks!
Dumping objects ->
{202} normal block at 0x00F53EF8, 44 bytes long.
 Data: <                > 01 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00
Object dump complete.
The thread 0x15a4 has exited with code 0 (0x0).
The program '[0x308] JuceDemo.exe' has exited with code 0 (0x0).

 

 


#2

By the way, this is not a timing issue.

The same behavior happens with the following code:


#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>

std::atomic<bool> finished;
std::mutex mutex;
std::condition_variable conditionVariable;

void theThread()
{
    // wait one second
    std::unique_lock<std::mutex> lock(mutex);
    conditionVariable.wait_for(lock, std::chrono::seconds(1));

    finished = true;
}

int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
{
    std::thread * thread = new std::thread(theThread);

    while (finished.load() == false)
        std::this_thread::yield();

    thread->join();

    delete thread;

    return 0;
}


#3

The MS leak detector only runs because code in juce_core invokes it on shutdown. Not seeing the message when you don't use juce_core doesn't mean there isn't a leak, it just means its not being checked at all.

It's most likely just a win32 message left on the queue at exit, or a static variable somewhere that's not being deleted before the leak detector runs (which can happen before all other statics are destroyed).

(And come on, please.. even in test code there's no excuse to ever write 'delete', especially when you're explicitly using C++11 classes! Let's make this forum a place where we ALL try to set a good example to anyone reading it!)


#4

Ok ok, no delete! :)

Same problem here:

void theThread()
{
    // wait one second
    std::unique_lock<std::mutex> lock(mutex);
    conditionVariable.wait_for(lock, std::chrono::seconds(1));

    finished = true;
}

int __stdcall WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
{
    std::thread thread(theThread);

    while (finished.load() == false)
        std::this_thread::yield();

    thread.join();

    _CrtCheckMemory();

    return 0;
}

And I added a call to _CrtCheckMemory() to check for leaks.

There is something strange.

Log without linking juce_core.cpp
'JuceDemo.exe' (Win32): Loaded 'C:\Windows\SysWOW64\advapi32.dll'. Cannot find or open the PDB file.
The thread 0x12b4 has exited with code 0 (0x0).
The thread 0x1594 has exited with code 0 (0x0).
The program '[0x1138] JuceDemo.exe' has exited with code 0 (0x0).

vs

Log linking juce_core.cpp
'JuceDemo.exe' (Win32): Loaded 'C:\Windows\SysWOW64\msctf.dll'. Cannot find or open the PDB file.
The thread 0x4b4 has exited with code 0 (0x0).
Detected memory leaks!
Dumping objects ->
{204} normal block at 0x00BDAF00, 44 bytes long.
 Data: <                > 01 00 00 00 00 00 00 00 00 00 00 00 0A 00 00 00
Object dump complete.
The thread 0x119c has exited with code 0 (0x0).
The program '[0x64] JuceDemo.exe' has exited with code 0 (0x0).

#5

Yes. Like I said, it'll be a static object somewhere.

Obviously if you run the leak checker in your main function - i.e. before the program's static destructors have been called - then that's exactly what you'd expect to see.


#6

Adding a breakpoint in _nh_malloc_dbg_impl I found where the leak comes from:

int _Mtx_init(_Mtx_t *mtx, int type)
    {    /* initialize mutex */
    _Mtx_t mutex;
    *mtx = 0;

    if ((mutex = (mtx_t)calloc(1, sizeof (struct _Mtx_internal_imp_t))) == 0)


with stack

     JuceDemo.exe!calloc(unsigned int nNum, unsigned int nSize) Line 56    C++
     JuceDemo.exe!_Mtx_init(_Mtx_internal_imp_t * * mtx, int type) Line 24    C++
     JuceDemo.exe!init_at_thread_exit_mutex() Line 28    C
     JuceDemo.exe!_Call_once(char * cntrl, void (void) * func) Line 41    C
     JuceDemo.exe!_Cnd_do_broadcast_at_thread_exit() Line 107    C
     JuceDemo.exe!_Call_func(void * _Data) Line 70    C++
     JuceDemo.exe!_callthreadstartex() Line 354    C
     JuceDemo.exe!_threadstartex(void * ptd) Line 337    C

but I haven't found yet how this block gets freed when not linking with Juce. I'll keep investigating.

Another strange thing I found out is that the same code with Juce v3.1.1 generates a 72 byte leak, while with the current Juce v3.2.0 the leak size is 44 bytes...

 


#7

I tried to explain twice, did you not read my answers?? THIS IS NOT A REAL MEMORY LEAK!

Don't "keep investigating", it's a waste of your time! Go and get on with some real programming instead!


#8

No point commenting the remarks.

To remove the annoying memory leak log when using std::thread together with Juce, try adding the following line at the beginning of main:

    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);

The documentation states that using this flag performs automatic leak checking at program exit. In this case it also prevents the false leak detection.