Our customers repeatedly report a crash in Logic Pro at the end of an offline bounce. Unfortunately, we were not able to reproduce the issue. However, we received a crash report (EXC_BAD_ACCESS), as shown in the snippet below.
Thread 0:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x19fe70998 __bsdthread_create + 8
1 libsystem_pthread.dylib 0x19feb0348 _pthread_create + 1008
2 myPlugin 0x40dc9af70 juce::Thread::createNativeThread(juce::Thread::Priority) (in myPlugin) (juce_Threads_mac.mm:143) + 4173680
3 myPlugin 0x40dc9b1ac juce::Thread::startThread(juce::Thread::Priority) (in myPlugin) (juce_Thread.cpp:169) + 4174252
4 myPlugin 0x40dd5718c AnalyzerProcessor::prepareToPlay(double, int) (in myPlugin) (AnalyzerProcessor.h:49) + 4944268
5 myPlugin 0x40d8e6c1c juce::NodeStates::applySettings(juce::Nodes const&) (in myPlugin) (juce_AudioProcessorGraph.cpp:469) + 289820
6 myPlugin 0x40d8e6598 juce::AudioProcessorGraph::Pimpl::handleAsyncUpdate() (in myPlugin) (juce_AudioProcessorGraph.cpp:1929) + 288152
7 myPlugin 0x40dc4460c juce::LockingAsyncUpdater::Impl::messageCallback() (in myPlugin) (juce_LockingAsyncUpdater.cpp:84) + 3819020
8 myPlugin 0x40dc4a1e0 juce::MessageQueue::runLoopCallback() (in myPlugin) (juce_MessageQueue_mac.h:104) + 3842528
9 CoreFoundation 0x19ff99cd4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
10 CoreFoundation 0x19ff99c68 __CFRunLoopDoSource0 + 172
11 CoreFoundation 0x19ff99a38 __CFRunLoopDoSources0 + 332
12 CoreFoundation 0x19ff98628 __CFRunLoopRun + 840
13 CoreFoundation 0x19ff97c58 CFRunLoopRunSpecific + 572
14 HIToolbox 0x1aba2c27c RunCurrentEventLoopInMode + 324
15 HIToolbox 0x1aba2f4e8 ReceiveNextEventCommon + 676
16 HIToolbox 0x1abbba484 _BlockUntilNextEventMatchingListInModeWithFilter + 76
17 AppKit 0x1a3ebfab4 _DPSNextEvent + 684
18 AppKit 0x1a485e5b0 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688
19 ViewBridge 0x1a95870a4 __77-[NSViewServiceApplication vbNextEventMatchingMask:untilDate:inMode:dequeue:]_block_invoke + 148
20 ViewBridge 0x1a9586e18 -[NSViewServiceApplication _withToxicEventMonitorPerform:] + 152
21 ViewBridge 0x1a9586ff8 -[NSViewServiceApplication vbNextEventMatchingMask:untilDate:inMode:dequeue:] + 168
22 ViewBridge 0x1a9574b34 -[NSViewServiceApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 100
23 AppKit 0x1a3eb2c64 -[NSApplication run] + 480
24 AppKit 0x1a3e8935c NSApplicationMain + 880
25 libxpc.dylib 0x19fbc0a3c _xpc_objc_main + 816
26 libxpc.dylib 0x19fbd0fc8 _xpc_main + 40
27 libxpc.dylib 0x19fbc0568 xpc_main + 64
28 ViewBridge 0x1a9570408 -[NSXPCSharedListener resume] + 32
29 ViewBridge 0x1a958925c NSViewServiceMain + 360
30 AUHostingServiceXPC_arrow 0x1004096ac 0x100400000 + 38572
31 dyld 0x19fb0eb98 start + 6076
Thread 50 Crashed:: AUOOPRenderingServer-280009362
0 libsystem_platform.dylib 0x19fee82f8 _platform_memmove + 168
1 myPlugin 0x40dd5722c AnalyzerProcessor::processBlock(juce::AudioBuffer<float>&, juce::MidiBuffer&) (in myPlugin) (AnalyzerProcessor.h:61) + 4944428
2 myPlugin 0x40d8ee3c4 juce::GraphRenderSequence<float>::NodeOp::process(juce::GraphRenderSequence<float>::Context const&) (in myPlugin) (juce_AudioProcessorGraph.cpp:886) + 320452
3 myPlugin 0x40d8f9de0 juce::GraphRenderSequence<float>::perform(juce::AudioBuffer<float>&, juce::MidiBuffer&, juce::AudioPlayHead*) (in myPlugin) (juce_AudioProcessorGraph.cpp:566) + 368096
4 myPlugin 0x40d8b53f4 JuceAU::processBlock(juce::AudioBuffer<float>&, juce::MidiBuffer&) (in myPlugin) (juce_audio_plugin_client_AU_1.mm:2143) + 87028
5 myPlugin 0x40d8ac9a8 JuceAU::Render(unsigned int&, AudioTimeStamp const&, unsigned int) (in myPlugin) (juce_audio_plugin_client_AU_1.mm:1532) + 51624
6 myPlugin 0x40d8bc6d4 ausdk::AUBase::DoRenderBus(unsigned int&, AudioTimeStamp const&, unsigned int, ausdk::AUOutputElement&, unsigned int, AudioBufferList&) (in myPlugin) (AUBase.h:548) + 116436
7 myPlugin 0x40d8bc2c0 ausdk::AUBase::DoRender(unsigned int&, AudioTimeStamp const&, unsigned int, unsigned int, AudioBufferList&) (in myPlugin) (AUBase.cpp:0) + 115392
8 myPlugin 0x40d8c2a68 ausdk::AUMethodRender(void*, unsigned int*, AudioTimeStamp const*, unsigned int, unsigned int, AudioBufferList*) (in myPlugin) (AUPlugInDispatch.cpp:334) + 141928
9 AudioToolboxCore 0x1a28b0bd4 AudioUnitRender + 432
10 AudioToolboxCore 0x1a27f16e0 invocation function for block in AUAudioUnitV2Bridge_Renderer::renderBlock() + 608
11 AudioToolboxCore 0x1a280d924 void* caulk::thread_proxy<std::__1::tuple<caulk::thread::attributes, AUOOPRenderingServer::AUOOPRenderingServer(int, int, int, std::__1::vector<AudioStreamBasicDescription, std::__1::allocator<AudioStreamBasicDescription>> const&, unsigned int, unsigned int, applesauce::xpc::dict const&, std::__1::shared_ptr<auoop::WorkgroupMirror>)::$_0, std::__1::tuple<>>>(void*) + 1712
12 libsystem_pthread.dylib 0x19feaec0c _pthread_start + 136
13 libsystem_pthread.dylib 0x19fea9b80 thread_start + 8
My first suspicion was that AnalyzerProcessor::processBlock gets called before AnalyzerProcessor::prepareToPlay, leading to access of uninitialized buffers in processBlock. So I started the Logic Pro in the debugger, set a breakpoint in AnalyzerProcessor::prepareToPlay and started a bounce.
I found out that prepareToPlay is called once at the end of the bounce, as shown in the stack trace below.
com.apple-main-thread:
AnalyzerProcessor::prepareToPlay(double, int) AnalyzerProcessor.h:41
juce::NodeStates::applySettings(const juce::Nodes &) juce_AudioProcessorGraph.cpp:479
juce::AudioProcessorGraph::Pimpl::handleAsyncUpdate() juce_AudioProcessorGraph.cpp:1929
juce::AudioProcessorGraph::Pimpl::rebuild(juce::AudioProcessorGraph::UpdateKind) juce_AudioProcessorGraph.cpp:1863
juce::AudioProcessorGraph::Pimpl::topologyChanged(juce::AudioProcessorGraph::UpdateKind) juce_AudioProcessorGraph.cpp:1924
juce::AudioProcessorGraph::Pimpl::addNode(std::unique_ptr<…>, std::optional<…>, juce::AudioProcessorGraph::UpdateKind) juce_AudioProcessorGraph.cpp:1753
juce::AudioProcessorGraph::addNode(std::unique_ptr<…>, std::optional<…>, juce::AudioProcessorGraph::UpdateKind) juce_AudioProcessorGraph.cpp:1997
PluginProcessor::prepareToPlay(double, int) PluginProcessor.cpp:147
JuceAU::SetProperty(unsigned int, unsigned int, unsigned int, const void *, unsigned int) juce_audio_plugin_client_AU_1.mm:800
ausdk::AUBase::DispatchSetProperty(unsigned int, unsigned int, unsigned int, const void *, unsigned int) AUBase.cpp:846
ausdk::AUMethodSetProperty(void *, unsigned int, unsigned int, unsigned int, const void *, unsigned int) AUPlugInDispatch.cpp:182
What’s interesting, though, is that on my machine, AnalyzerProcessor::prepareToPlay is called synchronously from the message thread while in the crash report it seems to be async.
Could that cause processBlock to be called before prepareToPlay?
And why is there an async call to AnalyzerProcessor::prepareToPlay in the crash report? Could it be that juce::AudioProcessorGraph::Pimpl::rebuild is called from a different thread than the message thread on the remote machine?
Any thoughts?
