RealtimeSanitizer (a.k.a. RTSan) is a real-time safety testing tool for C and C++ projects. RTSan can be used to detect real-time violations, i.e. calls to methods that are not safe for use in functions with deterministic runtime requirements.
RTSan is part of the LLVM project, starting from v20.0.0. Like other popular
sanitizers, it uses a lightweight dynamic library that can detect real-time
unsafe system library calls. Calls to functions such as malloc, free and
pthread_mutex_lock (along with anything else RTSan believes may have a
non-deterministic execution time) will cause RTSan to error, but only if they
are called within a real-time context, as defined by the user. Real-time
contexts are defined by the user simply by marking functions with the
[[clang::nonblocking]] attribute.
Using RealtimeSanitizer requires LLVM 20's clang and two actions:
- Mark a real-time function with the
[[clang::nonblocking]]attribute:
void process(processing_data const & data) [[clang::nonblocking]]
{
auto x = std::vector<float> (16); // oops!
}- Add
-fsanitize=realtimeto your compile and link flags (for CMake see below):
clang -fsanitize=realtime main.cppAt run-time, real-time violations are presented with a stack trace:
> ./a.out
==1==ERROR: RealtimeSanitizer: unsafe-library-call
Intercepted call to real-time unsafe function `malloc` in real-time context!
#0 0x591265778cb8 in malloc /root/llvm-project/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp:444:3
#1 0x73a58271117b in operator new(unsigned long) (/test/lib/libstdc++.so.6+0xc517b)
#2 0x59126579f576 in std::__new_allocator<float>::allocate(unsigned long, void const*) /test/include/c++/15.0.0/bits/new_allocator.h:151:27
#3 0x59126579f576 in std::allocator_traits<std::allocator<float>>::allocate(std::allocator<float>&, unsigned long) /test/include/c++/15.0.0/bits/alloc_traits.h:614:20
#4 0x59126579f576 in std::_Vector_base<float, std::allocator<float>>::_M_allocate(unsigned long) /test/include/c++/15.0.0/bits/stl_vector.h:384:20
#5 0x59126579f576 in std::_Vector_base<float, std::allocator<float>>::_M_create_storage(unsigned long) /test/include/c++/15.0.0/bits/stl_vector.h:402:33
#6 0x59126579f576 in std::_Vector_base<float, std::allocator<float>>::_Vector_base(unsigned long, std::allocator<float> const&) /test/include/c++/15.0.0/bits/stl_vector.h:338:9
#7 0x59126579f576 in std::vector<float, std::allocator<float>>::vector(unsigned long, std::allocator<float> const&) /test/include/c++/15.0.0/bits/stl_vector.h:584:9
#8 0x59126579f4ed in process(processing_data const&) /app/example.cpp:10:14
#9 0x59126579f535 in main /app/example.cpp:15:5
#10 0x73a582229d8f (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
#11 0x73a582229e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
#12 0x591265777434 in _start (/app/output.s+0x6434)- Getting RTSan
- Documentation
- CMake
- How it works
- Using RTSan Standalone (with compilers other than clang 20)
- Contact
The easiest way to use RTSan is by using Clang 20 or later. Once Clang 20 is installed
on your system, compile and link with the -fsanitize=realtime flag.
To experiment with RealtimeSanitizer before downloading Clang 20 pull the pre-built docker
image,
which has clang (and other llvm tooling) with RTSan readily installed.
docker pull realtimesanitizer/rtsan-clangYou can quickly experiment in your own repository using a shared-volume:
docker run -v $(pwd):/my_repo -w /my_repo -it realtimesanitizer/rtsan-clang /bin/bashwhich mounts the host's current working directory at path /my_repo in the
container, and initialises the working directory to it. Alternatively, you may
prefer to use the RTSan Docker image as a parent image for your own development
or CI environment:
FROM realtimesanitizer/rtsan-clang:latest
RUN apt-get update && apt-get install -y git cmake vimApologies, RealtimeSanitizer does not yet support Windows. We very much welcome contributions, so please contact us if you're interested.
A full list of features and instructions for configuring RealtimeSanitizer can be found in the official docs here.
We have given various talks about RTSan at software engineering conferences. Note that the older the talk is, the more likely it is to have stale info in it.
LLVM 20 clang is installed to /usr/local in the RTSan Docker
image, and CMake will
automatically detect it. However, if you've built the latest LLVM from source,
you'll need to instruct CMake to use the right version of clang by either i)
setting the CC and CXX environment variables or ii) passing the
CMAKE_C_COMPILER and CMAKE_CXX_COMPILER options to CMake as arguments.
Adding the compile and link flag -fsanitize=realtime can be done however
works best for your project. One unobtrusive option is to pass them as
arguments to CMake:
cmake \
-DCMAKE_CXX_FLAGS="-fsanitize=realtime" \
-DCMAKE_C_FLAGS="-fsanitize=realtime" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=realtime" ...RTSan's algorithm consists of two parts that work together:
- A compilation step that
- signals real-time context entry and exit for the duration of
[[clang::nonblocking]]functions, and
- signals real-time context entry and exit for the duration of
- A lightweight runtime library that
- keeps track of the real-time context,
- detects calls to system library functions that are known to block, and
- raises an error if a blocking library function is called in a real-time context.
The recommended way to use RTSan is to use it with LLVM 20 directly, as described elsewhere in this document. The rest of this section describes a hack which may or may not continue to work in the future.
If you are in a position where you cannot use this compiler and instead rely on AppleClang, GCC, or an older version of Clang you can still use RTSan by directly linking in the runtime in directly.
Pre-built versions of the runtime library can be downloaded from the rtsan-libs repository. Download the appropriate library for your architecture and link it to your binary.
You can otherwise build the RTSan runtime by following the instructions in the official docs.
When you have built or downloaded the runtime library, simply link it to your binary. This differs based on system:
> cd $BUILD_DIR_MAC
> find . -name "*rtsan_osx*dylib"
./lib/clang/20/lib/darwin/libclang_rt.rtsan_osx_dynamic.dylib
...
> cat your_proj/CMakeLists.txt
...
target_link_libraries(helloWorld PRIVATE
libclang_rt.rtsan_osx_dynamic.dylib
)
> cd $BUILD_DIR_LINUX
> find . -name "libclang_rt.rtsan.a"
./lib/clang/20/lib/aarch64-unknown-linux-gnu/libclang_rt.rtsan.a
...
> cat your_proj/CMakeLists.txt
...
target_link_libraries(helloWorld PRIVATE
libclang_rt.rtsan.a
pthread
dl
)
In your code, you must #include "rtsan_standalone/rtsan_standalone.h", provided in this repo. Initialize RTSan, and put __rtsan::ScopedSanitizeRealtime() in places where you would normally use [[clang::nonblocking]] (in the top level of your real-time callback).
#include "rtsan_standalone/rtsan_standalone.h"
int main() {
__rtsan::Initialize();
...
}
void my_real_time_function() {
__rtsan::ScopedSanitizeRealtime ssr;
...
}To indicate that a function is not real-time safe, add the __RTSAN_NOTIFY_BLOCKING_CALL() macro to the first line of that function. This is analogous to marking the function [[clang::blocking]]
void my_unsafe_spinlock() {
__RTSAN_NOTIFY_BLOCKING_CALL();
...
}To "enable" the sanitizer, you must compile your code defining __SANITIZE_REALTIME, e.g.
clang++ main.cpp -D__SANITIZE_REALTIME
Without this flag, each of these aforementioned constructs will compile to a no-op, and the sanitizer will be disabled.
This header also defines __rtsan::ScopedDisabler(), which allows for disabling the sanitizer in a specific scope. Please see the official docs for more information.
RealtimeSanitizer was invented by David Trevelyan and Ali Barker, and the upstream integration was authored by Chris Apple and David Trevelyan, who continue its maintenance. We welcome further contributions to make this tool more helpful to a wider group of developers. For all comments, suggestions and queries, please contact us by:
- joining the Discord server,
- sending an email to [email protected], or
- raising an issue in this GitHub repository.