[clang] [clang][rtsan] Reland realtime sanitizer codegen and driver (#102622) (PR #105841)
Chris Apple via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 23 08:16:44 PDT 2024
https://github.com/cjappl created https://github.com/llvm/llvm-project/pull/105841
This reverts commit a1e9b7e646b76bf844e8a9a101ebd27de11992ff
This relands commit d010ec6af8162a8ae4e42d2cac5282f83db0ce07
No modifications from the original patch. It was determined that the ubsan build failure was happening even after the revert, some examples:
https://lab.llvm.org/buildbot/#/builders/159/builds/4477
https://lab.llvm.org/buildbot/#/builders/159/builds/4478
https://lab.llvm.org/buildbot/#/builders/159/builds/4479
>From 3b78b5725a0d54274c0e6ea0a623c8bc586df745 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Thu, 22 Aug 2024 20:38:14 -0700
Subject: [PATCH] Reland "[clang][rtsan] Introduce realtime sanitizer codegen
and driver (#105744)
Review in #102622
This reverts commit a1e9b7e646b76bf844e8a9a101ebd27de11992ff.
It was determined that the ubsan build failure was happening even after the
revert, some examples:
https://lab.llvm.org/buildbot/#/builders/159/builds/4477
https://lab.llvm.org/buildbot/#/builders/159/builds/4478
https://lab.llvm.org/buildbot/#/builders/159/builds/4479
---
clang/docs/RealtimeSanitizer.rst | 85 +++++++++++++++++++
clang/docs/ReleaseNotes.rst | 5 ++
clang/docs/UsersManual.rst | 2 +
clang/docs/index.rst | 1 +
clang/include/clang/Basic/Sanitizers.def | 3 +
clang/include/clang/Driver/SanitizerArgs.h | 1 +
clang/lib/CodeGen/BackendUtil.cpp | 8 ++
clang/lib/CodeGen/CodeGenFunction.cpp | 7 ++
clang/lib/Driver/SanitizerArgs.cpp | 14 +--
clang/lib/Driver/ToolChains/CommonArgs.cpp | 6 ++
clang/lib/Driver/ToolChains/Darwin.cpp | 8 ++
clang/lib/Driver/ToolChains/Linux.cpp | 1 +
clang/test/CodeGen/rtsan_attribute_inserted.c | 7 ++
.../test/CodeGen/rtsan_entry_exit_insertion.c | 13 +++
.../rtsan_no_attribute_sanitizer_disabled.c | 6 ++
clang/test/Driver/fsanitize.c | 46 ++++++++++
16 files changed, 208 insertions(+), 5 deletions(-)
create mode 100644 clang/docs/RealtimeSanitizer.rst
create mode 100644 clang/test/CodeGen/rtsan_attribute_inserted.c
create mode 100644 clang/test/CodeGen/rtsan_entry_exit_insertion.c
create mode 100644 clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c
diff --git a/clang/docs/RealtimeSanitizer.rst b/clang/docs/RealtimeSanitizer.rst
new file mode 100644
index 00000000000000..799cd43509c6e6
--- /dev/null
+++ b/clang/docs/RealtimeSanitizer.rst
@@ -0,0 +1,85 @@
+=================
+RealtimeSanitizer
+=================
+
+.. contents::
+ :local:
+
+Introduction
+============
+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 considers any function marked with the ``[[clang::nonblocking]]`` attribute
+to be a real-time function. If RTSan detects a call to ``malloc``, ``free``,
+``pthread_mutex_lock``, or anything else that could have a non-deterministic
+execution time in a function marked ``[[clang::nonblocking]]``
+RTSan raises an error.
+
+The runtime slowdown introduced by RealtimeSanitizer is negligible.
+
+How to build
+============
+
+Build LLVM/Clang with `CMake <https://llvm.org/docs/CMake.html>` and enable the
+``compiler-rt`` runtime. An example CMake configuration that will allow for the
+use/testing of RealtimeSanitizer:
+
+.. code-block:: console
+
+ $ cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="compiler-rt" <path to source>/llvm
+
+Usage
+=====
+
+There are two requirements:
+
+1. The code must be compiled with the ``-fsanitize=realtime`` flag.
+2. Functions that are subject to real-time constraints must be marked
+ with the ``[[clang::nonblocking]]`` attribute.
+
+Typically, these attributes should be added onto the functions that are entry
+points for threads with real-time priority. These threads are subject to a fixed
+callback time, such as audio callback threads or rendering loops in video game
+code.
+
+.. code-block:: console
+
+ % cat example_realtime_violation.cpp
+ #include <vector>
+
+ void violation() [[clang::nonblocking]]{
+ std::vector<float> v;
+ v.resize(100);
+ }
+
+ int main() {
+ violation();
+ return 0;
+ }
+ # Compile and link
+ % clang++ -fsanitize=realtime -g example_realtime_violation.cpp
+
+If a real-time safety violation is detected in a ``[[clang::nonblocking]]``
+context, or any function invoked by that function, the program will exit with a
+non-zero exit code.
+
+.. code-block:: console
+
+ % clang++ -fsanitize=realtime -g example_realtime_violation.cpp
+ % ./a.out
+ Real-time violation: intercepted call to real-time unsafe function `malloc` in real-time context! Stack trace:
+ #0 0x000102893034 in __rtsan::PrintStackTrace() rtsan_stack.cpp:45
+ #1 0x000102892e64 in __rtsan::Context::ExpectNotRealtime(char const*) rtsan_context.cpp:78
+ #2 0x00010289397c in malloc rtsan_interceptors.cpp:286
+ #3 0x000195bd7bd0 in operator new(unsigned long)+0x1c (libc++abi.dylib:arm64+0x16bd0)
+ #4 0x5c7f00010230f07c (<unknown module>)
+ #5 0x00010230f058 in std::__1::__libcpp_allocate[abi:ue170006](unsigned long, unsigned long) new:324
+ #6 0x00010230effc in std::__1::allocator<float>::allocate[abi:ue170006](unsigned long) allocator.h:114
+ ... snip ...
+ #10 0x00010230e4bc in std::__1::vector<float, std::__1::allocator<float>>::__append(unsigned long) vector:1162
+ #11 0x00010230dcdc in std::__1::vector<float, std::__1::allocator<float>>::resize(unsigned long) vector:1981
+ #12 0x00010230dc28 in violation() main.cpp:5
+ #13 0x00010230dd64 in main main.cpp:9
+ #14 0x0001958960dc (<unknown module>)
+ #15 0x2f557ffffffffffc (<unknown module>)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 93040c2eee2c0b..9b9f0792adce49 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -446,6 +446,11 @@ Moved checkers
Sanitizers
----------
+- Introduced Realtime Sanitizer, activated by using the -fsanitize=realtime
+ flag. This sanitizer detects unsafe system library calls, such as memory
+ allocations and mutex locks. If any such function is called during invocation
+ of a function marked with the ``[[clang::nonblocking]]`` attribute, an error
+ is printed to the console and the process exits non-zero.
- Added the ``-fsanitize-undefined-ignore-overflow-pattern`` flag which can be
used to disable specific overflow-dependent code patterns. The supported
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index d19b77ae40b0d7..069ecba875cd59 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2068,6 +2068,8 @@ are listed below.
integrity.
- ``-fsanitize=safe-stack``: :doc:`safe stack <SafeStack>`
protection against stack-based memory corruption errors.
+ - ``-fsanitize=realtime``: :doc:`RealtimeSanitizer`,
+ a real-time safety checker.
There are more fine-grained checks available: see
the :ref:`list <ubsan-checks>` of specific kinds of
diff --git a/clang/docs/index.rst b/clang/docs/index.rst
index 9bae0bd83243bd..4a497f4d9bcc3c 100644
--- a/clang/docs/index.rst
+++ b/clang/docs/index.rst
@@ -32,6 +32,7 @@ Using Clang as a Compiler
UndefinedBehaviorSanitizer
DataFlowSanitizer
LeakSanitizer
+ RealtimeSanitizer
SanitizerCoverage
SanitizerStats
SanitizerSpecialCaseList
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index bee35e9dca7c39..9223f62b3639a7 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -79,6 +79,9 @@ SANITIZER("thread", Thread)
// Numerical stability sanitizer.
SANITIZER("numerical", NumericalStability)
+// RealtimeSanitizer
+SANITIZER("realtime", Realtime)
+
// LeakSanitizer
SANITIZER("leak", Leak)
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index e64ec463ca8907..0c6f3869549ef7 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -107,6 +107,7 @@ class SanitizerArgs {
bool needsNsanRt() const {
return Sanitizers.has(SanitizerKind::NumericalStability);
}
+ bool needsRtsanRt() const { return Sanitizers.has(SanitizerKind::Realtime); }
bool hasMemTag() const {
return hasMemtagHeap() || hasMemtagStack() || hasMemtagGlobals();
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index fdd89edd72e109..026f16484c0949 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -78,6 +78,7 @@
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
#include "llvm/Transforms/Instrumentation/NumericalStabilitySanitizer.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
+#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@@ -990,6 +991,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
FPM.addPass(BoundsCheckingPass());
});
+ if (LangOpts.Sanitize.has(SanitizerKind::Realtime))
+ PB.registerScalarOptimizerLateEPCallback(
+ [](FunctionPassManager &FPM, OptimizationLevel Level) {
+ RealtimeSanitizerOptions Opts;
+ FPM.addPass(RealtimeSanitizerPass(Opts));
+ });
+
// Don't add sanitizers if we are here from ThinLTO PostLink. That already
// done on PreLink stage.
if (!IsThinLTOPostLink) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index eff8c9f5694084..c89eaa0f4e3bfc 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -845,6 +845,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (SanOpts.has(SanitizerKind::ShadowCallStack))
Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
+ if (SanOpts.has(SanitizerKind::Realtime))
+ if (FD && FD->getASTContext().hasAnyFunctionEffects())
+ for (const FunctionEffectWithCondition &Fe : FD->getFunctionEffects()) {
+ if (Fe.Effect.kind() == FunctionEffect::Kind::NonBlocking)
+ Fn->addFnAttr(llvm::Attribute::SanitizeRealtime);
+ }
+
// Apply fuzzing attribute to the function.
if (SanOpts.hasOneOf(SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink))
Fn->addFnAttr(llvm::Attribute::OptForFuzzing);
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 9d9ad79d51d7f8..09262f40b5b50c 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -558,11 +558,15 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SanitizerKind::Leak | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::KernelAddress |
SanitizerKind::Scudo | SanitizerKind::SafeStack),
- std::make_pair(SanitizerKind::MemTag,
- SanitizerKind::Address | SanitizerKind::KernelAddress |
- SanitizerKind::HWAddress |
- SanitizerKind::KernelHWAddress),
- std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function)};
+ std::make_pair(SanitizerKind::MemTag, SanitizerKind::Address |
+ SanitizerKind::KernelAddress |
+ SanitizerKind::HWAddress |
+ SanitizerKind::KernelHWAddress),
+ std::make_pair(SanitizerKind::KCFI, SanitizerKind::Function),
+ std::make_pair(SanitizerKind::Realtime,
+ SanitizerKind::Address | SanitizerKind::Thread |
+ SanitizerKind::Undefined | SanitizerKind::Memory)};
+
// Enable toolchain specific default sanitizers if not explicitly disabled.
SanitizerMask Default = TC.getDefaultSanitizers() & ~AllRemove;
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 0738ed18f54078..0601016c3b14b8 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1456,6 +1456,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (!Args.hasArg(options::OPT_shared))
HelperStaticRuntimes.push_back("hwasan-preinit");
}
+ if (SanArgs.needsRtsanRt() && SanArgs.linkRuntimes())
+ SharedRuntimes.push_back("rtsan");
}
// The stats_client library is also statically linked into DSOs.
@@ -1481,6 +1483,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("asan_cxx");
}
+ if (!SanArgs.needsSharedRt() && SanArgs.needsRtsanRt() &&
+ SanArgs.linkRuntimes())
+ StaticRuntimes.push_back("rtsan");
+
if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) {
StaticRuntimes.push_back("memprof");
if (SanArgs.linkCXXRuntimes())
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 2550541a438481..5e7f9290e2009d 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -1519,6 +1519,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
const char *sanitizer = nullptr;
if (Sanitize.needsUbsanRt()) {
sanitizer = "UndefinedBehaviorSanitizer";
+ } else if (Sanitize.needsRtsanRt()) {
+ sanitizer = "RealtimeSanitizer";
} else if (Sanitize.needsAsanRt()) {
sanitizer = "AddressSanitizer";
} else if (Sanitize.needsTsanRt()) {
@@ -1541,6 +1543,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
}
}
+ if (Sanitize.needsRtsanRt()) {
+ assert(Sanitize.needsSharedRt() &&
+ "Static sanitizer runtimes not supported");
+ AddLinkSanitizerLibArgs(Args, CmdArgs, "rtsan");
+ }
if (Sanitize.needsLsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
if (Sanitize.needsUbsanRt()) {
@@ -3539,6 +3546,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
+ Res |= SanitizerKind::Realtime;
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 2265138edbffbe..96680b3412a2db 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -800,6 +800,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
+ Res |= SanitizerKind::Realtime;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
Res |= SanitizerKind::KernelAddress;
diff --git a/clang/test/CodeGen/rtsan_attribute_inserted.c b/clang/test/CodeGen/rtsan_attribute_inserted.c
new file mode 100644
index 00000000000000..05a1d9a8c2047a
--- /dev/null
+++ b/clang/test/CodeGen/rtsan_attribute_inserted.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=realtime %s -emit-llvm -o - %s | FileCheck %s
+
+float process(float *a) [[clang::nonblocking]] { return *a; }
+
+// CHECK-LABEL: @process{{.*}}#0 {
+// CHECK: attributes #0 = {
+// CHECK-SAME: {{.*sanitize_realtime.*}}
diff --git a/clang/test/CodeGen/rtsan_entry_exit_insertion.c b/clang/test/CodeGen/rtsan_entry_exit_insertion.c
new file mode 100644
index 00000000000000..9ba0103ca1e353
--- /dev/null
+++ b/clang/test/CodeGen/rtsan_entry_exit_insertion.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -fsanitize=realtime -emit-llvm -o - %s | FileCheck %s
+
+int foo(int *a) [[clang::nonblocking]] { return *a; }
+
+// The first instruction after the function is entred should be a call to
+// enable the realtime sanitizer stack.
+// CHECK-LABEL: define{{.*}}@foo
+// CHECK-NEXT: entry:
+// CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
+
+// __rtsan_realtime_exit should be inserted at all function returns.
+// CHECK-LABEL: call{{.*}}__rtsan_realtime_exit
+// CHECK-NEXT: ret
diff --git a/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c b/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c
new file mode 100644
index 00000000000000..43ad6ed1a429ee
--- /dev/null
+++ b/clang/test/CodeGen/rtsan_no_attribute_sanitizer_disabled.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+float process(float *a) [[clang::nonblocking]] { return *a; }
+
+// Without the -fsanitize=realtime flag, we shouldn't attach the attribute.
+// CHECK-NOT: {{.*sanitize_realtime.*}}
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index 678fa432fb0a0a..f86c978f221cd4 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -1040,3 +1040,49 @@
// RUN: not %clang --target=aarch64-none-elf -fsanitize=dataflow %s -### 2>&1 | FileCheck %s -check-prefix=UNSUPPORTED-BAREMETAL
// RUN: not %clang --target=arm-arm-none-eabi -fsanitize=shadow-call-stack %s -### 2>&1 | FileCheck %s -check-prefix=UNSUPPORTED-BAREMETAL
// UNSUPPORTED-BAREMETAL: unsupported option '-fsanitize={{.*}}' for target
+
+// RUN: %clang --target=x86_64-apple-darwin -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-DARWIN
+// CHECK-RTSAN-X86-64-DARWIN-NOT: unsupported option
+
+// RUN: %clang --target=x86_64-apple-darwin -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-DARWIN
+// CHECK-RTSAN-X86-64-DARWIN-NOT: unsupported option
+// RUN: %clang --target=x86_64-apple-macos -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-MACOS
+// CHECK-RTSAN-X86-64-MACOS-NOT: unsupported option
+// RUN: %clang --target=arm64-apple-macos -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-MACOS
+// CHECK-RTSAN-ARM64-MACOS-NOT: unsupported option
+
+// RUN: %clang --target=arm64-apple-ios-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-IOSSIMULATOR
+// CHECK-RTSAN-ARM64-IOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang --target=arm64-apple-watchos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-WATCHOSSIMULATOR
+// CHECK-RTSAN-ARM64-WATCHOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang --target=arm64-apple-tvos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-ARM64-TVOSSIMULATOR
+// CHECK-RTSAN-ARM64-TVOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang --target=x86_64-apple-ios-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-IOSSIMULATOR
+// CHECK-RTSAN-X86-64-IOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang --target=x86_64-apple-watchos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-WATCHOSSIMULATOR
+// CHECK-RTSAN-X86-64-WATCHOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang --target=x86_64-apple-tvos-simulator -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-TVOSSIMULATOR
+// CHECK-RTSAN-X86-64-TVOSSIMULATOR-NOT: unsupported option
+
+// RUN: %clang --target=x86_64-linux-gnu -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-X86-64-LINUX
+// CHECK-RTSAN-X86-64-LINUX-NOT: unsupported option
+
+// RUN: not %clang --target=i386-pc-openbsd -fsanitize=realtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RTSAN-OPENBSD
+// CHECK-RTSAN-OPENBSD: unsupported option '-fsanitize=realtime' for target 'i386-pc-openbsd'
+
+// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-TSAN
+// CHECK-REALTIME-TSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=thread'
+
+// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-ASAN
+// CHECK-REALTIME-ASAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=address'
+
+// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-MSAN
+// CHECK-REALTIME-MSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=memory'
+
+// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=realtime,undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-REALTIME-UBSAN
+// CHECK-REALTIME-UBSAN: error: invalid argument '-fsanitize=realtime' not allowed with '-fsanitize=undefined'
More information about the cfe-commits
mailing list