Help: Weird plugin crash when closing the DAW (Linux VST, Ardour)

when closing Ardour, sometimes my plugin crashes with a Segmentation fault. In my understanding, the backtrace of gdb seems to be rather unrelated to my code:

#0 0x00007f5b72912fa6 in juce::ContainerDeletePolicy<juce::ImagePixelData>::destroy(juce::ImagePixelData*) (object=0x7f5b1400c100) at …/…/…/…/modules/juce_core/memory/juce_ContainerDeletePolicy.h:52
#1 0x00007f5b7290c45a in juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::decIfNotNull(juce::ImagePixelData*) (o=0x7f5b1400c100) at …/…/…/…/modules/juce_core/memory/juce_ReferenceCountedObject.h:372
#2 0x00007f5b72901f77 in juce::ReferenceCountedObjectPtr<juce::ImagePixelData>::~ReferenceCountedObjectPtr() (this=0x7f5b14053ea0, __in_chrg=) at …/…/…/…/modules/juce_core/memory/juce_ReferenceCountedObject.h:333
#3 0x00007f5b72889daa in juce::Image::~Image() (this=Python Exception <class ‘RecursionError’> maximum recursion depth exceeded while getting the str of an object:
0x7f5b14053ea0, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/images/juce_Image.cpp:261
#4 0x00007f5b728f4dea in juce::ImageCache::Pimpl::Item::~Item() (this=Python Exception <class ‘RecursionError’> maximum recursion depth exceeded while getting the str of an object:
0x7f5b14053ea0, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/images/juce_ImageCache.cpp:100
#5 0x00007f5b7290d2de in juce::Array<juce::ImageCache::Pimpl::Item, juce::DummyCriticalSection, 0>::deleteAllElements() (this=0x7f5b1400b138) at …/…/…/…/modules/juce_core/containers/juce_Array.h:1268
#6 0x00007f5b72902f64 in juce::Array<juce::ImageCache::Pimpl::Item, juce::DummyCriticalSection, 0>::~Array() (this=0x7f5b1400b138, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_core/containers/juce_Array.h:147
#7 0x00007f5b728f4c05 in juce::ImageCache::Pimpl::~Pimpl() (this=0x7f5b1400b110, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/images/juce_ImageCache.cpp:34
#8 0x00007f5b728f4c46 in juce::ImageCache::Pimpl::~Pimpl() (this=0x7f5b1400b110, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/images/juce_ImageCache.cpp:34
#9 0x00007f5b7286017f in juce::DeletedAtShutdown::deleteAll() () at …/…/…/…/modules/juce_events/messages/juce_DeletedAtShutdown.cpp:78
#10 0x00007f5b72861362 in juce::shutdownJuce_GUI() () at …/…/…/…/modules/juce_events/messages/juce_MessageManager.cpp:442
#11 0x00007f5b7272d060 in JuceVSTWrapper::~JuceVSTWrapper() (this=0x563b66a05d80, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:350
#12 0x00007f5b7272d1b0 in JuceVSTWrapper::~JuceVSTWrapper() (this=0x563b66a05d80, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:357
#13 0x00007f5b7272f528 in JuceVSTWrapper::dispatcherCB(VstEffectInterface*, int, int, long long, void*, float) (vstInterface=0x563b66a05de8, opCode=0x1, index=0x0, value=0x0, ptr=0x0, opt=0) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:1165
#14 0x00007f5ba09b8ef1 in vstfx_close(_VSTState*) () at /usr/lib/ardour5/libardour.so.3

This crash is somewhat random and hard to reproduce reliably, but it tends to happen more often (or only) when more instances of the plugin are loaded and the plugin GUI has once been opened in the session.
I couldn’t reproduce this behaviour with another DAW both on Linux and Windows yet.

I’m kind of lost here, but I guess maximum recursion depth exceeded while getting the str of an object' of ~Image() might give a hint on this issue. The plugin uses two background images for the GUI (using the Projucer only, no manual code by me), and without those images, the crash doesn’t occur so far (but another weird one does).

Does anyone have any idea about this or a hint where to look?

I’d say you are creating an ImageCache on the heap (new ImageCache)?

ImageCache is supposed to be used as singleton, and all images you access with static methods.

