Leaked objects when using Juce::Component in a Dynamic lib


#1

Hi Jules,

 

(All the demonstration codes below are trivial and straightforward. Dylib and GUI app projects created by Introjucer.)

I created a trivial Component subclass and build it as a .dylib on Mac. There are C style constructor and destructor helper functions. Then I load and use this Component class in a main desktop GUI app. It works correctly but several leaking assertion failures are met on every quit.

The header file:

class LibComponent : public Component

{

public:

    LibComponent();

    ~LibComponent();

    

    void paint (Graphics& g);

    void resized ();

};

 

extern "C" LibComponent *NewLibComponentHelper();

typedef LibComponent *LibComponent_Constructor_Helper();

 

extern "C" void DeleteLibComponentHelper(LibComponent*);

typedef void LibComponent_Destructor_Helper(LibComponent*);

 

The src file:

#include "LibComponent.h"

 

LibComponent::LibComponent()

{

    std::cout << "lib Component construct\n";

    setSize(30, 20);

}

 

LibComponent::~LibComponent()

{

    std::cout << "lib Component destructor\n";

    deleteAllChildren();

}

 

void LibComponent::paint(Graphics& g)

{

    std::cout << "lib Component paint\n";

    g.fillAll(Colours::aqua);

}

 

void LibComponent::resized()

{

    std::cout << "lib Component resized\n";

}

 

__attribute__((visibility("default")))

LibComponent* NewLibComponentHelper() {

    return new LibComponent();

}

 

__attribute__((visibility("default")))

void DeleteLibComponentHelper(LibComponent* libC) {

    if (libC) {

        delete libC;

        libC = NULL;

        std::cout << "libC nulled\n";

    }

}

 

The host app codes (main component):

//==============================================================================

MainContentComponent::MainContentComponent()

{

    libC = nullptr;

    bool isOpened = testLib.open("/Users/shaoduo/Desktop/TestASLibJuce/Builds/MacOSX/build/Debug/TestASLibJuce.dylib");

 

    if (!isOpened) {

        std::cout << "open lib failed\n";

    }

    LibComponent_Constructor_Helper *libCompConstructor = (LibComponent_Constructor_Helper*)testLib.getFunction("NewLibComponentHelper");

    if (!libCompConstructor) {

        std::cout << "open func constructor failed\n";

    }

    libCompDestructor = (LibComponent_Destructor_Helper*)testLib.getFunction("DeleteLibComponentHelper");

    if (!libCompDestructor) {

        std::cout << "open func destructor failed\n";

    }

    libC = libCompConstructor();

    if (libC) {

        addAndMakeVisible(libC);

    }

    

    setSize (500, 400);

}

 

MainContentComponent::~MainContentComponent()

{

    if (libC) {

        removeChildComponent(libC);

        libCompDestructor(libC);

    }

    

    libCompDestructor = NULL;

    testLib.close();

}

 

 

I think I followed the routine of using a dylib at run time. 

The codes runs correct and the component from the dylib can be correctly seen in the app.

But on quit, I got bunch of leaked object assertion

*** Leaked objects detected: 1 instance(s) of class DisplaySettingsChangeCallback

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class Desktop

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class ComponentAnimator

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class OwnedArray

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class MouseInputSource

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class MouseInputSourceInternal

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class OwnedArray

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 3 instance(s) of class AsyncUpdater

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

*** Leaked objects detected: 1 instance(s) of class MessageManager

JUCE Assertion failure in juce_LeakedObjectDetector.h:95

 

I currently have no idea how to find the cause down there. If I get rid of the dylib and compile the component subclass in the GUI app, there won't be any issue (of course...). But with a dylib, it gives leaking asserstion failures on quit. Any thoughts on this or how to debug this?

 

Thanks a lot.

 

 

 


#2

You're aware how dangerous it is to pass a C++ object out of a DLL and use it in another module, right?

If you do understand all the horribleness and are confident that know what you're doing, and if you really for some reason must use a DLL, then you can probably get things working just by calling shutdownJuce_GUI() before your DLL unloads. But unless you're a C++ ninja who really really needs to use a DLL in that way, then stick to static libs!