tezvyn:

Thread Sanitizer catches data races in Swift

AI-drafted, machine-checkedintermediate

Thread Sanitizer turns flaky race crashes into reproducible reports by monitoring memory accesses at runtime. Use it in Xcode to catch unsynchronized cross-thread reads and writes. It only catches races that execute during your test run, so coverage matters.

WHY IT EXISTS: Data races are among the hardest bugs to reproduce because they depend on exact timing between threads. A race can corrupt memory, crash randomly, or pass tests yet fail in production. Traditional debuggers and breakpoints often hide races by changing timing. Thread Sanitizer was built to make these failures deterministic by detecting the race the moment it happens.

THE MENTAL MODEL: Think of Thread Sanitizer as a strict referee watching every read and write to memory. It records which thread touched which byte and when. If two threads access the same memory without synchronization and at least one writes, it blows the whistle immediately. It trades runtime performance for certainty, slowing execution dramatically to maintain this shadow history.

HOW IT WORKS: TSan instruments your code at compile time, inserting checks around every memory access and synchronization primitive. It maintains a shadow state in memory that tracks the happens before relationship between threads using vector clocks. When an access violates the happens before ordering, it reports a data race with a full stack trace for both threads. It also detects other threading issues like Swift actor isolation violations, lock ordering inversions, and unsafe use of atomic operations.

WHEN TO USE IT: Enable TSan during unit tests, UI tests, and dedicated integration test runs on the simulator or macOS. It is especially valuable when refactoring legacy code that uses GCD, OperationQueue, or manual pthreads, and when verifying that new Swift concurrency code correctly uses actors and Sendable boundaries. Run it on CI before merging concurrency heavy changes.

WHEN NOT TO USE IT: Do not ship it in production or use it on device in performance sensitive scenarios. The overhead makes it unsuitable for user facing builds or profiling. It also cannot detect races inside system libraries that were not compiled with TSan instrumentation, and it will not catch races in code that your tests do not execute. It is not a replacement for static analysis or careful code review.

ONE CANONICAL EXAMPLE: Imagine a shared counter incremented from multiple GCD queues without a lock. In normal execution it might miscount silently. With TSan enabled, the simultaneous unsynchronized increment is flagged instantly, showing the exact lines in both queues that touched the counter and the lack of a happens before edge between them.

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.