If you have a container owning the ImageCache, it will destroy all the cached contents. But since the ImageCache itself is a singleton, that is destroyed on shutdown. So things are destroyed twice leading to the errors you are seeing…

Also something to note: don’t use Image*, always use it on the stack. The ImageData is shared anyway, so there is no need to put an Image into a ScopedPointer or OwnedArray…

But could be something else…

This actually looks like it’s the ImageCache singleton being automatically deleted when the last plugin instance closes. Why that’d crash is a bit of a mystery, unless perhaps you’ve managed to corrupt the memory of the image object that it’s trying to delete there?

Thanks a lot for your answers. But I have to admit that I just partly understand what you are saying, since this is somewhat beyond my knowledge.

There’s no new ImageCache in my code, at least not in the code I have under control (PluginEditor.*). All of the image-related code is generated by the Projucer, probably the right way. But thanks for explaining that background, I’m happy to learn such things :slight_smile: .

No idea how I could have done this, or how I might find out… As I said, I barely handle the images by hand.

Anyways, if I remove the images completely, I (very rarely) get another crash when closing the DAW. This time it’s not related to ~Image(), but to ~Font():

#0 0x00007f9e3ca7c261 in juce::ContainerDeletePolicy<juce::Font::SharedFontInternal>::destroy(juce::Font::SharedFontInternal*) (object=0x7f9e3002fc30) at …/…/…/…/modules/juce_core/memory/juce_ContainerDeletePolicy.h:52
#1 0x00007f9e3ca7c261 in juce::ReferenceCountedObjectPtr<juce::Font::SharedFontInternal>::decIfNotNull(juce::Font::SharedFontInternal*) (o=0x7f9e3002fc30) at …/…/…/…/modules/juce_core/memory/juce_ReferenceCountedObject.h:372
#2 0x00007f9e3ca7c261 in juce::ReferenceCountedObjectPtr<juce::Font::SharedFontInternal>::~ReferenceCountedObjectPtr() (this=<optimized out>, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_core/memory/juce_ReferenceCountedObject.h:333
#3 0x00007f9e3ca7c261 in juce::Font::~Font() (this=<optimized out>, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/fonts/juce_Font.cpp:293
#4 0x00007f9e3caa39c2 in juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>::~CachedGlyphEdgeTable() (this=0x7f9e44029f20, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:279
#5 0x00007f9e3caa39c2 in juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>::~CachedGlyphEdgeTable() (this=0x7f9e44029f20, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:279
#6 0x00007f9e3ca9e768 in juce::ContainerDeletePolicy<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState> >::destroy(juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>*) (object=0x7f9e44029f20) at …/…/…/…/modules/juce_core/memory/juce_ContainerDeletePolicy.h:52
#7 0x00007f9e3ca9e768 in juce::ReferenceCountedArray<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::DummyCriticalSection>::releaseObject(juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>*) (o=0x7f9e44029f20) at …/…/…/…/modules/juce_core/containers/juce_ReferenceCountedArray.h:907
#8 0x00007f9e3ca9e768 in juce::ReferenceCountedArray<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::DummyCriticalSection>::releaseAllObjects() (this=0x7f9e44046db8) at …/…/…/…/modules/juce_core/containers/juce_ReferenceCountedArray.h:899
#9 0x00007f9e3ca9e768 in juce::ReferenceCountedArray<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::DummyCriticalSection>::~ReferenceCountedArray() (this=0x7f9e44046db8, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_core/containers/juce_ReferenceCountedArray.h:133
#10 0x00007f9e3ca9e768 in juce::RenderingHelpers::GlyphCache<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::RenderingHelpers::SoftwareRendererSavedState>::~GlyphCache() (this=0x7f9e44046db0, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:154
#11 0x00007f9e3ca9e768 in juce::RenderingHelpers::GlyphCache<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::RenderingHelpers::SoftwareRendererSavedState>::~GlyphCache() (this=0x7f9e44046db0, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:154
#12 0x00007f9e3ca30dfa in juce::DeletedAtShutdown::deleteAll() () at …/…/…/…/modules/juce_events/messages/juce_DeletedAtShutdown.cpp:78
#13 0x00007f9e3ca30e7f in juce::shutdownJuce_GUI() () at …/…/…/…/modules/juce_events/messages/juce_MessageManager.cpp:442
#14 0x00007f9e3c955d43 in JuceVSTWrapper::~JuceVSTWrapper() (this=0x55be8ae5eff0, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:350
#15 0x00007f9e3c9563b5 in JuceVSTWrapper::~JuceVSTWrapper() (this=0x55be8ae5eff0, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:357
#16 0x00007f9e3c9564b3 in JuceVSTWrapper::dispatcherCB(VstEffectInterface*, int, int, long long, void*, float) (vstInterface=<optimized out>, opCode=<optimized out>, index=0x0, value=0x0, ptr=0x0, opt=0) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:1165
#17 0x00007f9e94c57ef1 in vstfx_close(_VSTState*) () at /usr/lib/ardour5/libardour.so.3

