Crash on exit where MIDI data was processed while DeviceManager was destroyed


#1

Hi,

just had a strange crash on exit and can’t figure out why it happened . It may be a bug in JUCE.

On shutdown - the AudioDeviceManager is being destroyed. Before destruction all audio and MIDI callbacks attached to it were removed. You can see the destruction being called on the main thread here

Thread 0:: Juce Message Thread  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	0x00007fff8a16e4de mach_msg_trap + 10
1   libsystem_kernel.dylib        	0x00007fff8a16d64f mach_msg + 55
2   com.apple.audio.midi.CoreMIDI 	0x00000001043bd07b MIDIClient_PortDisconnectSource + 116
3    com.myself.testapp         	0x00000001012cd766 juce::CoreMidiHelpers::MidiPortAndCallback::~MidiPortAndCallback() + 182
4    com.myself.testapp         	0x00000001012bcc45 juce::CoreMidiHelpers::MidiPortAndCallback::~MidiPortAndCallback() + 21
5    com.myself.testapp         	0x00000001012b9ff1 juce::MidiInput::~MidiInput() + 49
6    com.myself.testapp         	0x00000001012ba035 juce::MidiInput::~MidiInput() + 21
7    com.myself.testapp         	0x00000001012cf45d juce::ContainerDeletePolicy<juce::MidiInput>::destroy(juce::MidiInput*) + 61
8    com.myself.testapp         	0x00000001012cf3c7 juce::OwnedArray<juce::MidiInput, juce::DummyCriticalSection>::deleteAllObjects() + 71
9    com.myself.testapp         	0x00000001012cf328 juce::OwnedArray<juce::MidiInput, juce::DummyCriticalSection>::~OwnedArray() + 24
10   com.myself.testapp         	0x00000001012ba825 juce::OwnedArray<juce::MidiInput, juce::DummyCriticalSection>::~OwnedArray() + 21
11   com.myself.testapp         	0x00000001012afca0 juce::AudioDeviceManager::~AudioDeviceManager() + 848
12   com.myself.testapp         	0x00000001012afdb5 juce::AudioDeviceManager::~AudioDeviceManager() + 21

The application crashed in a different thread (looks like a MIDI thread) which tried to push midi data to obviously removed objects. Here is a stack trace of that

Thread 2 Crashed:
0    com.myself.testapp         	0x00000001012ccfb7 void juce::MidiDataConcatenator::pushMidiData<juce::MidiInput, juce::MidiInputCallback>(void const*, int, double, juce::MidiInput*, juce::MidiInputCallback&) + 279
1    com.myself.testapp         	0x00000001012ccd86 juce::CoreMidiHelpers::MidiPortAndCallback::handlePackets(MIDIPacketList const*) + 214
2    com.myself.testapp         	0x00000001012b9c44 juce::CoreMidiHelpers::midiInputProc(MIDIPacketList const*, void*, void*) + 36
3   com.apple.audio.midi.CoreMIDI 	0x00000001043e7208 LocalMIDIReceiverList::HandleMIDIIn(unsigned int, unsigned int, void*, MIDIPacketList const*) + 120
4   com.apple.audio.midi.CoreMIDI 	0x00000001043e47fa MIDIProcess::RunMIDIInThread() + 252
5   com.apple.audio.midi.CoreMIDI 	0x00000001043c9e5a XThread::RunHelper(void*) + 10
6   com.apple.audio.midi.CoreMIDI 	0x00000001043c9a8b CAPThread::Entry(CAPThread*) + 109
7   libsystem_pthread.dylib       	0x00007fff85b0805a _pthread_body + 131
8   libsystem_pthread.dylib       	0x00007fff85b07fd7 _pthread_start + 176
9   libsystem_pthread.dylib       	0x00007fff85b053ed thread_start + 13

Does anyone have any ideas how could this happen?

Thanks.


#2

Well it seems as if haven’t removed all listeners yet as its being called. Also it’s really hard for us to debug without some source code. Can you post some minimal code which reproduces the problem?


#3

This has happened only once and so far - cannot be reproduced easily. Actually was not reproduced again at all.

The code is really not important since all that is being done is destroying the AudioDeviceManager as you can see in the first stack trace (bottom) and then it crashed. In any case - her is what’s happening in the destructor on application exit

deviceManager.removeChangeListener(this);
deviceManager.removeMidiInputCallback(midiListener);

Then the deviceManager gets destroyed when its container class gets destroyed.

Looks like a race condition in JUCE code. The environment where this happened had a MIDI clock sending messages continuously. Could it be that the “MidiPortAndCallback” destructor which was called from “MidiInput” destructor happened before the receiver tried to push the messages out.


#4

I think we would have seen this before. We have a few locks to avoid this type of race condition. I’m afraid without more code, it’s hard for us to find the issue.