JUCE AudioPluginHost crash with Slate Digital and Youlean plug-ins

Hi,

I am developing a JUCE host on Mac which is based on AudioPluginHost example.
I have noticed that it crashes when trying to scan some Slate Digital plug-in in VST3 and crash when trying to use them in Audio Units.
These crashes reproduce in the host example.
Another plug-in that crashes is Youlean loudness meter.
These plug-ins don’t crash in other DAWs such as Logic, Cubase etc.

Youlean appears to crash because Juce host creates it with a default of 10 channels and does not adjust it to the possible 2 channels.

Slate’s crash is different and still unclear:
Here is a partial list of the plugins that crash: Virtual Tape Machines, VBC Rack, VerbSuite classics and more
Slate Digital crash log
Thread 0 Crashed:: JUCE Message Thread Dispatch queue: com.apple.main-thread
0 com.eiosis.aireq51 0x0000000111d45799 ACFShutdown + 3686201
1 com.eiosis.aireq51 0x0000000111d45918 ACFShutdown + 3686584
2 com.eiosis.aireq51 0x0000000111e4b4f4 ACFShutdown + 4758676
3 com.eiosis.aireq51 0x0000000111f16b93 ACFShutdown + 5591859
4 com.juce.pluginhost 0x0000000100b98e26 juce::AudioUnitPluginInstance::refreshParameterList() + 3270
5 com.juce.pluginhost 0x0000000100b95cc6 juce::AudioUnitPluginFormat::createPluginInstance(juce::PluginDescription const&, double, int, std::__1::function<void (std::__1::unique_ptr<juce::AudioPluginInstance, std::__1::default_deletejuce::AudioPluginInstance >, juce::String const&)>)::AUAsyncInitializationCallback::completion(ComponentInstanceRecord*, int) + 1398
6 com.juce.pluginhost 0x0000000100b945c5 juce::AudioUnitPluginFormat::createPluginInstance(juce::PluginDescription const&, double, int, std::__1::function<void (std::__1::unique_ptr<juce::AudioPluginInstance, std::__1::default_deletejuce::AudioPluginInstance >, juce::String const&)>) + 1133
7 com.juce.pluginhost 0x0000000100b7113d juce::AudioPluginFormat::handleMessage(juce::Message const&) + 175
8 com.juce.pluginhost 0x0000000100bf7660 juce::MessageQueue::runLoopSourceCallback(void*) + 200
9 com.apple.CoreFoundation 0x00007fff36407832 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
10 com.apple.CoreFoundation 0x00007fff364077d1 __CFRunLoopDoSource0 + 103
11 com.apple.CoreFoundation 0x00007fff364075eb __CFRunLoopDoSources0 + 209
12 com.apple.CoreFoundation 0x00007fff3640631a __CFRunLoopRun + 927
13 com.apple.CoreFoundation 0x00007fff3640591e CFRunLoopRunSpecific + 462
14 com.apple.HIToolbox 0x00007fff35031abd RunCurrentEventLoopInMode + 292
15 com.apple.HIToolbox 0x00007fff350317d5 ReceiveNextEventCommon + 584
16 com.apple.HIToolbox 0x00007fff35031579 _BlockUntilNextEventMatchingListInModeWithFilter + 64
17 com.apple.AppKit 0x00007fff33678039 _DPSNextEvent + 883
18 com.apple.AppKit 0x00007fff33676880 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
19 com.apple.AppKit 0x00007fff3366858e -[NSApplication run] + 658
20 com.juce.pluginhost 0x0000000100b29fa2 main + 191
21 libdyld.dylib 0x00007fff704eecc9 start + 1

