0

I have a Xamarin.iOS application in production that uses a lot of MIDI with soundfonts. I'm using appcenter.ms to capture crashes and log events. One crash keeps happening sporadically (and pretty rarely) to my users that I'm not able to recreate and troubleshoot. According to the crash reports it is happening across many different devices and iOS versions. It seems random. I'm also using Sentry.io with breadcrumbs but nothing ever gets logged there with the same date/time stamp that I can match up with this crash. The garbage collector seems to be involved and it also seems to be related to loading soundfonts (i.e. GlobalState::LoadInstrumentFromDLSCollection from the stack trace).

Does anyone have any suggestions on what might cause this or how to track it down? Is there some adverse interaction occurring between the garbage collector and the underlying low level c++ operation? Is there a way to ensure the garbage collector doesn't try to run in the middle of loading a soundfont?

Here's my code for loading soundfonts followed by the complete stack trace from appcenter (by the way, the try/catch doesn't actually catch any exceptions when this happens but I'm including it anyway). Of course I could be wrong about this code being the culprit but that's the only that loads soundfonts.

I've googled each of the iOS related c++ calls (e.g. SampleManager::InsertSample(unsigned long, Sample*)) but can't find anyone else reporting similar issues.

public bool LoadInstrument(string soundFontPath)
        {
           
            if (_currentInstrumentPath != soundFontPath)
                _currentInstrumentPath = soundFontPath;
            try
            {
                var soundFontUrl = CFUrl.FromFile(soundFontPath);
                if (_samplerUnit == null)
                    return false;
                if (!_samplerUnit.IsPlaying)
                    _samplerUnit.LoadInstrument(new SamplerInstrumentData(soundFontUrl, InstrumentType.SF2Preset)
                    {
                        BankLSB = SamplerInstrumentData.DefaultBankLSB,
                        BankMSB = SamplerInstrumentData.DefaultMelodicBankMSB,
                        PresetID = (byte)0
                    });
            }
            catch (Exception ex)
            {
                App.DiagnosticsLogger.WriteLog(ex);
                _eventAggregator.PublishOnUIThreadAsync(new TUE.Messages.ExceptionThrownMessage
                {
                    SourceClass = "MidiSequencePlayer",
                    Exception = ex,
                    DisplayMessage = "Failed to load the soundfont, Path: " + soundFontPath
                });
                var fileName = System.IO.Path.GetFileName(soundFontPath);
                var properties = new Dictionary<string, string>();
                properties.Add("ExceptionMessage", ex.Message);
                properties.Add("MethodName", "LoadInstrument");
                properties.Add("FileName", fileName);
                properties.Add("Path", soundFontPath);
                App.AnalyticsLogger.LogEvent("MSQ.LoadInstrument", "MIDI", properties, Sentry.Protocol.BreadcrumbLevel.Error);
                return false;
            }
            return true;
        }

StackTrace:

libEmbeddedSystemAUs.dylib
    SampleManager::InsertSample(unsigned long, Sample*)
    libEmbeddedSystemAUs.dylib
    InstrumentManager::AddSample(DlsWave*, __CFURL const*, bool, unsigned int)
    
libEmbeddedSystemAUs.dylib
    GlobalState::LoadInstrumentFromDLSCollection(InstrumentState*, __CFURL const*, unsigned int, unsigned int, bool)
    
libEmbeddedSystemAUs.dylib
    Sampler::SetProperty(unsigned int, unsigned int, unsigned int, void const*, unsigned int)
libEmbeddedSystemAUs.dylib
    AUBase::DispatchSetProperty(unsigned int, unsigned int, unsigned int, void const*, unsigned int)

libEmbeddedSystemAUs.dylib
    AUMethodSetProperty(void*, unsigned int, unsigned int, unsigned int, void const*, unsigned int)
gc.safepoint_poll
     
gc.safepoint_poll
    
gc.safepoint_poll
    
gc.safepoint_poll
    
gc.safepoint_poll
gc.safepoint_poll
     
gc.safepoint_poll
    
gc.safepoint_poll
    
gc.safepoint_poll
    
