brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.4 KiB · 4ce976a Raw
357 lines · plain
1=================2RealtimeSanitizer3=================4 5.. contents::6   :local:7 8Introduction9============10RealtimeSanitizer (a.k.a. RTSan) is a real-time safety testing tool for C and C++11projects. RTSan can be used to detect real-time violations, i.e. calls to methods12that are not safe for use in functions with deterministic run time requirements.13RTSan considers any function marked with the ``[[clang::nonblocking]]`` attribute14to be a real-time function. At run-time, if RTSan detects a call to ``malloc``, 15``free``, ``pthread_mutex_lock``, or anything else known to have a 16non-deterministic execution time in a function marked ``[[clang::nonblocking]]``17it raises an error. 18 19RTSan performs its analysis at run-time but shares the ``[[clang::nonblocking]]`` 20attribute with the :doc:`FunctionEffectAnalysis` system, which operates at 21compile-time to detect potential real-time safety violations. For comprehensive 22detection of real-time safety issues, it is recommended to use both systems together.23 24The runtime slowdown introduced by RealtimeSanitizer is negligible.25 26How to build27============28 29Build LLVM/Clang with `CMake <https://llvm.org/docs/CMake.html>`_ and enable the30``compiler-rt`` runtime. An example CMake configuration that will allow for the31use/testing of RealtimeSanitizer:32 33.. code-block:: console34 35   $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="compiler-rt" <path to source>/llvm36 37Usage38=====39 40There are two requirements:41 421. The code must be compiled with the ``-fsanitize=realtime`` flag.432. Functions that are subject to real-time constraints must be marked44   with the ``[[clang::nonblocking]]`` attribute.45 46Typically, these attributes should be added onto the functions that are entry47points for threads with real-time priority. These threads are subject to a fixed48callback time, such as audio callback threads or rendering loops in video game49code.50 51.. code-block:: console52 53   % cat example_realtime_violation.cpp54   #include <vector>55 56   void violation() [[clang::nonblocking]]{57     std::vector<float> v;58     v.resize(100);59   }60 61   int main() {62     violation();63     return 0;64   }65   # Compile and link66   % clang++ -fsanitize=realtime example_realtime_violation.cpp67 68If a real-time safety violation is detected in a ``[[clang::nonblocking]]``69context, or any function invoked by that function, the program will exit with a70non-zero exit code.71 72.. code-block:: console73 74   % clang++ -fsanitize=realtime example_realtime_violation.cpp75   % ./a.out76   ==76290==ERROR: RealtimeSanitizer: unsafe-library-call77   Intercepted call to real-time unsafe function `malloc` in real-time context!78       #0 0x000102a7b884 in malloc rtsan_interceptors.cpp:42679       #1 0x00019c326bd0 in operator new(unsigned long)+0x1c (libc++abi.dylib:arm64+0x16bd0)80       #2 0xa30d0001024f79a8  (<unknown module>)81       #3 0x0001024f794c in std::__1::__libcpp_allocate[abi:ne200000](unsigned long, unsigned long)+0x4482       #4 0x0001024f78c4 in std::__1::allocator<float>::allocate[abi:ne200000](unsigned long)+0x4483       ... snip ...84       #9 0x0001024f6868 in std::__1::vector<float, std::__1::allocator<float>>::resize(unsigned long)+0x4885       #10 0x0001024f67b4 in violation()+0x2486       #11 0x0001024f68f0 in main+0x18 (a.out:arm64+0x1000028f0)87       #12 0x00019bfe3150  (<unknown module>)88       #13 0xed5efffffffffffc  (<unknown module>)89 90 91Blocking functions92------------------93 94Calls to system library functions such as ``malloc`` are automatically caught by95RealtimeSanitizer. Real-time programmers may also write their own blocking96(real-time unsafe) functions that they wish RealtimeSanitizer to be aware of.97RealtimeSanitizer will raise an error at run time if any function attributed98with ``[[clang::blocking]]`` is called in a ``[[clang::nonblocking]]`` context.99 100.. code-block:: console101 102    $ cat example_blocking_violation.cpp103    #include <atomic>104    #include <thread>105 106    std::atomic<bool> has_permission{false};107 108    int wait_for_permission() [[clang::blocking]] {109      while (has_permission.load() == false)110        std::this_thread::yield();111      return 0;112    }113 114    int real_time_function() [[clang::nonblocking]] {115      return wait_for_permission();116    }117 118    int main() {119      return real_time_function();120    }121 122    $ clang++ -fsanitize=realtime example_blocking_violation.cpp && ./a.out123    ==76131==ERROR: RealtimeSanitizer: blocking-call124    Call to blocking function `wait_for_permission()` in real-time context!125        #0 0x0001000c3db0 in wait_for_permission()+0x10 (a.out:arm64+0x100003db0)126        #1 0x0001000c3e3c in real_time_function()+0x10 (a.out:arm64+0x100003e3c)127        #2 0x0001000c3e68 in main+0x10 (a.out:arm64+0x100003e68)128        #3 0x00019bfe3150  (<unknown module>)129        #4 0x5a27fffffffffffc  (<unknown module>)130 131 132Run-time flags133--------------134 135RealtimeSanitizer supports a number of run-time flags, which can be specified in the ``RTSAN_OPTIONS`` environment variable:136 137.. code-block:: console138 139   % RTSAN_OPTIONS=option_1=true:path_option_2="/some/file.txt" ./a.out140   ...141 142Or at compile-time by providing the symbol ``__rtsan_default_options``:143 144.. code-block:: c145 146  __attribute__((__visibility__("default")))147  extern "C" const char *__rtsan_default_options() {148    return "symbolize=false:abort_on_error=0:log_to_syslog=0";149  }150 151You can see all sanitizer options (some of which are unsupported) by using the ``help`` flag:152 153.. code-block:: console154 155   % RTSAN_OPTIONS=help=true ./a.out156 157A **partial** list of flags RealtimeSanitizer respects:158 159.. list-table:: Run-time Flags160   :widths: 20 10 10 70161   :header-rows: 1162 163   * - Flag name164     - Default value165     - Type166     - Short description167   * - ``halt_on_error``168     - ``true``169     - boolean170     - Exit after first reported error.171   * - ``suppress_equal_stacks``172     - ``true``173     - boolean174     - If true, suppress duplicate reports (i.e. only print each unique error once). Only particularly useful when ``halt_on_error=false``.175   * - ``print_stats_on_exit``176     - ``false``177     - boolean178     - Print stats on exit. Includes total and unique errors.179   * - ``color``180     - ``"auto"``181     - string182     - Colorize reports: (always|never|auto).183   * - ``fast_unwind_on_fatal``184     - ``false``185     - boolean186     - If available, use the fast frame-pointer-based unwinder on detected errors. If true, ensure the code under test has been compiled with frame pointers with ``-fno-omit-frame-pointers`` or similar.187   * - ``abort_on_error``188     - OS dependent189     - boolean190     - If true, the tool calls ``abort()`` instead of ``_exit()`` after printing the error report. On some OSes (macOS, for example) this is beneficial because a better stack trace is emitted on crash.191   * - ``symbolize``192     - ``true``193     - boolean194     - If set, use the symbolizer to turn virtual addresses to file/line locations. If false, can greatly speed up the error reporting.195   * - ``suppressions``196     - ``""``197     - path198     - If set to a valid suppressions file, will suppress issue reporting. See details in `Disabling and Suppressing`_.199   * - ``verify_interceptors``200     - ``true``201     - boolean202     - If true, verifies interceptors are working at initialization. The program will abort with error ``==ERROR: Interceptors are not working. This may be because RealtimeSanitizer is loaded too late (e.g. via dlopen)`` if an issue is detected.203 204Some issues with flags can be debugged using the ``verbosity=$NUM`` flag:205 206.. code-block:: console207 208   % RTSAN_OPTIONS=verbosity=1:misspelled_flag=true ./a.out209   WARNING: found 1 unrecognized flag(s):210   misspelled_flag211   ...212 213Additional customization214------------------------215 216In addition to ``__rtsan_default_options`` outlined above, you can provide definitions of other functions that affect how RTSan operates.217 218To be notified on every error reported by RTsan, provide a definition of ``__sanitizer_report_error_summary``.219 220.. code-block:: c221 222   extern "C" void __sanitizer_report_error_summary(const char *error_summary) {223      fprintf(stderr, "%s %s\n", "In custom handler! ", error_summary);224      /* do other custom things */225   }226 227The error summary will be of the form: 228 229.. code-block:: console230 231   SUMMARY: RealtimeSanitizer: unsafe-library-call main.cpp:8 in process(std::__1::vector<int, std::__1::allocator<int>>&)232 233To register a callback which will be invoked before a RTSan kills the process:234 235.. code-block:: c236 237  extern "C" void __sanitizer_set_death_callback(void (*callback)(void));238 239  void custom_on_die_callback() {240    fprintf(stderr, "In custom handler!")241    /* do other custom things */242  }243 244  int main()245  {246    __sanitizer_set_death_callback(custom_on_die_callback);247    ...248  }249 250.. _disabling-and-suppressing:251 252Disabling and suppressing253-------------------------254 255There are multiple ways to disable error reporting when using RealtimeSanitizer.256 257In general, ``ScopedDisabler`` should be preferred, as it is the most performant.258 259.. list-table:: Suppression methods260   :widths: 30 15 15 10 70261   :header-rows: 1262 263   * - Method264     - Specified at?265     - Scope266     - Run-time cost267     - Description268   * - ``ScopedDisabler``269     - Compile-time270     - Stack271     - Very low272     - Violations are ignored for the lifetime of the ``ScopedDisabler`` object.273   * - ``function-name-matches`` suppression274     - Run-time275     - Single function276     - Medium277     - Suppresses intercepted and ``[[clang::blocking]]`` function calls by name.278   * - ``call-stack-contains`` suppression279     - Run-time280     - Stack281     - High282     - Suppresses any stack trace containing the specified pattern.283    284 285``ScopedDisabler``286##################287 288At compile time, RealtimeSanitizer may be disabled using ``__rtsan::ScopedDisabler``. RTSan ignores any errors originating within the ``ScopedDisabler`` instance variable scope.289 290.. code-block:: c++291 292    #include <sanitizer/rtsan_interface.h>293 294    void process(const std::vector<float>& buffer) [[clang::nonblocking]] {295        {296            __rtsan::ScopedDisabler d;297            ...298        }299    }300 301If RealtimeSanitizer is not enabled at compile time (i.e., the code is not compiled with the ``-fsanitize=realtime`` flag), the ``ScopedDisabler`` is compiled as a no-op.302 303In C, you can use the ``__rtsan_disable()`` and ``rtsan_enable()`` functions to manually disable and re-enable RealtimeSanitizer checks.304 305.. code-block:: c++306 307    #include <sanitizer/rtsan_interface.h>308 309    int process(const float* buffer) [[clang::nonblocking]]310    {311        {312            __rtsan_disable();313 314            ...315 316            __rtsan_enable();317        }318    }319 320Each call to ``__rtsan_disable()`` must be paired with a subsequent call to ``__rtsan_enable()`` to restore normal sanitizer functionality. If a corresponding ``rtsan_enable()`` call is not made, the behavior is undefined.321 322Suppression file323################324 325At run-time, suppressions may be specified using a suppressions file passed in ``RTSAN_OPTIONS``. Run-time suppression may be useful if the source cannot be changed.326 327.. code-block:: console328 329   > cat suppressions.supp330   call-stack-contains:MallocViolation331   call-stack-contains:std::*vector332   function-name-matches:free333   function-name-matches:CustomMarkedBlocking*334   > RTSAN_OPTIONS="suppressions=suppressions.supp" ./a.out335   ...336 337Suppressions specified in this file are one of two flavors.338 339``function-name-matches`` suppresses reporting of any intercepted library call, or function marked ``[[clang::blocking]]`` by name. If, for instance, you know that ``malloc`` is real-time safe on your system, you can disable the check for it via ``function-name-matches:malloc``.340 341``call-stack-contains`` suppresses reporting of errors in any stack that contains a string matching the pattern specified. For example, suppressing error reporting of any non-real-time-safe behavior in ``std::vector`` may be specified ``call-stack-contains:std::*vector``. You must include symbols in your build for this method to be effective, unsymbolicated stack traces cannot be matched. ``call-stack-contains`` has the highest run-time cost of any method of suppression.342 343Patterns may be exact matches or are "regex-light" patterns, containing special characters such as ``^$*``.344 345The number of potential errors suppressed via this method may be seen on exit when using the ``print_stats_on_exit`` flag.346 347Compile-time sanitizer detection348--------------------------------349 350Clang provides the pre-processor macro ``__has_feature`` which may be used to detect if RealtimeSanitizer is enabled at compile-time.351 352.. code-block:: c++353 354    #if defined(__has_feature) && __has_feature(realtime_sanitizer)355    ...356    #endif357