Description
Summary
On iOS devices (heavily concentrated on iOS 26.x), a minority but non-trivial share of cold launches crash inside FirebaseApp.CreateAndTrack with EXC_BAD_ACCESS (SIGBUS) / KERN_PROTECTION_FAILURE. The crash site is il2cpp::vm::ClassMatches + 12 at Image.cpp:326, reached via il2cpp::vm::Image::FromTypeNameParseInfo + 304 at Image.cpp:377. The crash persists even when the community-recommended mitigations (frame-defer + ContinueWithOnMainThread) are in place — the main thread crashes while honoring those guards.
Environment
| Component |
Version |
| Firebase Unity SDK |
13.3.0 |
| Firebase iOS (Cocoapods, bundled) |
12.4.0 |
| Unity |
2022.3 LTS (IL2CPP scripting backend, iOS target) |
| DI container |
Zenject (Firebase init wrapped in a custom IInitializable) |
| UniTask |
Cysharp.Threading.Tasks (latest stable at the time of release) |
| Xcode build toolchain |
Xcode 16.x |
Device distribution of affected crashes (14-day window, production):
- iPhone ~98%, iPad ~2%
- iOS 26.x ~70% (iOS 26.3 dominant, iOS 26.4 secondary)
- iOS 18.x ~25%
- Remainder on iOS 16/17
Impact and frequency
- ~611 unique device events over 14 days on a single recent app version (not a cumulative figure across versions).
- Rate is a minority of the install base (~single-digit %), not 100% reproducible — strongly indicative of a race condition rather than deterministic stripping or a missing symbol.
- Non-zero presence on iOS 18.x confirms the issue is not purely an iOS 26 beta artifact; iOS 26 appears to amplify an underlying race.
Exception
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Subtype: KERN_PROTECTION_FAILURE
Termination Reason: SIGNAL 10 Bus error
Triggered Thread: 0 (main thread)
Important: KERN_PROTECTION_FAILURE indicates the faulting address resolves to a valid mapped page but the CPU's memory-protection bits rejected the access. This is the classic signature of a torn or stale pointer being dereferenced, not a null pointer returned from a stripped-type lookup.
Crash stack (symbolicated, main-thread-init build)
User-code frames are redacted; Firebase / Unity / IL2CPP symbols preserved verbatim:
Thread 0 Crashed:
0 UnityFramework il2cpp::vm::ClassMatches(___Il2CppMetadataTypeHandle const*, char const*, bool, char const*) + 12 (Image.cpp:326)
1 UnityFramework il2cpp::vm::Image::FromTypeNameParseInfo(Il2CppImage const*, ...) + 304 (Image.cpp:377)
2 UnityFramework FirebaseApp_CreateAndTrack_* + 1016 (Firebase.App.cpp:10051)
3 UnityFramework [REDACTED user_init_controller]_<StartFirebaseApp>b__3_0 (user controller)
4 UnityFramework Action_1_Invoke_ClosedInstInvoker
5 UnityFramework U3CU3Ec__DisplayClass4_1_1_<ContinueWithOnMainThread>b__1 + 44 (Generics.cpp:23712)
6 UnityFramework RuntimeInvoker_TrueByte
7 UnityFramework Func_1_Invoke_ClosedInstInvoker (Generics__6.cpp:30923)
8 UnityFramework U3CU3Ec__DisplayClass5_0_1_<RunAsync>b__0 + 112 (Generics.cpp:24825)
9 UnityFramework ExceptionAggregator_Wrap + 36 (Firebase.Platform.cpp:1907)
10 UnityFramework Dispatcher_PollJobs + 108 (Firebase.Platform.cpp:2082)
11 UnityFramework FirebaseHandler_Update + 232 (Firebase.Platform.cpp:3640)
12 UnityFramework il2cpp::vm::Runtime::InvokeWithThrow + 100 (Runtime.cpp:608)
13 UnityFramework il2cpp::vm::Runtime::Invoke + 80 (Runtime.cpp:594)
14 UnityFramework ScriptingInvocation::Invoke + 120 (ScriptingInvocation.cpp:298)
15 UnityFramework MonoBehaviour::CallUpdateMethod + 276 (MonoBehaviour.cpp:593)
16 UnityFramework void BaseBehaviourManager::CommonUpdate<BehaviourManager>() + 100 (Behaviour.cpp:158)
17 UnityFramework ExecutePlayerLoop(NativePlayerLoopSystem*) + 140 (PlayerLoop.cpp:406)
...
Note frames 9–11: the continuation is reached via Firebase.Platform.Dispatcher.PollJobs from FirebaseHandler.Update on the Unity main thread — confirming ContinueWithOnMainThread is being honored. The crash fires anyway.
Historical context — Xcode bucket migration
Before the main-thread-init refactor, the identical crash (same top 3 frames, same exception type) was occurring on a background threadpool thread:
Triggered Thread: N (background worker)
0 UnityFramework il2cpp::vm::ClassMatches + 12 (Image.cpp:326)
1 UnityFramework il2cpp::vm::Image::FromTypeNameParseInfo (Image.cpp:377)
2 UnityFramework FirebaseApp_CreateAndTrack + 1016 (Firebase.App.cpp:10051)
3 UnityFramework [REDACTED user_init_controller]_<StartFirebaseApp>b__2_0
4 UnityFramework Action_1_Invoke_ClosedInstInvoker
5 UnityFramework Task_Execute (mscorlib)
...
9 UnityFramework ThreadPoolWorkQueue_Dispatch
12 UnityFramework worker_thread (ThreadPoolWorkerThread.cpp:250)
13 UnityFramework il2cpp::vm::ThreadStart (Thread.cpp:801)
14 UnityFramework il2cpp::os::ThreadImpl::ThreadStartWrapper (ThreadImpl.cpp:123)
15 libsystem_pthread.dylib _pthread_start
Because the Xcode crash grouping is primarily keyed off the main thread's state when the process dies, those older reports were bucketed under a generic "no useful main-thread stack" signature. Moving Firebase init to the main thread did not eliminate the race; it only changed how Xcode groups the resulting crashes (the crash now has a rich main-thread stack and a distinct signature).
Mitigations already in place (ineffective)
The following are both present in the currently shipping build where the 611-event crash count was collected. Neither eliminates the crash:
1. Frame-defer guard — defer Firebase init by one Update tick so IL2CPP's generic-metadata finalization on cold launch has time to settle before any Firebase reflection path runs:
public void Initialize()
{
_initTask = new TaskCompletionSource<bool>();
InitSdk().Forget();
}
private async UniTask InitSdk()
{
await UniTask.Yield(PlayerLoopTiming.Update);
StartFirebaseApp();
}
2. Main-thread continuation — marshal the CheckAndFixDependenciesAsync() continuation back to the Unity main thread before accessing FirebaseApp.DefaultInstance:
private void StartFirebaseApp()
{
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
{
if (task.Result == DependencyStatus.Available)
{
_ = FirebaseApp.DefaultInstance; // triggers CreateAndTrack → FromTypeNameParseInfo
_initTask.TrySetResult(true);
}
else
{
_initTask.TrySetResult(false);
}
});
}
The crash stack explicitly contains <ContinueWithOnMainThread>b__1 (frame 5) → Dispatcher_PollJobs (frame 10) → FirebaseHandler_Update (frame 11) → MonoBehaviour::CallUpdateMethod (frame 15) — proving the main-thread marshal is being honored. Thread 0 still crashes.
Hypotheses
-
Cold-launch IL2CPP metadata race persists on main thread. The UniTask.Yield guard defers init by exactly one Update tick. If CheckAndFixDependenciesAsync() completes near-synchronously (warm cache), the continuation fires almost immediately, and FirebaseApp.DefaultInstance can touch IL2CPP type metadata while other main-thread work (generic method table construction, static cctors on the first access of certain UnityEngine.* types) is still mutating the metadata image. FromTypeNameParseInfo then reads a torn Il2CppMetadataTypeHandle — matching the KERN_PROTECTION_FAILURE signal type (not a null return, which would be the stripping signature).
-
iOS 26 W^X/PAC enforcement amplifies a pre-existing race. The crash is elevated on iOS 26.x (~70% of events). iOS 26's stricter page-protection enforcement may be surfacing races that prior iOS versions silently tolerated — in particular if any Firebase init path (or class realization triggered by it) touches pages mid-remap.
-
Stripping / link.xml are not the cause. The Firebase Unity SDK's bundled link.xml at Assets/Firebase/FirebaseApp/Internal/link.xml already preserves the types that FirebaseInterops.cs resolves by name (Firebase.Auth.FirebaseAuth, Firebase.AppCheck.FirebaseAppCheck). KERN_PROTECTION_FAILURE is inconsistent with stripping (which returns null, giving KERN_INVALID_ADDRESS), and a stripping root cause would crash every user on affected binary builds — not a single-digit percent.
What we have not yet tried
- Upgrade to Firebase Unity SDK 13.10.0 (iOS Cocoapods 12.12.0). The CHANGELOG entries between 12.4.0 and 12.12.0 do not appear to document a fix for this specific stack; 12.12.0 additionally requires Xcode 26.2 + Swift 6.2.3, which is a non-trivial build-system change for teams still on Xcode 16.
- Add
FirebaseAppDelegateClassName to Info.plist. We left this out because the crash stack is at the IL2CPP metadata layer (ClassMatches / FromTypeNameParseInfo), not obviously on the AppDelegate swizzle path. If the Firebase team believes it would alter the relevant code path, we are happy to test it.
Questions for the Firebase team
- Is there a known IL2CPP metadata race inside
FirebaseApp.CreateAndTrack (the Firebase.App.cpp:10051 call site) that can still fire even with ContinueWithOnMainThread applied?
- Does the call at
Firebase.App.cpp:10051 perform a Type.GetType(string) / Assembly.GetType(string) lookup, and if so, which type is being resolved? If it is a Firebase-internal type already covered by the SDK's link.xml, what else could produce a KERN_PROTECTION_FAILURE at that offset?
- Any iOS 26 compatibility work planned for the Core / App init path that is not yet reflected in CHANGELOG entries between 12.4.0 and 12.12.0?
- What additional diagnostic breadcrumbs or environment probes would help characterize this race from a live Crashlytics report?
Related issues
Reproduction difficulty
We do not yet have a minimal Unity project that reliably reproduces this crash. The issue only manifests on a small fraction of user devices during cold launch, strongly suggesting timing/race sensitivity. We are happy to provide additional symbolicated .crash files or to test diagnostic builds if the team can suggest instrumentation.
Reproducing the issue
No response
Firebase Unity SDK Version
13.30
Unity editor version
2022.3..69
Installation Method
.unitypackage
Problematic Firebase Component(s)
No response
Other Firebase Component(s) in use
No response
Additional SDKs you are using
No response
Targeted Platform(s)
Apple Platforms
Unity editor platform
Mac
Scripting Runtime
IL2CPP
Release Distribution Type
Pre-built SDK from https://firebase.google.com/download/unity
Relevant Log Output
If using CocoaPods for Apple platforms, the project's Podfile.lock
Expand Podfile.lock snippet
👀 Replace this line with the contents of your Podfile.lock!
Description
Summary
On iOS devices (heavily concentrated on iOS 26.x), a minority but non-trivial share of cold launches crash inside
FirebaseApp.CreateAndTrackwithEXC_BAD_ACCESS (SIGBUS) / KERN_PROTECTION_FAILURE. The crash site isil2cpp::vm::ClassMatches + 12atImage.cpp:326, reached viail2cpp::vm::Image::FromTypeNameParseInfo + 304atImage.cpp:377. The crash persists even when the community-recommended mitigations (frame-defer +ContinueWithOnMainThread) are in place — the main thread crashes while honoring those guards.Environment
IInitializable)Device distribution of affected crashes (14-day window, production):
Impact and frequency
Exception
Important:
KERN_PROTECTION_FAILUREindicates the faulting address resolves to a valid mapped page but the CPU's memory-protection bits rejected the access. This is the classic signature of a torn or stale pointer being dereferenced, not a null pointer returned from a stripped-type lookup.Crash stack (symbolicated, main-thread-init build)
User-code frames are redacted; Firebase / Unity / IL2CPP symbols preserved verbatim:
Note frames 9–11: the continuation is reached via
Firebase.Platform.Dispatcher.PollJobsfromFirebaseHandler.Updateon the Unity main thread — confirmingContinueWithOnMainThreadis being honored. The crash fires anyway.Historical context — Xcode bucket migration
Before the main-thread-init refactor, the identical crash (same top 3 frames, same exception type) was occurring on a background threadpool thread:
Because the Xcode crash grouping is primarily keyed off the main thread's state when the process dies, those older reports were bucketed under a generic "no useful main-thread stack" signature. Moving Firebase init to the main thread did not eliminate the race; it only changed how Xcode groups the resulting crashes (the crash now has a rich main-thread stack and a distinct signature).
Mitigations already in place (ineffective)
The following are both present in the currently shipping build where the 611-event crash count was collected. Neither eliminates the crash:
1. Frame-defer guard — defer Firebase init by one Update tick so IL2CPP's generic-metadata finalization on cold launch has time to settle before any Firebase reflection path runs:
2. Main-thread continuation — marshal the
CheckAndFixDependenciesAsync()continuation back to the Unity main thread before accessingFirebaseApp.DefaultInstance:The crash stack explicitly contains
<ContinueWithOnMainThread>b__1(frame 5) →Dispatcher_PollJobs(frame 10) →FirebaseHandler_Update(frame 11) →MonoBehaviour::CallUpdateMethod(frame 15) — proving the main-thread marshal is being honored. Thread 0 still crashes.Hypotheses
Cold-launch IL2CPP metadata race persists on main thread. The
UniTask.Yieldguard defers init by exactly one Update tick. IfCheckAndFixDependenciesAsync()completes near-synchronously (warm cache), the continuation fires almost immediately, andFirebaseApp.DefaultInstancecan touch IL2CPP type metadata while other main-thread work (generic method table construction, static cctors on the first access of certainUnityEngine.*types) is still mutating the metadata image.FromTypeNameParseInfothen reads a tornIl2CppMetadataTypeHandle— matching theKERN_PROTECTION_FAILUREsignal type (not a null return, which would be the stripping signature).iOS 26 W^X/PAC enforcement amplifies a pre-existing race. The crash is elevated on iOS 26.x (~70% of events). iOS 26's stricter page-protection enforcement may be surfacing races that prior iOS versions silently tolerated — in particular if any Firebase init path (or class realization triggered by it) touches pages mid-remap.
Stripping /
link.xmlare not the cause. The Firebase Unity SDK's bundledlink.xmlatAssets/Firebase/FirebaseApp/Internal/link.xmlalready preserves the types thatFirebaseInterops.csresolves by name (Firebase.Auth.FirebaseAuth,Firebase.AppCheck.FirebaseAppCheck).KERN_PROTECTION_FAILUREis inconsistent with stripping (which returns null, givingKERN_INVALID_ADDRESS), and a stripping root cause would crash every user on affected binary builds — not a single-digit percent.What we have not yet tried
FirebaseAppDelegateClassNameto Info.plist. We left this out because the crash stack is at the IL2CPP metadata layer (ClassMatches/FromTypeNameParseInfo), not obviously on the AppDelegate swizzle path. If the Firebase team believes it would alter the relevant code path, we are happy to test it.Questions for the Firebase team
FirebaseApp.CreateAndTrack(theFirebase.App.cpp:10051call site) that can still fire even withContinueWithOnMainThreadapplied?Firebase.App.cpp:10051perform aType.GetType(string)/Assembly.GetType(string)lookup, and if so, which type is being resolved? If it is a Firebase-internal type already covered by the SDK'slink.xml, what else could produce aKERN_PROTECTION_FAILUREat that offset?Related issues
Reproduction difficulty
We do not yet have a minimal Unity project that reliably reproduces this crash. The issue only manifests on a small fraction of user devices during cold launch, strongly suggesting timing/race sensitivity. We are happy to provide additional symbolicated
.crashfiles or to test diagnostic builds if the team can suggest instrumentation.Reproducing the issue
No response
Firebase Unity SDK Version
13.30
Unity editor version
2022.3..69
Installation Method
.unitypackage
Problematic Firebase Component(s)
No response
Other Firebase Component(s) in use
No response
Additional SDKs you are using
No response
Targeted Platform(s)
Apple Platforms
Unity editor platform
Mac
Scripting Runtime
IL2CPP
Release Distribution Type
Pre-built SDK from https://firebase.google.com/download/unity
Relevant Log Output
If using CocoaPods for Apple platforms, the project's Podfile.lock
Expand
Podfile.locksnippet👀 Replace this line with the contents of your Podfile.lock!