Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save cgcardona/2588b36fae7a32e58160e6bbdb58308f to your computer and use it in GitHub Desktop.

Select an option

Save cgcardona/2588b36fae7a32e58160e6bbdb58308f to your computer and use it in GitHub Desktop.

Xcode Diagnostics & Runtime Debugging Tools Guide

This document explains the debugging and runtime diagnostics tools available in Xcode's Diagnostics panel.
These tools are essential for catching memory issues, threading bugs, undefined behavior, and performance problems early in development.


🧪 Runtime Sanitization

Address Sanitizer (ASan)

What it does:
Detects memory corruption issues such as: - Use-after-free - Buffer overflows - Heap corruption - Dangling pointers

When to use:
Enable during heavy refactors or when chasing crashes like EXC_BAD_ACCESS.

Official Docs:
https://developer.apple.com/documentation/code_diagnostics/address_sanitizer

Reference: Address Sanitizer detects runtime memory errors and increases memory usage during debugging.


Detect Use of Stack After Return

What it does:
Extends Address Sanitizer to detect invalid access to stack memory after a function has returned.

When to use:
Useful when working with unsafe pointers, C/C++, or low‑level audio engine code.

Docs:
https://developer.apple.com/documentation/code_diagnostics/address_sanitizer


Thread Sanitizer (TSan)

What it does:
Detects threading issues such as: - Data races - Incorrect mutex usage - Unsafe concurrency access

When to use:
Critical for Swift concurrency, AVAudioEngine threading, and multi‑actor architectures.

Official Docs:
https://developer.apple.com/documentation/code_diagnostics/thread_sanitizer

Reference: Thread Sanitizer identifies race conditions and threading bugs at runtime.


Undefined Behavior Sanitizer (UBSan)

What it does:
Detects undefined operations like: - Integer overflow - Invalid casts - Illegal memory operations

When to use:
Great for catching subtle logic errors that don't always crash immediately.

Docs:
https://developer.apple.com/documentation/code_diagnostics/undefined_behavior_sanitizer

Reference: Undefined Behavior Sanitizer identifies undefined runtime operations.


🧵 Runtime API Checking

Main Thread Checker

What it does:
Warns when UI APIs are used off the main thread.

When to use:
Always safe to keep enabled during UI development and SwiftUI debugging.

Docs:
https://developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early


Thread Performance Checker

What it does:
Detects expensive operations running on the main thread that may cause UI hangs.

When to use:
Helpful when optimizing performance or diagnosing sluggish UI.

Docs:
https://developer.apple.com/documentation/xcode/diagnosing-memory-thread-and-crash-issues-early


🧠 Memory Management Debugging

Malloc Scribble

What it does:
Overwrites freed memory with patterns so invalid access is easier to detect.

Use when:
Tracking down memory stomps or weird state corruption.

Docs:
https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html


Malloc Guard Edges

What it does:
Places guard pages around allocations to catch buffer overruns immediately.

Docs:
https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html


Guard Malloc

What it does:
Replaces malloc with a debugging allocator that isolates allocations onto pages so invalid memory access crashes instantly.

Docs:
https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html

Reference: Guard Malloc forces crashes at the exact moment memory errors occur by isolating allocations.


Zombie Objects

What it does:
Prevents deallocated Objective‑C objects from being freed so you can detect messaging a deallocated instance.

Docs:
https://developer.apple.com/documentation/xcode/investigating-crashes-for-zombie-objects


Malloc Stack Logging

What it does:
Records allocation stack traces so you can see where memory was created or freed.

Useful with: - Instruments - Leaks tool - Memory Graph Debugger

Docs:
https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html


⚠️ Best Practices for Teams

  • Don't ship with sanitizers enabled --- they reduce performance significantly.
  • Create a dedicated Sanitizer Debug Scheme.
  • Run ASan + TSan regularly in CI for stability.
  • Use Guard Malloc only for deep debugging --- it is very slow.

🎯 Quick Recommendations (From Real‑World DAW Development)

If you're building complex apps like audio engines or concurrency-heavy systems:

✅ Address Sanitizer → Memory safety
✅ Thread Sanitizer → Actor/thread bugs
✅ Main Thread Checker → UI correctness
✅ Instruments → Performance profiling

These four together catch the majority of production crashes early.

🧰 LLDB Crash Debugging Essentials

While sanitizers help detect problems early, LLDB is often the fastest way to understand why a crash happened. When Xcode pauses execution, LLDB lets you inspect every thread, stack frame, and loaded binary in real time.


🔎 Core Commands Every macOS Developer Should Know

thread backtrace all / bt all

Shows the full stack trace for every thread in the process.

thread backtrace all
bt all

Use this when:

  • Investigating deadlocks or freezes
  • Diagnosing Swift concurrency issues
  • Debugging background or audio threads

thread info

Displays detailed information about the currently selected thread.

thread info

Helpful for identifying:

  • QoS / priority issues
  • Actor execution context
  • Suspended or blocked threads

image lookup -a <address>

Resolves a raw memory address to the symbol and binary it belongs to.

image lookup -a 0x123456789

Extremely useful when:

  • Working from crash logs with raw addresses
  • Debugging optimized builds
  • Investigating framework or AudioUnit crashes

🧠 Additional LLDB Commands Worth Knowing

frame variable

Inspect local variables in the current stack frame.

frame variable

thread select <id>

Switch between threads.

thread select 5

po <expression>

Prints an Objective-C or Swift object description.

po engine
po projectStore

register read

Shows CPU register state --- useful when debugging low-level crashes.

register read

⚠️ Best Practices

  • Capture bt all immediately after a crash before continuing execution.
  • Combine LLDB with Address Sanitizer and Thread Sanitizer for maximum visibility.
  • Async boundaries can hide root causes --- inspect multiple threads.
  • Real-time systems often crash off the main thread, so check worker threads first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment