Time to Get Real – Introducing RealtimeSanitizer for Swift

Swift is modern, powerful, and versatile – but real-time coding can get tricky. Meet RTSanStandaloneSwift, our new Swift wrapper around LLVM’s RealtimeSanitizer, designed to help you write safe and effective real-time code.

Developing robust real-time systems brings a unique set of challenges. Real-time code must not only be logically correct but also execute within strict time constraints. Failing to meet these deadlines can lead to system failures, which means that thorough debugging and validation of real-time safety are absolutely essential. 

To simplify this intricate process, LLVM 20 introduces RealtimeSanitizer – a runtime analysis tool designed to detect operations that violate real-time constraints. While RealtimeSanitizer is initially available in the Clang compiler, its foundations are built within LLVM, allowing for broader language adoption. This has already been demonstrated with the Rust wrapper.

Over the past several months, we’ve collaborated with Chris Apple and David Trevelyan, creators of RealtimeSanitizer, to bring this powerful capability to Swift. Today, we’re excited to introduce RTSanStandaloneSwift – a Swift wrapper around RealtimeSanitizer that will enable Swift developers to build and maintain real-time applications more easily.

Real-time programming in Swift

C and C++ have long dominated real-time development due to their predictable performance and low-level control.

Swift, on the other hand, is a modern, fast, and memory-safe language that is interoperable with C++ and has cross-platform support, making it an attractive option for a wide range of applications. 

Swift’s project goal is to create the best available language for uses ranging from systems programming to mobile and desktop apps, scaling up to highly distributed cloud services.

While Swift has already demonstrated its capability as a real-time programming language, its high-level nature can make it challenging to reason about strict execution time requirements.

Let’s examine a simple Swift implementation of an audio processor:

	
	
class AudioProcessor {
    var gain = 1

    func process(buffer: inout [Float]) {
        for i in 0..<buffer.count {
            buffer[i] = buffer[i] * gain
        }
    }
}

Although this example resembles a straightforward C-style loop, it contains several potential pitfalls for real-time performance:

  • Exclusivity checking – which may allocate memory
  • Protocol lookup and metadata instantiation  – which may allocate memory or introduce locks
  • Copy-on-write behaviour on the array – which may allocate memory

Having a tool that can help us detect these issues would be invaluable.

How RealtimeSanitizer works

Similar to AddressSanitizer, RealtimeSanitizer works by intercepting “interesting” functions – in this context, those that could violate realtime-safety guarantees. Typically, these functions involve locks, memory allocation or I/O operations.

For a full list of intercepted functions, check out the implementation details.

In C++ (Clang), real-time sanitizer is activated by annotating a function with the [[clang:nonblocking]] attribute. When such a function invokes a real-time unsafe operation, the sanitizer aborts the process and provides a stack trace for debugging purposes.

RealtimeSanitizer also includes a suite of C functions that give developers fine-grained control over its behaviour.

RealtimeSanitizer in Swift

Leveraging Swift’s interoperability with C, we can invoke RealtimeSanitizer’s C bindings and create a more convenient Swift API.

RTSanStandaloneSwift is a lightweight implementation that introduces a user-friendly Swift macro for annotating functions that are subject to real-time constraints.

Similar to the [[clang:nonblocking]] attribute in C++, RTSanStandaloneSwift provides the @NonBlocking macro in Swift.

For example, we can annotate our earlier process function like this:

	
	
@NonBlocking
func process(buffer: inout [Float]) {
    for i in 0..<buffer.count {
        buffer[i] = buffer[i] * gain
    }
}

Now, when we run this code, RealtimeSanitizer will automatically detect and report any real-time violations:

	
	
==11917==ERROR: RealtimeSanitizer: unsafe-library-call
Intercepted call to real-time unsafe function `os_unfair_lock_lock` in real-time context!
    #0 in os_unfair_lock_lock rtsan_interceptors_posix.cpp:592
    #1 in _swift_allocObject_+0x1b4 (libswiftCore.dylib:arm64)
    #2 in _ArrayBuffer._consumeAndCreateNew(bufferIsUnique:minimumCapacity:)
    #3 0x00010061f5a4 in AudioProcessor_main main.swift:26

SUMMARY: RealtimeSanitizer: unsafe-library-call (libswiftCore.dylib) in _swift_allocObject

In this particular example, RealtimeSanitizer detected a lock within the Swift runtime triggered by the copy-on-write behavior during array mutation.

RTSanStandaloneSwift roadmap

We consider the current version of RTSanStandaloneSwift a transitional solution, and plan further improvements in the next stages:

Stage 1

Currently, RTSanStandaloneSwift ships with a prebuilt version of the RealtimeSanitizer dynamic library. While this approach is functional, it is not ideal in the long term. 

Stage 2

LLVM 20 is officially out, so when the first Swift nightly toolchains targeting LLVM 20 become available, we plan to phase out the prebuilt versions of the RealtimeSanitizer dynamic library. At that point, RTSanStandaloneSwift will rely entirely on the RealtimeSanitizer functionality provided directly in the toolchain.

Stage 3

Ultimately, our goal is to make a pitch for adding the attributes and the sanitizer as first-class features natively integrated into Swift.

Get involved and try it out

RTSanStandaloneSwift marks a significant milestone for real-time programming in Swift, enabling Swift developers to more easily write predictable and safe real-time code.

We’d love you to try it out, share your feedback and contribute to its ongoing development.