iOS: app killed with 0xdead10cc — StackTraceSymbols holds a shared flock on the PDB inside the app bundle
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Description
On iOS, a .NET app running on CoreCLR is terminated by the OS a few seconds after it is
backgrounded, with `EXC_CRASH (SIGKILL)`, `RUNNINGBOARD`, code `0xdead10cc`. RunningBoard names
the offending file: the app's own **PDB, inside the app bundle**.
```
RunningBoard terminated [app:1710] because it was suspended
while holding a shared file lock:
/var/containers/Bundle/Application//MyApp.app/MyApp.pdb
File locks MUST be held in one of the following directories:
/var/mobile/Containers/Data/Application/
/var/mobile/Containers/Data/Application//tmp
```
Debug builds only — a Release build ships no PDB and is unaffected. This is a regression from the
switch to CoreCLR as the iOS runtime in .NET 11 (Mono read symbols through a different path).
### Analysis
1. `StackTraceSymbols.TryOpenFile` opens the PDB on the first stack trace that needs line numbers:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/StackTraceSymbols.cs#L233
```csharp
// Open the file with read and delete FileShare flags. This matches what dll loading does
return new FileStream(path!, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
```
2. On Unix, any `FileShare` other than `None` maps to `flock(LOCK_SH)`
(`SafeFileHandle.Unix.cs`, `CanLockTheFile` / `LockOperations.LOCK_SH`).
3. The resulting `MetadataReaderProvider` is cached in a
`ConditionalWeakTable`. The key is the assembly, which lives
for the whole process, so **the lock is never released**.
4. At suspension, RunningBoard sees a file lock outside the app's data container and kills the app.
Setting `System.IO.DisableFileLocking=true` makes the termination disappear (verified on device,
iPad A16 / iOS 26.6.2), which confirms the chain — but it is a process-wide switch and disables
`FileShare` semantics everywhere, so it is not an acceptable general answer.
The comment's rationale does not hold on Unix: `dlopen` takes no advisory lock, so the shared
`flock` is not "what dll loading does" there.
### Proposed fix
Open the PDB with `FileShare.ReadWrite | FileShare.Delete`, which takes no advisory lock on Unix.
Nothing is lost: the file is opened read-only for symbol reading, and `FileShare.Delete` already
allows it to be removed underneath the reader.
### Repro
.NET 11 RC1 MAUI app, `net11.0-ios`, Debug, on a device (not the simulator — it is not suspended
the same way). Launch from the home screen, background it for 40 s (the kill happens at
suspension, not on entering the background), return. The app has been killed and cold-starts.
Objective check: sample the process id throughout, or read the RunningBoard log from a
sysdiagnose. Note that the crash report is not reliable as a signal — iOS throttles writing them
when the same app dies repeatedly.
I am happy to send the one-line PR if you would like it.
Contributor guide
Research direction
Start in src/libraries/System.Diagnostics.StackTrace/src/System/Diagnostics/StackTraceSymbols.cs at TryOpenFile, then inspect SafeFileHandle.Unix.cs for the FileShare-to-flock behavior. Reproduce on a Debug net11.0-ios device by backgrounding the app and verify that symbol reading still works without the app being terminated for holding a bundle-file lock.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, ios
- Domain
- mobile-dev, operating-systems
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100