Understanding Crash Reporter Extension lifecycle and debugging behavior

Hi! I have a few questions about the lifecycle and capabilities of the Crash Reporter Extension.

  1. Besides using the corpsePort to inspect the crashed process through Mach APIs, is it safe/supported/recommended for the extension to access files in a shared App Group container? Are there any caveats or exceptions we should be aware of, for example around memory-mapped files, file coordination, or filesystem access after the host app has crashed? Shall we use some particular APIs for this kind of shared resource or not?
  2. While debugging the extension, I noticed that when I trigger a crash in the app I am debugging, LLDB does not stop inside the extension (it also ends up stopping the debugging session). However, I can observe that the extension does run, because it writes data into a shared App Group directory related to the crash. Is this expected behavior? Is there a recommended way to debug the Crash Reporter Extension reliably (with lldb, or other way)?
  3. More generally, I would like to better understand the extension lifecycle:
    • When exactly does the extension start running?
    • How long can it live after the app crashes?
    • Is there a time limit for operating on the corpse process?
    • Is the extension subject to resource limits similar to other app extensions, such as memory, disk, CPU, watchdog, or jetsam constraints?
    • If the Crash Reporter Extension itself crashes, how can we detect that? Would those crashes appear in Xcode Organizer, or is there another recommended way to observe them?

Any clarification around the supported lifecycle, debugging model, and resource limits would be very useful.

Answered by DTS Engineer in 894264022
1- … is it safe/supported/recommended for the extension to access files in a shared App Group container?

I don’t see any fundamental problems with that but…

As with any shared files, you have to take steps to ensure consistency. Moreover, using a file lock isn’t a valid approach, because the main app might die while in the lock. Likewise for file coordination. You have to rely on atomic file system operations instead.

2- While debugging the extension …

I haven’t had a chance to play with this yet, but I suspect that this will act like any other appex, in that you have to tell Xcode to debug the appex, not the app. If you want to debug the appex and the app, you need to run both, and then you need to detach from the app after crashing because otherwise LLDB will swallow the crash (in the same way that LLDB-caught crashes don’t generate system crash reports).

