Request .NET 10 servicing backport of #129713 (Mono LLVM full-AOT: in-flight exception relocated by moving GC across resume unwind)
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Request
Please consider backporting dotnet/runtime#129713 ("[mono] Keep in-flight exception alive across LLVM resume unwind") to a .NET 10 servicing release. The fix is currently in `main` only (milestone 11.0-preview7), and I could not find an existing pull request targeting `release/10.0.x`.
### Why this matters on .NET 10
The bug produces an unrecoverable `SIGSEGV` / `EXC_BAD_ACCESS` in shipping iOS apps built with the default Release configuration for MAUI/iOS on .NET 10, where full AOT and LLVM are both enabled:
```xml
true
true
```
Debug builds are unaffected because they run under `--interpreter`, so the fault cannot be reproduced during development or on the simulator. It appears only in Release/AOT/LLVM builds — that is, in production and in store/TestFlight builds — which makes it expensive to diagnose and impossible to catch in a normal test loop.
The failure mode is not a corner case in our code. Any managed exception that unwinds through an LLVM-compiled `finally` and is then resumed for the catch search can hit it. In our app the trigger is ordinary `OperationCanceledException` propagation out of `BlockingCollection.GetConsumingEnumerable(CancellationToken)` on background consumer threads, which is a common .NET pattern. Because the in-flight exception is held as a raw pointer across the resume, a moving GC can relocate it and the resumed catch search then dereferences a stale pointer. The crash is therefore timing-dependent: it looks like a rare, unattributable native crash in the field rather than a reproducible defect.
### Observed impact
- Platform: iOS, arm64, Release + full AOT + LLVM.
- Crash signal: `SIGSEGV` / `EXC_BAD_ACCESS` at a small invalid address (e.g. `0xa40` — a field offset off a garbage `MonoImage` pointer).
- Representative symbolicated crashed-thread stack (runtime + BCL frames only; the app-level closure frame is not retained):
```text
pthread_mutex_lock
mono_os_mutex_lock
mono_image_lock
mono_image_alloc0
mono_class_setup_interfaces
ensure_inited_for_assignable_check
mono_class_is_assignable_from_general
mono_object_handle_isinst
mono_object_isinst_checked
mono_handle_exception_internal
mono_resume_unwind
mono_arm_resume_unwind
llvm_resume_unwind_trampoline
System.Collections.Concurrent.BlockingCollection`1.GetConsumingEnumerable+<>d__68.MoveNext
System.Threading.Tasks.Task.InnerInvoke
System.Threading.Tasks.Task.ExecuteEntryUnsafe
```
The second-pass catch search (`mono_object_isinst_checked`) walks a garbage `MonoClass` into lazy interface setup and faults taking the image lock — consistent frame-for-frame with the mechanism fixed in #129713. That the runtime enters `mono_class_setup_interfaces` at all for a long-initialized corlib exception type is itself evidence the exception pointer is stale.
- Reached production in release builds; the triggering exception path is a routine application lifecycle transition, so the exposure recurs for every affected user session rather than being a one-off. Aggregated crash reporting surfaces it as intermittent, unattributable native crashes spread across several signature groups.
### Build environment
- .NET SDK 10.0.302
- `ios` workload manifest 26.5.10301/10.0.100
- MAUI iOS app, Release configuration, `RunAOTCompilation=true`, `EnableLLVM=true`
### Related
- dotnet/runtime#129713 — the fix (merged to `main`, 11.0-preview7)
- dotnet/runtime#129508 — LLVM 23 FullAOT regression tracking
### Why a servicing backport rather than waiting
.NET 10 is the current LTS target for shipping MAUI/iOS apps; moving to a .NET 11 preview is not an option for store builds. Without the backport, the only mitigations available to app developers are (a) disabling LLVM in Release, which costs startup and steady-state performance, or (b) restructuring application code to avoid ever letting an exception unwind through an LLVM `finally` on a background thread — which is not generally achievable and, in our case, meant removing legitimate cancellation from a lifecycle path. Both are workarounds for a runtime defect with an already-reviewed and already-merged fix.
Happy to provide additional crash detail or to test a servicing build if that would help.
Contributor guide
Research direction
No source file or test is named. Start by reviewing dotnet/runtime#129713 and its compatibility with release/10.0.x, then check dotnet/runtime#129508 and the reported .NET 10 iOS arm64 Release full-AOT/LLVM configuration. Done means the servicing backport is prepared and validated, or its requirements and rejection are documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, ios
- Domain
- compilers, mobile-dev, release
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100