Closing the Plug-In makes the DAW crash


#1

Hey Community,

I do my independent coursework for my informatics studies programming an audio plugin. Everything works well except the fact that when I close the plug-in in any DAW the whole DAW shuts down immediately. I am pretty sure it has something to do with ether a Slider or a Label in the GUI. I already wrapped all the components in ScopedPointers. When closing my plugin I get the following error. I hope you guys can help me out. Regards, Thilo

juce::HeapBlock<juce::Slider::Listener*, false>::get() const + 12 (juce_HeapBlock.h:159)

juce::Array<juce::Slider::Listener*, juce::DummyCriticalSection, 0>::removeFirstMatchingValue(juce::Slider::Listener*) + 53 (juce_Array.h:918)

juce::ListenerList<juce::Slider::Listener, juce::Array<juce::Slider::Listener*, juce::DummyCriticalSection, 0> >::remove(juce::Slider::Listener*) + 104 (juce_ListenerList.h:97)

juce::Slider::removeListener(juce::Slider::Listener*) + 51 (juce_Slider.cpp:1384)

juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl::~Pimpl() + 80 (juce_AudioProcessorValueTreeState.cpp:437)

juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl::~Pimpl() + 21 (juce_AudioProcessorValueTreeState.cpp:439)

juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl::~Pimpl() + 25 (juce_AudioProcessorValueTreeState.cpp:436)

juce::ContainerDeletePolicy<juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl>::destroy(juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl*) + 63 (juce_ContainerDeletePolicy.h:53)

juce::ScopedPointer<juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl>::reset() + 31 (juce_ScopedPointer.h:159)

juce::ScopedPointer<juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl>::~ScopedPointer() + 21 (juce_ScopedPointer.h:94)

juce::ScopedPointer<juce::AudioProcessorValueTreeState::SliderAttachment::Pimpl>::~ScopedPointer() + 21 (juce_ScopedPointer.h:94)

juce::AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() + 44 (juce_AudioProcessorValueTreeState.cpp:474)

juce::AudioProcessorValueTreeState::SliderAttachment::~SliderAttachment() + 21 (juce_AudioProcessorValueTreeState.cpp:474)

juce::ContainerDeletePolicy<juce::AudioProcessorValueTreeState::SliderAttachment>::destroy(juce::AudioProcessorValueTreeState::SliderAttachment*) + 59 (juce_ContainerDeletePolicy.h:52)

juce::ScopedPointer<juce::AudioProcessorValueTreeState::SliderAttachment>::reset() + 31 (juce_ScopedPointer.h:159)

juce::ScopedPointer<juce::AudioProcessorValueTreeState::SliderAttachment>::~ScopedPointer() + 21 (juce_ScopedPointer.h:94)

juce::ScopedPointer<juce::AudioProcessorValueTreeState::SliderAttachment>::~ScopedPointer() + 21 (juce_ScopedPointer.h:94)

CompressorAudioProcessorEditor::~CompressorAudioProcessorEditor() + 301 (PluginEditor.cpp:52)

CompressorAudioProcessorEditor::~CompressorAudioProcessorEditor() + 21 (PluginEditor.cpp:52)

CompressorAudioProcessorEditor::~CompressorAudioProcessorEditor() + 25 (PluginEditor.cpp:51)

juce::Component::deleteAllChildren() + 108 (juce_Component.cpp:1520)

JuceAU::EditorCompHolder::~EditorCompHolder() + 39 (juce_AU_Wrapper.mm:1400)

JuceAU::EditorCompHolder::~EditorCompHolder() + 21 (juce_AU_Wrapper.mm:1402)

JuceAU::EditorCompHolder::~EditorCompHolder() + 25 (juce_AU_Wrapper.mm:1399)

juce::ContainerDeletePolicy<JuceAU::EditorCompHolder>::destroy(JuceAU::EditorCompHolder*) + 63 (juce_ContainerDeletePolicy.h:53)