gc.safepoint_poll
    
gc.safepoint_poll
    
gc.safepoint_poll
gc.safepoint_poll
     
gc.safepoint_poll
gc.safepoint_poll
     gc.safepoint_poll
plcrash::MS::async::dwarf_cfa_state_iterator<unsigned long long, long long>::next(unsigned int*,
plcrash::MS::async::plcrash_dwarf_cfa_reg_rule_t*, unsigned long long*)
TUE.iOS plcrash::MS::async::dwarf_cfa_state_iterator<unsigned long long, long long>::next(unsigned int*,
plcrash::MS::async::plcrash_dwarf_cfa_reg_rule_t*, unsigned long long*)
Foundation
    __NSThreadPerformPerform
C
CoreFoundation
    __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
CoreFoundation
    __CFRunLoopDoSource0
CoreFoundation
    __CFRunLoopDoSources0
 
CoreFoundation
    __CFRunLoopRun
 
CoreFoundation

CFRunLoopRunSpecific

GraphicsServices
    GSEventRunModal
 
UIKitCore
    -[UIApplication _run]
 
UIKitCore
    UIApplicationMain

TUE.iOS
    gc.safepoint_poll
 
TUE.iOS
    gc.safepoint_poll
 
TUE.iOS
    gc.safepoint_poll
 
TUE.iOS
    gc.safepoint_poll
 
TUE.iOS
    gc.safepoint_poll
 
TUE.iOS
    gc.safepoint_poll
 
TUE.iOS
    gc.safepoint_poll
 
TUE.iOS

xamarin_release_block_on_main_thread

TUE.iOS

plcrash::MS::async::dwarf_cfa_state_iterator<unsigned long long, long long>::next(unsigned int*,
plcrash::MS::async::plcrash_dwarf_cfa_reg_rule_t*, unsigned long long*)
libdyld.dylib

start
Sean
  • 868
  • 9
  • 22
  • Did you symbolicate the iOS crash report as mentioned [here](https://learn.microsoft.com/en-us/appcenter/diagnostics/ios-symbolication#bitcode)? The stacktrace you shared does not help much. – nevermore Dec 07 '20 at 06:09
  • Yes, I uploaded the dSYM file when this version first went live. In fact, I do have some other crashes for this version and I'm seeing function names and class names (although not line numbers) in the stack traces for those crashes (same version/build as this crash). Is there anything else besides uploading my dSYM file? Your link mentions bitcode: my app isn't compiled for bitcode that I know of...(not sure where to enable/disable that in Mac VS) – Sean Dec 07 '20 at 15:49
  • Bitcode is currently always disabled by default through [this thread](https://github.com/MicrosoftDocs/appcenter-docs/issues/471). Can't get more information from the stacktrace. – nevermore Dec 08 '20 at 09:55
  • Thanks..I'll reach out to appcenter.. maybe someone can explain why I'm not getting a symbolicated crash there. – Sean Dec 08 '20 at 15:10
  • Yes, you can share the solution here if you find:). – nevermore Dec 09 '20 at 02:03
  • Jack, will do! The appcenter got back with me, asked for screenshots of my stack trace, are looking into things... – Sean Dec 10 '20 at 20:16
  • OK, good luck!! – nevermore Dec 11 '20 at 01:26
  • nevermore: I have posted the solution below. I resolved this over a year ago and I've never gotten this error report again. I guess you have to do this on the main thread. – Sean Jan 25 '22 at 16:29

1 Answers1

0

I wrapped my call to LoadInstrument inside of MainThread.BeginInvokeOnMainThread. This seems to have completely resolved the issue as I've never gotten another report on this again:

MainThread.BeginInvokeOnMainThread(() =>
                        _samplerUnit.LoadInstrument(new SamplerInstrumentData(soundFontUrl, InstrumentType.SF2Preset)
                        {
                            BankLSB = SamplerInstrumentData.DefaultBankLSB,
                            BankMSB = SamplerInstrumentData.DefaultMelodicBankMSB,
                            PresetID = (byte)0
                        }));
Sean
  • 868
  • 9
  • 22