iOS Firebase EXC_BAD_ACCESS KERN_INVALID_ADDRESS

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 (0x2b corruption offset suggests potential internal Apple APIs)
  • Missing symbol at address (Missing) 0x1c51c9f08 indicates 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 var after 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

  1. Enable Zombie Objects via scheme diagnostics
  2. Integrate AddressSanitizer + ThreadSanitizer in debug builds:
    # Xcode Build Settings
    OTHER_CFLAGS = -fsanitize=address,thread
  3. Guard UIKit operations with dispatchPrecondition(.onQueue(.main))
  4. Replace weak references with explicit lifecycle management
  5. Implement defensive nil-checks for delegates/callbacks
  6. Use os_unfair_lock instead of DispatchQueue for high-priority resources
  7. 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.