If that doesn’t work, lemme know because there are always other options (-:

3- When exactly does the extension start running?

App extensions lifecycles are complicated, and they’re generally not considered API. That is, the system might launch the appex early, or keep it running after it completes, or whatever. Rather than worrying about the process itself, it’s best to focus on its invocation, which in this case means the system calling your processCrashReport(process:) method. Your extension process will be executed from the point where the system calls that routine to the point where that routine returns.

Except there’s a time limit, which I’ll come back to (-:

How long can it live after the app crashes?

That’s not considered part of the API.

Is there a time limit for operating on the corpse process?

Yes. I couldda sworn that was in the docs, but apparently not. Anyway, one of my colleagues discussed it on this thread.

Is the extension subject to resource limits … ?

Yes.

That’s not really a meaningful question because all third-party iOS code is subject to resource limits (-:

If the Crash Reporter Extension itself crashes, how can we detect that?

Your crash reporter extension can’t have its own crash reporter extension. Where would that end? (-:

If your crash reporter extension crashes, those crash reports will show up in the usual places. So, if your app is on the App Store they’ll show up in the Xcode organiser.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

1- … is it safe/supported/recommended for the extension to access files in a shared App Group container?

I don’t see any fundamental problems with that but…

As with any shared files, you have to take steps to ensure consistency. Moreover, using a file lock isn’t a valid approach, because the main app might die while in the lock. Likewise for file coordination. You have to rely on atomic file system operations instead.

2- While debugging the extension …

I haven’t had a chance to play with this yet, but I suspect that this will act like any other appex, in that you have to tell Xcode to debug the appex, not the app. If you want to debug the appex and the app, you need to run both, and then you need to detach from the app after crashing because otherwise LLDB will swallow the crash (in the same way that LLDB-caught crashes don’t generate system crash reports).

If that doesn’t work, lemme know because there are always other options (-:

3- When exactly does the extension start running?

App extensions lifecycles are complicated, and they’re generally not considered API. That is, the system might launch the appex early, or keep it running after it completes, or whatever. Rather than worrying about the process itself, it’s best to focus on its invocation, which in this case means the system calling your processCrashReport(process:) method. Your extension process will be executed from the point where the system calls that routine to the point where that routine returns.

Except there’s a time limit, which I’ll come back to (-:

How long can it live after the app crashes?

That’s not considered part of the API.

Is there a time limit for operating on the corpse process?

Yes. I couldda sworn that was in the docs, but apparently not. Anyway, one of my colleagues discussed it on this thread.

Is the extension subject to resource limits … ?

Yes.

That’s not really a meaningful question because all third-party iOS code is subject to resource limits (-:

If the Crash Reporter Extension itself crashes, how can we detect that?

Your crash reporter extension can’t have its own crash reporter extension. Where would that end? (-:

If your crash reporter extension crashes, those crash reports will show up in the usual places. So, if your app is on the App Store they’ll show up in the Xcode organiser.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for the answers!

I think the main point that is still unclear is debugging. What you mentioned is basically what I have been testing.

When I try to run the app extension with the debugger attached and select the owning app as the Host App, the debugger automatically detaches from the app extension when the app crashes.

The only way I was able to make it work was by selecting a different Host App, for example Safari or Photos, instead of the app that owns my Crash Reporter Extension. Even then, in around 90% of cases, after hitting the breakpoint, the debugging session stops a few seconds later.

So your questions prompted me to actually run some tests (-: I realise that you’re working on the Mac, but I’m not really set up to test that right now, so instead I tried this out on iOS.

I started by creating a new app project that I can crash at will:

  1. Using Xcode 27.0b1 running on macOS 26.5, I created a new app from the app template and named it “Test833154”.

  2. In the Signing & Capabilities editor, I selected my team and set the bundle ID to com.example.Test833154.

  3. I added a Crash button to the UI:

    Button("Crash") {
        let p = UnsafeMutablePointer<Int>(bitPattern: 0x100)!
        p.pointee += 1
    }
    
  4. I ran it on an iOS 27.0b1 device.

  5. In the app, I tapped the Crash button and the app crashed into the Xcode debugger. So far, so goodbad … good.


I then added a crash reporter extension to that:

  1. In Xcode I chose File > New > Target and chose the Crash Reporter Extension template and named it “QCrashEx”.

  2. When asked whether I want to activate the extension’s scheme, I clicked Don’t Activate.

  3. In the Signing & Capabilities editor, I checked that my team was selected, and that the bundle ID was com.example.Test833154.QCrashEx.

  4. I added a first light log point [1] to the extension:

    @main
    struct QCrashEx: CrashReporterExtension {
        // subsystem:com.example.Test833154.QCrashEx
        let log = Logger(subsystem: "com.example.Test833154.QCrashEx", category: "crash")
    
        func processCrashReport(process: CrashedProcess) {
            log.log("First light!")
        }
    }
    
  5. I made sure the app target was selected.

  6. And chose Product > Run.

  7. On my Mac, I ran the Console app and selected my iOS device on the left.

  8. I pasted subsystem:com.example.Test833154.qcrashex into the search field and started the log stream.

  9. In the app on the device, I tapped the Crash button. The app crashed into Xcode debugger.

  10. In Xcode, I chose Debug > Detach from Test833154.

  11. The app crashed, and I observed the first light log entry in Console. Nice.

    type: default
    time: 14:48:08.567466+0100
    process: QCrashEx
    subsystem: com.example.Test833154.QCrashEx
    category: crash
    message: First light!
    

Finally, I set up debugging for my extension:

  1. In Xcode, I select my crash reporter extension’s scheme.
  2. And set a breakpoint on the log(…) call in my crash reporter extension.
  3. I chose Debug > Attach to Process by PID or Name, entered “QCrashEx” into the PID or Process Name field, and clicked Attach.
  4. On the device, I launched my test app.
  5. And tapped the Crash button.
  6. The app crashes, my crash report extension started, Xcode attached to it, and then it stopped at the breakpoint.

Huzzah!

I don’t think there’s anything iOS specific here, so I think the equivalent process will also work on the Mac. Please try it out and let me know how you get along.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] I talk about this concept in Debugging a Network Extension Provider.

Understanding Crash Reporter Extension lifecycle and debugging behavior
 
 
Q