Search code examples
iosplcrashreporter

Can Core Foundation be used in PLCrashReporter signal callback?


I'm using PLCrashReporter in my iOS project and I'm curious, is it possible to use Core Foundation code in my custom crash callback. The thing, that handle my needs is CFPreferences.Here is part of code, that I create:

void LMCrashCallback(siginfo_t* info, ucontext_t* uap, void* context) {
  CFStringRef networkStatusOnCrash;
  networkStatusOnCrash = (CFStringRef)CFPreferencesCopyAppValue(networkStatusKey, kCFPreferencesCurrentApplication);
  CFStringRef additionalInfo = CFStringCreateWithFormat(
              NULL, NULL, CFSTR( "Additional Crash Properties:[Internet: %@]", networkStatusOnCrash);
  CFPreferencesSetAppValue(additionalInfoKey, additionalInfo,
                           kCFPreferencesCurrentApplication);
  CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
}

My target is to collect some system information, just in time when app crashed, e.g Internet connection type.

I know it is not good idea to create own crash callback due to async-safe functions, but this can help.

Also as other option: Is there a way to extend somehow PLCrashReportSystemInfo class?


Solution

  • This is very dangerous. In particular the call to CFStringCreateWithFormat allocates memory. Allocating memory in the middle of a crash handler can lead to battery-draining deadlock (yep; had that bug…) For example, if you were in the middle of free() (which is not an uncommon place to crash), you may already be holding a spinlock on the heap. When you call malloc to get some memory, you may spinlock the heap again and deadlock in a tight-loop. The heap needs to be locked so often and for such short periods of time that it doesn't use a blocking lock. It does the equivalent of while (locked) {}.

    You seem to just be reading a preference and copying it to another preference. There's no reason to do that inside a crash handler. Just check hasPendingCrashReport during startup (which I assume you're doing already), and read the key then. It's not clear what networkStatusKey is, but it should still be there when you start up again.

    If for any reason it's modified very early (before you call hasPendingCrashReport), you can grab it in main() before launching the app. Or you can grab it in a +load method, which is called even earlier.