Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[compiler-rt] Realtime Sanitizer: Introduce Realtime Sanitizer (RTSan) backend #92460

Merged
merged 47 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
81ec957
First try
cjappl May 7, 2024
76d9cd9
Fixing some clang tidy foo
cjappl May 7, 2024
7b476ec
One round of renaming
cjappl May 7, 2024
cfbde34
Another round of style cleanups
cjappl May 7, 2024
3dd143f
more auto removal, more case fixing
cjappl May 7, 2024
9eaded1
Missing end of namespace comment
cjappl May 7, 2024
11030b6
Fix one naming issue
cjappl May 8, 2024
d92cb45
No more unistd
cjappl May 13, 2024
985fe27
Radsan context moved to impl
cjappl May 13, 2024
9d4e76f
Promise lit tests later
cjappl May 13, 2024
04f234a
Move radsan_test and add helper comment to top of file
cjappl May 13, 2024
41f1cd1
Only link radsan statically
cjappl May 13, 2024
680189c
Fix comments in radsan.h
cjappl May 15, 2024
b1d0789
Replace inlined exit with selected action stub
davidtrevelyan May 16, 2024
b5a7f7a
Codeowners
cjappl May 16, 2024
43d0141
Fix python formatting errors
cjappl May 16, 2024
06aa72d
Fix cpp style issues
cjappl May 16, 2024
86191f1
PR: Delete python header comment
cjappl May 20, 2024
47ea072
PR: Change main namespace name to __radsan
cjappl May 20, 2024
26a571b
PR: Fix stack trace namespace
cjappl May 20, 2024
71ae4a2
PR: Fix incorrect C++ style comments
cjappl May 20, 2024
8dde886
PR: Prefix external API with dunderscores
cjappl May 20, 2024
0a7062e
PR: Fix variable naming cases for variables, leave lambdas for now
cjappl May 20, 2024
38d8436
PR: Fix style nit
cjappl May 20, 2024
ddab264
PR: Fix small style fallout
cjappl May 20, 2024
d12e0f1
Update comment and TU-local function style
davidtrevelyan May 21, 2024
91bf6ed
PR: Remove too early inclusion of sanitizer common lit tests
cjappl May 21, 2024
c7a911e
Test failure: fix initialization of pthread_cond_t
cjappl May 30, 2024
1e2322d
Test failure: Try again with initialization of pthread_cond_t
cjappl May 30, 2024
3f976f8
Fix code formatting on unit test
cjappl May 30, 2024
da347d8
Ensure all pthread_cond_t are initialized in unit tests
cjappl May 30, 2024
7710e55
Fix issue where CREAT flag was not properly passing mode (#23)
cjappl May 31, 2024
7e430f8
Fix issue where fcntl was not using last arg correctly (#24)
cjappl May 31, 2024
0ae584d
Introduce test fixture for temporary files (#25)
cjappl Jun 1, 2024
91422bd
Clean out temp files in test fixture SetUp too
davidtrevelyan Jun 1, 2024
4b491aa
Rename RADSan to RTSan
davidtrevelyan Jun 3, 2024
c717391
First working rtsan driver tests
cjappl Jun 5, 2024
035d933
Add linux working test
cjappl Jun 5, 2024
1b3bfad
Another test for openBSD
cjappl Jun 5, 2024
cf32e04
Add feature for realtime sanitizer, add incompatible sanitizers
cjappl Jun 5, 2024
e03a8f0
More incompatabilities added
cjappl Jun 5, 2024
900632c
rtsan tests to fsanitize
cjappl Jun 5, 2024
df5f31b
Deleted rtsan.c
cjappl Jun 5, 2024
a375aca
Code formatting
cjappl Jun 5, 2024
40862de
Fix python styling
cjappl Jun 26, 2024
07d1ae5
PR: Get rid of clang components only leave compiler-rt
cjappl Jul 3, 2024
7d531a7
PR: MaskRay comments
cjappl Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler-rt/CODE_OWNERS.TXT
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@ D: ThreadSanitizer
N: Bill Wendling
E: [email protected]
D: Profile runtime library

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW @alexander-shaposhnikov NSAN is missing from here.

N: Christopher Apple, David Trevelyan
E: [email protected], [email protected]
D: Realtime Sanitizer (RTSan)
3 changes: 3 additions & 0 deletions compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
${LOONGARCH64})
set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM64_32})
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64})
set(ALL_RTSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
${LOONGARCH64})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was copied from ASAN, is this acceptable? We don't have all architectures to test, although we think that our interceptors are simple enough to work on any machine (no platform specific assembly in our code, for example)