Youlean crash log:
Thread 2 Crashed:: com.apple.audio.IOThread.client
0 com.Youlean.audiounit.Youlean-Loudness-Meter-2 0x0000000118bfcdd4 IPlugBase::SetOutputChannelConnections(int, int, bool) + 104
1 com.Youlean.audiounit.Youlean-Loudness-Meter-2 0x0000000118c67cfc IPlugAU::RenderProc(void*, unsigned int*, AudioTimeStamp const*, unsigned int, unsigned int, AudioBufferList*) + 1228
2 com.Youlean.audiounit.Youlean-Loudness-Meter-2 0x0000000118c69ad4 IPlugAU::AUMethodRender(void*, unsigned int*, AudioTimeStamp const*, unsigned int, unsigned int, AudioBufferList*) + 76
3 com.juce.pluginhost 0x0000000102f13c3c juce::AudioUnitPluginInstance::processAudio(juce::AudioBuffer&, juce::MidiBuffer&, bool) + 760 (juce_AudioUnitPluginFormat.mm:1094)
4 com.juce.pluginhost 0x0000000102e8e4fc juce::AudioUnitPluginInstance::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 48 (juce_AudioUnitPluginFormat.mm:1116)
5 com.juce.pluginhost 0x0000000102f3bca0 void juce::AudioProcessorGraph::Node::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 84 (juce_AudioProcessorGraph.h:162)
6 com.juce.pluginhost 0x0000000102f3bbbc juce::GraphRenderSequence::ProcessOp::callProcess(juce::AudioBuffer&, juce::MidiBuffer&) + 260 (juce_AudioProcessorGraph.cpp:297)
7 com.juce.pluginhost 0x0000000102f3b9ac juce::GraphRenderSequence::ProcessOp::perform(juce::GraphRenderSequence::Context const&) + 312 (juce_AudioProcessorGraph.cpp:276)
8 com.juce.pluginhost 0x0000000102f43750 juce::GraphRenderSequence::perform(juce::AudioBuffer&, juce::MidiBuffer&, juce::AudioPlayHead*) + 628 (juce_AudioProcessorGraph.cpp:85)
9 com.juce.pluginhost 0x0000000102e46264 void juce::processBlockForBuffer<float, juce::AudioProcessorGraph::RenderSequenceFloat>(juce::AudioBuffer&, juce::MidiBuffer&, juce::AudioProcessorGraph&, std::__1::unique_ptr<juce::AudioProcessorGraph::RenderSequenceFloat, std::__1::default_deletejuce::AudioProcessorGraph::RenderSequenceFloat >&, std::__1::atomic&) + 384 (juce_AudioProcessorGraph.cpp:1405)
10 com.juce.pluginhost 0x0000000102e460d8 juce::AudioProcessorGraph::processBlock(juce::AudioBuffer&, juce::MidiBuffer&) + 108 (juce_AudioProcessorGraph.cpp:1420)
11 com.juce.pluginhost 0x0000000102fc4d04 juce::AudioProcessorPlayer::audioDeviceIOCallback(float const**, int, float**, int, int) + 784 (juce_AudioProcessorPlayer.cpp:279)
12 com.juce.pluginhost 0x0000000102d87e70 juce::AudioDeviceManager::audioDeviceIOCallbackInt(float const**, int, float**, int, int) + 340 (juce_AudioDeviceManager.cpp:829)
13 com.juce.pluginhost 0x0000000102d92920 juce::AudioDeviceManager::CallbackHandler::audioDeviceIOCallback(float const**, int, float**, int, int) + 68 (juce_AudioDeviceManager.cpp:54)
14 com.juce.pluginhost 0x0000000102d9d664 juce::CoreAudioClasses::CoreAudioInternal::audioCallback(AudioBufferList const*, AudioBufferList*) + 496 (juce_mac_CoreAudio.cpp:767)
15 com.juce.pluginhost 0x0000000102d9d460 juce::CoreAudioClasses::CoreAudioInternal::audioIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*) + 56 (juce_mac_CoreAudio.cpp:856)
16 com.apple.audio.CoreAudio 0x000000018452b138 invocation function for block in HALC_ProxyIOContext::HALC_ProxyIOContext(unsigned int, unsigned int) + 5484
17 com.apple.audio.CoreAudio 0x00000001846a4388 HALB_IOThread::Entry(void*) + 88
18 libsystem_pthread.dylib 0x0000000182b9f878 _pthread_start + 320
19 libsystem_pthread.dylib 0x0000000182b9a5e0 thread_start + 8

I’ll be happy to get some directions how to solve it and also help JUCE example (which is amazing) get more stable.

Regards,
William

Just to check: are you running in debug or release mode? Many plugins crash on purpose in debug builds.

Thanks dimbouce, both modes crash release and debug

