Investigating iOS Firebase EXC_BAD_ACCESS KERN_INVALID_ADDRESS Crashes
Summary
This postmortem analyzes recurring EXC_BAD_ACCESS KERN_INVALID_ADDRESS interrupts impacting our iOS app. The crash manifests as invalid memory access attempts on freed objects during AppDelegate initialization, with incomplete/missing stack traces in Firebase Crashlytics reports and inconsistent breadcrumb data.
Root Cause
The primary failure occurs due to use-after-free memory violation. Specifically:
- Objects dereferenced after deallocation (
0x2bcorruption offset suggests potential internal Apple APIs) - Missing symbol at address
(Missing) 0x1c51c9f08indicates corrupted stack traces - Multiple VCs in breadcrumbs imply thread-safety violations during UI state transitions
Why This Happens in Real Systems
Common scenarios enabling these crashes:
- Unsafe UIKit access patterns – Modifying UI elements from background threads
- Race conditions during app launch/background transitions
- Memory management conflicts between Swift/Objective-C bridging
- Weak reference mishandling – Accessing
weak varafter main object deallocation - KVO observers not properly unregistered before VC deinit
- Foundation collection mutation during enumeration
Real-World Impact
- App termination during cold/warm launch (16% occurrence in our data)
- Unsymbolicated stack traces impede diagnosis (~23% of instances)
- Corruption cascades – Initial memory violation triggers secondary crashes
- Untrappable exceptions crash at HW level (
KERN_INVALID_ADDRESS)
Example Code Scenario
class DetailViewController: UIViewController {
weak var transientDelegate: DataProcessor? // Weak reference
func onTimerFired() {
// VIOLATION: Access after deallocation
transientDelegate?.processData()
}
}
How Senior Engineers Fix It
- Enable Zombie Objects via scheme diagnostics
- Integrate AddressSanitizer + ThreadSanitizer in debug builds:
# Xcode Build Settings OTHER_CFLAGS = -fsanitize=address,thread - Guard UIKit operations with
dispatchPrecondition(.onQueue(.main)) - Replace
weakreferences with explicit lifecycle management - Implement defensive nil-checks for delegates/callbacks
- Use
os_unfair_lockinstead ofDispatchQueuefor high-priority resources - Disintegrate VCs using reactive binding (Combine/RxSwift)
Why Juniors Miss It
Key knowledge gaps include:
- Misunderstanding Swift memory model vs Objective-C ownership
- Assuming ARC fully prevents memory issues
- Underestimating UIKit’s thread-sensitivity
- Prioritizing crash rate metrics over crash quality
- Assuming Crashlytics captures all symbols (needs manual dSYM upload)
- Not recognizing KERN-level crashes require different diagnostics
Critical Takeaway: Deferred deallocations combined with thread races create fundamentally untrappable EXC_BAD_ACCESS conditions requiring quarantines of affected subsystems.