Skip to content

Tracktion/rtcheck

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build

rtcheck

Dynamic library to catch run-time safety violations heavily inspired by RADSan

Contents

Adding rtcheck to a project

CMake option 1: Git Submodule

git submodule add -b main https://github.com/Tracktion/rtcheck rtcheck

To update down the road:

git submodule update --remote --merge rtcheck

Build rtcheck as part of your CMakeLists.txt

add_subdirectory(rtcheck)

CMake option 2: FetchContent

Include(FetchContent)
FetchContent_Declare(rtcheck
    GIT_REPOSITORY https://github.com/Tracktion/rtcheck.git
    GIT_TAG origin/main
    SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/rtcheck)
FetchContent_MakeAvailable(rtcheck)

Link rtcheck to your CMake project

target_link_libraries("YourProject" PRIVATE rtcheck)

Then include rtcheck in your source files:

#include <rtcheck.h>

Using rtcheck

Simply add an instance of rtc::realtime_context at the start of the scope you want to check for real-time safety violations like this:

int main()
{
    std::thread t ([]
    {
        rtc::realtime_context rc;
        malloc (1024); // Allocating memory is a real-time safety violation!
    });

    t.join();

    return 0;
}

The call to malloc in the above code will then be caught and logged as so:

Real-time violation: intercepted call to real-time unsafe function malloc in real-time context! Stack trace:
0   librt_check.dylib                   0x000000010543f7d4 _ZN3rtc14get_stacktraceEv + 84
 1   librt_check.dylib                   0x000000010543f450 _ZN3rtc32log_function_if_realtime_contextEPKc + 300
  2   librt_check.dylib                   0x000000010543fe00 _Z44log_function_if_realtime_context_and_enabledN3rtc11check_flagsEPKc + 64
   3   librt_check.dylib                   0x000000010543fe30 wrap_malloc + 32
    4   fail_malloc                         0x0000000104fcff14 main + 32
     5   dyld                                0x00000001901760e0 start + 2360

Disabling checks

There are two ways to disable checks. You can either disable all checks, which can be useful if you know you'll be calling a potentially unsafe function but in a safe way (e.g. an un-contented lock), or you want to log something:

{
    rtc::non_realtime_context nrc;
    std::cout << "need to get this message on the screen!";
}

Or you can selectively disable checks:

{
    rtc::disable_checks_for_thread (check_flags::threads);
    mutex.lock(); // I know this is uncontended, don't for get to unlock!
}

Catching your own violations

If you have some code which you know is non-real-time safe e.g. an unbounded distribution function or some other async call, you can opt-in to let rtcheck catch it by calling the following function:

void my_unsafe_function()
{
    log_function_if_realtime_context (__func__);
}

This will then get logged if called whilst a rtc::realtime_context is alive.

Error Modes

There are two currently supported error modes

  • Exit with error code 1 (default)
  • Log and continue

Exiting it useful for CI runs where you want the program to terminate in an obvious way (non-zero exit code) to fail the run. In normal use though, you may just want to log the violation and continue.

You can change between these globally using the following function:

/** Sets the global error more to determine the behaviour when a real-time
    violation is detected.
*/
void set_error_mode (error_mode);

Notes:

Features

  • Enable in scope
  • Disable in scope
  • Symbolicated stack-trace
  • Run-time options for checks
  • Opt-in for own code
  • linux
  • macOS (malloc unsupported)
  • Add option to realtime_context constructor to disable checks for that scope
  • Delay time

Functions (test = ✔)

  • Time
    • sleep ✔
    • nanosleep ✔
    • usleep ✔
  • Memory
    • malloc ✔
    • calloc ✔
    • realloc ✔
    • free ✔
    • reallocf (macOS) ✔
    • valloc ✔
    • posix_memalign ✔
    • mmap ✔
    • munmap ✔
  • Threads
    • pthread_create ✔
    • pthread_mutex_lock ✔
    • pthread_mutex_unlock ✔
    • pthread_join ✔
    • pthread_cond_signal
    • pthread_cond_broadcast
    • pthread_cond_wait
    • pthread_cond_timedwait
    • pthread_rwlock_rdlock ✔
    • pthread_rwlock_unlock ✔
    • pthread_rwlock_wrlock ✔
    • pthread_spin_lock (linux)
  • Files
    • open ✔
    • openat
    • close
    • fopen
    • fread
    • fwrite
    • fclose
    • fcntl ✔
    • creat
    • puts
    • fputs
    • stat ✔
    • stat64
    • fstat
    • fstat64
  • IO
    • socket
    • send
    • sendmsg
    • sendto
    • recv
    • recvmsg
    • recvfrom
    • shutdown
  • System calls
    • syscall ✔
    • schedule
    • context_switch

CI/Tests

  • Failures
    • Throwing exceptions
    • Large std::function
    • Atomic 4*ptr size
    • Dynamic loading of a library
  • Passes
    • Atomic double
    • Small std::function
    • thread_local? (pass on linux, fail on macOS)
  • Running on CI Linux
  • Running on CI macOS
  • Tests via CTest (can catch failues)

Packages

  • cpack
  • conan
  • vcpkg

About

Dynamic library to catch run-time safety violations

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published