juce::ScopedPointer<JuceAU::EditorCompHolder>::reset(JuceAU::EditorCompHolder*) + 64 (juce_ScopedPointer.h:171)

juce::ScopedPointer<JuceAU::EditorCompHolder>::operator=(JuceAU::EditorCompHolder*) + 47 (juce_ScopedPointer.h:125)

JuceAU::JuceUIViewClass::deleteEditor(objc_object*) + 259 (juce_AU_Wrapper.mm:1527)

JuceAU::JuceUIViewClass::shutdown(objc_object*) + 59

JuceAU::JuceUIViewClass::dealloc(objc_object*, objc_selector*) + 57 (juce_AU_Wrapper.mm:1545)

(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 817

_CFAutoreleasePoolPop + 22
-[NSAutoreleasePool release] + 144
0x100000000 + 8634532

Common pattern with Listeners
#2

You need to clear / null your slider attachment before your slider get destroyed.

@tpoole : this pops up the third time in a row, it used to work without crashing at some point. Could this be fixed by using a SafePointer in SliderAttachement et. al?


#3

I agree, that it seems a pitfall for new users, however a SafePointer comes with a performance penalty having to check for nullptr every time anything is done with it.

And TBH there is a warning about that in the docs, even with exclamation mark:

Make sure that your AudioProcessorValueTreeState and Slider aren’t deleted before this object!

You could making it an extra paragraph or setting in bold, but then there is really nothing to the rescue.


#4

If I may quote Mr. Donal Knuth himself: The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming. :wink:


#5

Yes, I have this quote on my answering machine, I don’t think it applies here.

Not checking every time if every possible precondition is met is not an optimisation.
The SliderAttachment is not intended to work without a Slider, but a new user is often not aware, that the order you define your members has actually a meaning. When will they learn, if not by these mistakes?

I was wondering if there could be an assert, but I didn’t have a good idea.

However, if the Slider could have a SliderAttachment as member that you can set, it would all sort itself, since it will be deleted with the slider automatically.
However that would mean a commitment to the AudioProcessorValueTreeState that I would love, but others might disagree…

In code that would be as simple as adding a
ScopedPointer<AudioProcessorValueTreeState> attachment and this method::

void Slider::attachToValueTreeState (AudioProcessorValueTreeState& state, const String& paramId)
{
    attachment = new AudioProcessorValueTreeState::SliderAttachment (state, paramId, *this);
}

#6

I assume you meant

ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> attachment; 

This would be a nice addition that shouldn’t break anything, should it?


#7

Right, thank you for the correction.
I also see it as harmless and very helpful, if you use the AudioProcessorValueTreeState.

It is up to the juce team… @t0m ( sorry to send so much stuff your way :wink: )


#8

The only problem could be that AudioProcessorValueTreeState::SliderAttachment and all AudioProcessorValueTreeState stuff in general is defined in the juce_audio_processors module while Slider is defined in juce_gui_basisc - so this addition would make juce_audio_processors a dependency for the module?


#9

Good point. TBH at the moment there are only a few modules truly optional, most of them pull such a long tail after them, that they can’t easily be avoided. We were talking about that in another thread a few weeks back.

I wonder if using #ifdef JUCE_AUDIO_PROCESSORS_H_INCLUDED would be considered an option (or naming it a bit more generic USING_JUCE_AUDIO_PROCESSORS…)


#10

or #if JUCE_MODULE_AVAILABLE_juce_audio_processors ?


#11

Rather than adding a SliderAttachment member to each Slider, why don’t you keep around this kind of struct for whenever you need such a coupling:

struct SliderWithAttachment
{
    ScopedPointer <Slider> slider;
    ScopedPointer <SliderAttachment> attachment;
};

This way, in your Editor you can simply add a member like:

SliderWithAttachment knob;

and voila, you have the knob.slider and the knob.attachment automatically deleted in the correct order, and also nicely bound together making the code more readable IMHO


#12

I like that approach thanks!