if(ANDROID)
set(OS_NAME "Android")
Expand Down
12 changes: 11 additions & 1 deletion compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,9 @@ if(APPLE)
list_intersect(ASAN_SUPPORTED_ARCH
ALL_ASAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(RTSAN_SUPPORTED_ARCH
ALL_RTSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(DFSAN_SUPPORTED_ARCH
ALL_DFSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
Expand Down Expand Up @@ -663,6 +666,7 @@ else()
filter_available_targets(UBSAN_COMMON_SUPPORTED_ARCH
${SANITIZER_COMMON_SUPPORTED_ARCH})
filter_available_targets(ASAN_SUPPORTED_ARCH ${ALL_ASAN_SUPPORTED_ARCH})
filter_available_targets(RTSAN_SUPPORTED_ARCH ${ALL_RTSAN_SUPPORTED_ARCH})
filter_available_targets(FUZZER_SUPPORTED_ARCH ${ALL_FUZZER_SUPPORTED_ARCH})
filter_available_targets(DFSAN_SUPPORTED_ARCH ${ALL_DFSAN_SUPPORTED_ARCH})
filter_available_targets(LSAN_SUPPORTED_ARCH ${ALL_LSAN_SUPPORTED_ARCH})
Expand Down Expand Up @@ -716,7 +720,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
endif()
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")

set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
set(ALL_SANITIZERS asan;rtsan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
"sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
Expand Down Expand Up @@ -747,6 +751,12 @@ else()
set(COMPILER_RT_HAS_ASAN FALSE)
endif()

if (COMPILER_RT_HAS_SANITIZER_COMMON AND RTSAN_SUPPORTED_ARCH)
set(COMPILER_RT_HAS_RTSAN TRUE)
else()
set(COMPILER_RT_HAS_RTSAN FALSE)
endif()

if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD|SunOS")
set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)
else()
Expand Down
92 changes: 92 additions & 0 deletions compiler-rt/lib/rtsan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
include_directories(..)

set(RTSAN_CXX_SOURCES
rtsan.cpp
rtsan_context.cpp
rtsan_stack.cpp
rtsan_interceptors.cpp)

set(RTSAN_PREINIT_SOURCES
rtsan_preinit.cpp)

set(RTSAN_HEADERS
rtsan.h
rtsan_context.h
rtsan_stack.h)

set(RTSAN_DEPS)

set(RTSAN_CFLAGS
${COMPILER_RT_COMMON_CFLAGS}
${COMPILER_RT_CXX_CFLAGS}
-DSANITIZER_COMMON_NO_REDEFINE_BUILTINS)
set(RTSAN_LINK_FLAGS ${COMPILER_RT_COMMON_LINK_FLAGS})
set(RTSAN_LINK_LIBS
${COMPILER_RT_UNWINDER_LINK_LIBS}
${COMPILER_RT_CXX_LINK_LIBS})

if(APPLE)
add_compiler_rt_object_libraries(RTRtsan
OS ${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${RTSAN_SUPPORTED_ARCH}
SOURCES ${RTSAN_CXX_SOURCES}
ADDITIONAL_HEADERS ${RTSAN_HEADERS}
CFLAGS ${RTSAN_CFLAGS}
DEPS ${RTSAN_DEPS})
else()
add_compiler_rt_object_libraries(RTRtsan
ARCHS ${RTSAN_SUPPORTED_ARCH}
SOURCES ${RTSAN_CXX_SOURCES}
ADDITIONAL_HEADERS ${RTSAN_HEADERS}
CFLAGS ${RTSAN_CFLAGS}
DEPS ${RTSAN_DEPS})
add_compiler_rt_object_libraries(RTRtsan_preinit
ARCHS ${RTSAN_SUPPORTED_ARCH}
SOURCES ${RTSAN_PREINIT_SOURCES}
ADDITIONAL_HEADERS ${RTSAN_HEADERS}
CFLAGS ${RTSAN_CFLAGS})
endif()

set(RTSAN_COMMON_RUNTIME_OBJECT_LIBS
RTInterception
RTSanitizerCommon
RTSanitizerCommonLibc
RTSanitizerCommonCoverage
RTSanitizerCommonSymbolizer)

append_list_if(COMPILER_RT_HAS_LIBDL dl RTSAN_LINK_LIBS)
append_list_if(COMPILER_RT_HAS_LIBRT rt RTSAN_LINK_LIBS)
append_list_if(COMPILER_RT_HAS_LIBM m RTSAN_LINK_LIBS)
append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread RTSAN_LINK_LIBS)
append_list_if(COMPILER_RT_HAS_LIBLOG log RTSAN_LINK_LIBS)

add_compiler_rt_component(rtsan)

if (APPLE)
add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
set(RTSAN_LINK_FLAGS ${RTSAN_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS})

add_compiler_rt_runtime(clang_rt.rtsan
SHARED
OS ${SANITIZER_COMMON_SUPPORTED_OS}
ARCHS ${RTSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTRtsan
${RTSAN_COMMON_RUNTIME_OBJECT_LIBS}
LINK_FLAGS ${RTSAN_LINK_FLAGS}
LINK_LIBS ${RTSAN_LINK_LIBS}
PARENT_TARGET rtsan)
else()
add_compiler_rt_runtime(clang_rt.rtsan
STATIC
ARCHS ${RTSAN_SUPPORTED_ARCH}
OBJECT_LIBS RTRtsan_preinit
RTRtsan
${RTSAN_COMMON_RUNTIME_OBJECT_LIBS}
LINK_FLAGS ${RTSAN_LINK_FLAGS}
CFLAGS ${RTSAN_CFLAGS}
PARENT_TARGET rtsan)
endif()

if(COMPILER_RT_INCLUDE_TESTS)
add_subdirectory(tests)
endif()
37 changes: 37 additions & 0 deletions compiler-rt/lib/rtsan/rtsan.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//===--- rtsan.cpp - Realtime Sanitizer -------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//

#include <rtsan/rtsan.h>
#include <rtsan/rtsan_context.h>
#include <rtsan/rtsan_interceptors.h>

extern "C" {

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init() {
__rtsan::InitializeInterceptors();
}

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter() {
__rtsan::GetContextForThisThread().RealtimePush();
}

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit() {
__rtsan::GetContextForThisThread().RealtimePop();
}

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_off() {
__rtsan::GetContextForThisThread().BypassPush();
}

SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_on() {
__rtsan::GetContextForThisThread().BypassPop();
}

} // extern "C"
40 changes: 40 additions & 0 deletions compiler-rt/lib/rtsan/rtsan.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===--- rtsan.h - Realtime Sanitizer ---------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//

#pragma once

#include "sanitizer_common/sanitizer_internal_defs.h"

extern "C" {

// Initialise rtsan interceptors.
// A call to this method is added to the preinit array on Linux systems.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_init();

// Enter real-time context.
// When in a real-time context, RTSan interceptors will error if realtime
// violations are detected. Calls to this method are injected at the code
// generation stage when RTSan is enabled.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_enter();

// Exit the real-time context.
// When not in a real-time context, RTSan interceptors will simply forward
// intercepted method calls to the real methods.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_realtime_exit();

// Disable all RTSan error reporting.
// Injected into the code if "nosanitize(realtime)" is on a function.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_off();

// Re-enable all RTSan error reporting.
// The counterpart to `__rtsan_off`.
SANITIZER_INTERFACE_ATTRIBUTE void __rtsan_on();

} // extern "C"
97 changes: 97 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//===--- rtsan_context.cpp - Realtime Sanitizer -----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//

#include <rtsan/rtsan_context.h>

#include <rtsan/rtsan_stack.h>

#include <sanitizer_common/sanitizer_allocator_internal.h>
#include <sanitizer_common/sanitizer_stacktrace.h>

#include <new>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

static pthread_key_t context_key;
static pthread_once_t key_once = PTHREAD_ONCE_INIT;

static void internalFree(void *ptr) { __sanitizer::InternalFree(ptr); }
cjappl marked this conversation as resolved.
Show resolved Hide resolved

static __rtsan::Context &GetContextForThisThreadImpl() {
auto make_thread_local_context_key = []() {
CHECK_EQ(pthread_key_create(&context_key, internalFree), 0);
};

pthread_once(&key_once, make_thread_local_context_key);
__rtsan::Context *current_thread_context =
static_cast<__rtsan::Context *>(pthread_getspecific(context_key));
if (current_thread_context == nullptr) {
current_thread_context = static_cast<__rtsan::Context *>(
__sanitizer::InternalAlloc(sizeof(__rtsan::Context)));
new (current_thread_context) __rtsan::Context();
pthread_setspecific(context_key, current_thread_context);
}

return *current_thread_context;
}

/*
This is a placeholder stub for a future feature that will allow
a user to configure RTSan's behaviour when a real-time safety
violation is detected. The RTSan developers intend for the
following choices to be made available, via a RTSAN_OPTIONS
environment variable, in a future PR:

i) exit,
ii) continue, or
iii) wait for user input from stdin.

Until then, and to keep the first PRs small, only the exit mode
is available.
*/
static void InvokeViolationDetectedAction() { exit(EXIT_FAILURE); }

namespace __rtsan {
cjappl marked this conversation as resolved.
Show resolved Hide resolved

Context::Context() = default;

void Context::RealtimePush() { realtime_depth++; }

void Context::RealtimePop() { realtime_depth--; }

void Context::BypassPush() { bypass_depth++; }

void Context::BypassPop() { bypass_depth--; }

void Context::ExpectNotRealtime(const char *intercepted_function_name) {
if (InRealtimeContext() && !IsBypassed()) {
BypassPush();
PrintDiagnostics(intercepted_function_name);
InvokeViolationDetectedAction();
BypassPop();
}
}

bool Context::InRealtimeContext() const { return realtime_depth > 0; }

bool Context::IsBypassed() const { return bypass_depth > 0; }

void Context::PrintDiagnostics(const char *intercepted_function_name) {
fprintf(stderr,
"Real-time violation: intercepted call to real-time unsafe function "
"`%s` in real-time context! Stack trace:\n",
intercepted_function_name);
__rtsan::PrintStackTrace();
}

Context &GetContextForThisThread() { return GetContextForThisThreadImpl(); }

} // namespace __rtsan
38 changes: 38 additions & 0 deletions compiler-rt/lib/rtsan/rtsan_context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===--- rtsan_context.h - Realtime Sanitizer -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//

#pragma once

namespace __rtsan {

class Context {
public:
Context();

void RealtimePush();
void RealtimePop();

void BypassPush();
void BypassPop();

void ExpectNotRealtime(const char *intercepted_function_name);

private:
bool InRealtimeContext() const;
bool IsBypassed() const;
void PrintDiagnostics(const char *intercepted_function_name);

int realtime_depth{0};
int bypass_depth{0};
};

Context &GetContextForThisThread();

} // namespace __rtsan
Loading