I’m not touching anything related to fonts in my code, besides having some strings shown in the GUI as usual.

So maybe I’m really doing something wrong and these crashes are just the symptom of this. But if so, I have no idea how to handle this or where to look…

Can you reproduce this with the demo plug-in from the examples directory (using the tip of the latest develop branch)?

Much to my surprise, I could make the demo plug-in crash:

ardour-5.12.0[899]: segfault at 7f3843fa7600 ip 00007f38798589d9 sp 00007ffd99769ec0 error 4 in JuceDemoPlugin.so[7f3879107000+dfc000]

#0 0x00007f38798589d9 in juce::ContainerDeletePolicy<juce::Font::SharedFontInternal>::destroy(juce::Font::SharedFontInternal*) (object=0x7f387404e500) at …/…/…/…/modules/juce_core/memory/juce_ContainerDeletePolicy.h:52
#1 0x00007f38798529a1 in juce::ReferenceCountedObjectPtr<juce::Font::SharedFontInternal>::decIfNotNull(juce::Font::SharedFontInternal*) (o=0x7f387404e500) at …/…/…/…/modules/juce_core/memory/juce_ReferenceCountedObject.h:372
#2 0x00007f3879849603 in juce::ReferenceCountedObjectPtr<juce::Font::SharedFontInternal>::~ReferenceCountedObjectPtr() (this=0x7f3864024c20, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_core/memory/juce_ReferenceCountedObject.h:333
#3 0x00007f3879829f3c in juce::Font::~Font() (this=0x7f3864024c20, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/fonts/juce_Font.cpp:293
#4 0x00007f387985a7cc in juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>::~CachedGlyphEdgeTable() (this=0x7f3864024c10, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:279
#5 0x00007f387985a7f4 in juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>::~CachedGlyphEdgeTable() (this=0x7f3864024c10, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:279
#6 0x00007f387985a84f in juce::ContainerDeletePolicy<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState> >::destroy(juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>*) (object=0x7f3864024c10) at …/…/…/…/modules/juce_core/memory/juce_ContainerDeletePolicy.h:52
#7 0x00007f387985a2ad in juce::ReferenceCountedArray<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::DummyCriticalSection>::releaseObject(juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>*) (o=0x7f3864024c10) at …/…/…/…/modules/juce_core/containers/juce_ReferenceCountedArray.h:907
#8 0x00007f3879854afc in juce::ReferenceCountedArray<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::DummyCriticalSection>::releaseAllObjects() (this=0x7f386403e318) at …/…/…/…/modules/juce_core/containers/juce_ReferenceCountedArray.h:899
#9 0x00007f38798549ba in juce::ReferenceCountedArray<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::DummyCriticalSection>::~ReferenceCountedArray() (this=0x7f386403e318, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_core/containers/juce_ReferenceCountedArray.h:133
#10 0x00007f387985f16a in juce::RenderingHelpers::GlyphCache<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::RenderingHelpers::SoftwareRendererSavedState>::~GlyphCache() (this=0x7f386403e310, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:154
#11 0x00007f387985f192 in juce::RenderingHelpers::GlyphCache<juce::RenderingHelpers::CachedGlyphEdgeTable<juce::RenderingHelpers::SoftwareRendererSavedState>, juce::RenderingHelpers::SoftwareRendererSavedState>::~GlyphCache() (this=0x7f386403e310, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_graphics/native/juce_RenderingHelpers.h:154
#12 0x00007f38797a47e8 in juce::DeletedAtShutdown::deleteAll() () at …/…/…/…/modules/juce_events/messages/juce_DeletedAtShutdown.cpp:78
#13 0x00007f38797a59ca in juce::shutdownJuce_GUI() () at …/…/…/…/modules/juce_events/messages/juce_MessageManager.cpp:442
#14 0x00007f3879671d10 in JuceVSTWrapper::~JuceVSTWrapper() (this=0x56203ee4fe60, __in_chrg=) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:350
#15 0x00007f3879671e60 in JuceVSTWrapper::~JuceVSTWrapper() (this=0x56203ee4fe60, __in_chrg=<optimized out>) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:357
#16 0x00007f38796741f0 in JuceVSTWrapper::dispatcherCB(VstEffectInterface*, int, int, long long, void*, float) (vstInterface=0x56203ee4fec8, opCode=0x1, index=0x0, value=0x0, ptr=0x0, opt=0) at …/…/…/…/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:1165
#17 0x00007f38d3f2fef1 in vstfx_close(_VSTState*) () at /usr/lib/ardour5/libardour.so.3