I debugged the Youlean plugin, and it’s not obvious to me that the issue is in JUCE. Immediately after creating the AudioUnit, JUCE queries it for its bus layout and sets the bus layout of the AudioProcessor accordingly. The AudioUnit reports that it wants a default of 10 channels, so this is how JUCE sets up the AudioProcessor. Later, in prepareToPlay, JUCE checks again whether the plugin is still happy to play with 10 channels, and the plugin reports that it is.

To me, it looks like the plugin is buggy. I think it works in other hosts because those hosts are explicitly setting a channel layout after instantiating the plugin. If I adjust the AudioPluginHost to explicitly set a stereo layout on the plugin after creating the plugin instance, then it works without issues:

void PluginGraph::addPluginCallback (std::unique_ptr<AudioPluginInstance> instance,
                                     const String& error, Point<double> pos)
    if (instance == nullptr)
    {
        ...
    }
    else
    {
        // In production, you'd want to check whether this layout is actually supported by the plugin!
        instance->setBusesLayout ({ { juce::AudioChannelSet::stereo() },
                                    { juce::AudioChannelSet::stereo() } });

So, the problem seems to be that the plugin isn’t prepared with the channel count that it reports. I think that this issue should be resolved in the plugin. I’d recommend filing a bug report (feel free to point them our way in case they believe the issue really is in JUCE!).


For the AirEQ AU, I think this also looks like a bug in the plugin. Running in the AudioPluginHost built with Address Sanitizer, we see this output when loading the plugin. It’s crashing when calling AudioUnitGetProperty with the kAudioUnitProperty_BypassEffect key. I’m reasonably sure we can expect this call to succeed at this point. Again, I’d recommend contacting the developers of this plugin to see whether they agree that the bug is on their side.

==52367==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x00011653cf19 bp 0x7ffeef48bd50 sp 0x7ffeef48bd50 T0)
==52367==The signal is caused by a READ memory access.
==52367==Hint: address points to the zero page.
    #0 0x11653cf19 in ACFShutdown+0x2b6ec9 (Eiosis AirEQ:x86_64+0x834f19)
    #1 0x11653d097 in ACFShutdown+0x2b7047 (Eiosis AirEQ:x86_64+0x835097)
    #2 0x116642c73 in ACFShutdown+0x3bcc23 (Eiosis AirEQ:x86_64+0x93ac73)
    #3 0x11670e312 in ACFShutdown+0x4882c2 (Eiosis AirEQ:x86_64+0xa06312)
    #4 0x100e362a8 in juce::AudioUnitPluginInstance::AUBypassParameter::getCurrentHostValue() juce_AudioUnitPluginFormat.mm:1666
    #5 0x100e358a5 in juce::AudioUnitPluginInstance::AUBypassParameter::AUBypassParameter(juce::AudioUnitPluginInstance&) juce_AudioUnitPluginFormat.mm:1656
    #6 0x100e2ab2c in juce::AudioUnitPluginInstance::AUBypassParameter::AUBypassParameter(juce::AudioUnitPluginInstance&) juce_AudioUnitPluginFormat.mm:1657
    #7 0x100cf2823 in juce::AudioUnitPluginInstance::refreshParameterList() juce_AudioUnitPluginFormat.mm:1595
    #8 0x100da1030 in juce::AudioUnitPluginInstance::initialise(double, int) juce_AudioUnitPluginFormat.mm:704
    #9 0x100cb674c in juce::AudioUnitPluginFormat::createPluginInstance(juce::PluginDescription const&, double, int, std::__1::function<void (std::__1::unique_ptr<juce::AudioPluginInstance, std::__1::default_delete<juce::AudioPluginInstance> >, juce::String const&)>)::AUAsyncInitializationCallback::completion(ComponentInstanceRecord*, int) juce_AudioUnitPluginFormat.mm:2784
    #10 0x100cb3922 in juce::AudioUnitPluginFormat::createPluginInstance(juce::PluginDescription const&, double, int, std::__1::function<void (std::__1::unique_ptr<juce::AudioPluginInstance, std::__1::default_delete<juce::AudioPluginInstance> >, juce::String const&)>) juce_AudioUnitPluginFormat.mm:2816