Article

Swift Access Races

Detects when multiple threads call a mutating method on the same structure, or pass a shared variable as inout without synchronization.

Overview

This check detects access races that occur when calling a mutating function is called on the same structure without synchronization or when a shared variable is passed as an inout parameter to a function call without synchronization. Access races can result in unpredictable behavior.

Access Race with Mutating Struct Methods

In the following example, the producer() function adds a message to a global array and the consumer() function removes the messages and prints them. Because producer() is executed on one thread and consumer() is executed on another and both call mutating methods on the array, there is an access race on messages.

var messages: [String] = []
// Executed on Thread #1
func producer() {
    messages.append("A message");
}
// Executed on Thread #2
func consumer() {
    repeat {
        let message = messages.remove(at: 0)
        print("\(message)")
    } while !messages.isEmpty
}

Solution

Use Dispatch APIs to coordinate access to messages across multiple threads.

Access Race with inout Parameters

In the following example, the writeNumbers() function writes numbers to a global string, and the writeLetters() function writes letters to the same string. Because the two functions are called on different threads and both access log as inout, there is an access race on log.

var log: String = ""
// Executed on Thread #1
func writeNumbers() {
    print(1, 2, 3, separator: ",", to: &log)
}
// Executed on Thread #2
func writeLetters() {
    print("a", "b", "c", separator:",", to: &log)
}

Solution

Use Dispatch APIs to coordinate access to log across multiple threads.

See Also

Thread Sanitizer Checks

Data Races

Detects unsynchronized access to mutable state across multiple threads.

Races on Collections and Other APIs

Detects when a thread accesses a mutable object while another thread writes to that object, causing a data race.

Uninitialized Mutexes

Detects when a mutex is used before it’s initialized.

Thread Leaks

Detects when threads aren’t closed after use.