In this Ardour session, I loaded several instances of the demo plug-in as well as instances of my problematic plug-in. So far, I could only make this happen once, and I could not make it crash without my plug-in loaded. Could there be some kind of interaction? The demo plug-in I used was from yesterday’s develop brach. I’ll keep testing this with the very latest develop branch (couldn’t make that one crash until now), but this behaviour is pretty rare and so it takes much time…

All right, I could reproduce the crash of the demo plug-in a few more times, but only when my faulty plug-in is also loaded in the same session. So my plug-in seems to be the cause for these crashes.
I’d be glad about some input on how I could handle this now, since I’ve totally run out of ideas.

If you can get your hands on a macOS system, the Adress sanitiser in Xcode is the perfect tool for finding memory corruptions like this (there’s valgrind on Linux, but I don’t find it as effective as Xcode’s solution).

You’re probably writing / deallocating illegally because of some out of bounds thingie and it won’t complain until you deallocate the memory again in the destructor of your plugin.

As I said before, I believe, you are freeing memory, that is managed somewhere else.

  • One thing to look for, do a search over all your code, do you call delete anywhere?
    If so, it is time to remove that in change for RAII structures.

  • Make sure, ownership is clear, double check that only one place is responsible for deletion.

  • Don’t delete by hand, and always when you create something, put it in a managed ponter, like ReferenceCountedPtr, ScopedPointer, OwnedArray, or if you prefer STL use std::unique_ptr.

  • Another geniuos thing: uninitialised raw pointer and calling delete to clean up…

  • Look, if you are creating objects on the heap, that don’t belong there, like Image, MemoryBlock, Font etc… (see this thread: Loading ZipFile via a MemoryBlock)

  • Whenever you take the address of a member, consider this a bad design and try to find a better solution, since you contradict the natural lifetime of the member - especially if you return that address outside of that function

Good luck!

@chrisboy2000 and @daniel, thank you very much for your answers!

Sadly, a MacOS system is not available for me. I’ve spent some time with valgrind, but so far I couldn’t really get much more information out of it compared to gdb, besides
Invalid read of size 8 and Address 0x385e32a0 is not stack'd, malloc'd or (recently) free'd.

I really appreciate your explanations! I’m trying to get into those concepts and I definitively have to adapt some code. Seems to be very important in modern C++ :slight_smile: . Thanks again!

So, in order to get along with this issue, I reduced my plugin to the minimum. Basically, it now contains close to no handwritten code. There’s no signal processing, no effect parameters, no fiddling around with arrays / pointers and definitively no delete or free. The PluginProcessor.* only consists of some overriding methods which only do the bare necessities. The PluginEditor.* pretty much only contains code generated by the Projucer, holding some background images, buttons, sliders and labels without any kind of handling the user interaction. I’ll be damned if there is a mistake in this code! But it still crashes… :cold_sweat: .

Can you share the code of your plugin? It is hard to come up with theories in the blue…
It’s just guessing around, and there are a lot of mistakes, that would create that output…

Yes, of course I can share the code. I just didn’t dare to ask for someone to actually look at my code.
So here’s the PluginEditor.cpp, PluginEditor.h, PluginProcessor.cpp and PluginProcessor.h.
The PluginEditor.cpp is quite big, since it also contains the images. Sorry for that.