Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -3527,6 +3527,11 @@ def NoSanitize : InheritableAttr {
bool hasCoverage() const {
return llvm::is_contained(sanitizers(), "coverage");
}

bool hasRealtime() const {
return llvm::is_contained(sanitizers(), "realtime");
}

}];
}

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Sanitizers.def
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
#endif


// RealtimeSanitizer
SANITIZER("realtime", Realtime)

// AddressSanitizer
SANITIZER("address", Address)

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/SanitizerArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class SanitizerArgs {
bool needsStableAbi() const { return StableABI; }

bool needsMemProfRt() const { return NeedsMemProfRt; }
bool needsRtsanRt() const { return Sanitizers.has(SanitizerKind::Realtime); }
bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
bool needsHwasanRt() const {
return Sanitizers.has(SanitizerKind::HWAddress);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2408,6 +2408,12 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
NBA = Fn->getAttr<NoBuiltinAttr>();
}

for (const FunctionEffectWithCondition &Fe : Fn->getFunctionEffects()) {
if (Fe.Effect.kind() == FunctionEffect::Kind::NonBlocking) {
FuncAttrs.addAttribute(llvm::Attribute::NonBlocking);
}
}
}

if (isa<FunctionDecl>(TargetDecl) || isa<VarDecl>(TargetDecl)) {
Expand Down
43 changes: 43 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
Expand All @@ -40,6 +41,9 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/FPEnv.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
Expand Down Expand Up @@ -1410,6 +1414,35 @@ QualType CodeGenFunction::BuildFunctionArgList(GlobalDecl GD,
return ResTy;
}

void InsertCallBeforeInstruction(llvm::Function *Fn,
llvm::Instruction &Instruction,
const char *FunctionName) {
llvm::LLVMContext &context = Fn->getContext();
llvm::FunctionType *FuncType =
llvm::FunctionType::get(llvm::Type::getVoidTy(context), false);
llvm::FunctionCallee Func =
Fn->getParent()->getOrInsertFunction(FunctionName, FuncType);
llvm::IRBuilder<> builder{&Instruction};
builder.CreateCall(Func, {});
}

void InsertCallAtFunctionEntryPoint(llvm::Function *Fn,
const char *InsertFnName) {

InsertCallBeforeInstruction(Fn, Fn->front().front(), InsertFnName);
}

void InsertCallAtAllFunctionExitPoints(llvm::Function *Fn,
const char *InsertFnName) {
for (auto &BB : *Fn) {
for (auto &I : BB) {
if (auto *RI = dyn_cast<llvm::ReturnInst>(&I)) {
InsertCallBeforeInstruction(Fn, I, InsertFnName);
}
}
}
}

void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo) {
assert(Fn && "generating code for null Function");
Expand Down Expand Up @@ -1578,9 +1611,19 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
}
}

if (SanOpts.has(SanitizerKind::Realtime)) {
if (Fn->hasFnAttribute(llvm::Attribute::NonBlocking))
InsertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter");
}

// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());

if (SanOpts.has(SanitizerKind::Realtime)) {
if (Fn->hasFnAttribute(llvm::Attribute::NonBlocking))
InsertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit");
}

// If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can.
if (!CurFn->doesNotThrow())
Expand Down
14 changes: 9 additions & 5 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,11 +552,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;

Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,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.
Expand All @@ -1455,6 +1457,11 @@ 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())
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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()) {
Expand Down Expand Up @@ -3477,6 +3484,7 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
Res |= SanitizerKind::Realtime;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Leak;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
Res |= SanitizerKind::Realtime;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Fuzzer;
Expand Down
48 changes: 48 additions & 0 deletions clang/test/Driver/fsanitize.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,3 +1038,51 @@
// 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'


12 changes: 12 additions & 0 deletions clang/test/Driver/rtsan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
// RUN: %clang -O1 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
// RUN: %clang -O3 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto=thin -o - | FileCheck %s
// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto=thin -o - | FileCheck %s
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto -o - | FileCheck %s
// RUN: %clang -O2 -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -flto -o - | FileCheck %s

int foo(int *a) [[clang::nonblocking]] { return *a; }
// CHECK: __rtsan_realtime_enter

Choose a reason for hiding this comment

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

Does this just check for the presence of these two lines? Is there any way we could make this test a bit tighter, and really check the required behaviour of:

  1. __rtsan_realtime_enter is the first instruction at the entry point, and
  2. __rtsan_realtime_exit is final instruction before all exit points

I'm not sure this is possible because I'm really unfamiliar with the lit system. What do you think? Would this test bring good value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good question. So for both of our references, the output of such a command looks like this:

/Users/topher/code/radsan_cjappl/llvm-project/build/bin/clang-19 -target x86_64-unknown-linux -fsanitize=realtime rtsan.c -S -emit-llvm -o - 

; ModuleID = 'rtsan.c'
source_filename = "rtsan.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux"

; Function Attrs: noinline nounwind nonblocking optnone uwtable
define dso_local i32 @foo(ptr noundef %0) #0 {
  call void @__rtsan_realtime_enter()
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8
  %3 = load ptr, ptr %2, align 8
  %4 = load i32, ptr %3, align 4
  call void @__rtsan_realtime_exit()
  ret i32 %4
}

declare void @__rtsan_realtime_enter()

declare void @__rtsan_realtime_exit()

attributes #0 = { noinline nounwind nonblocking optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"clang version 19.0.0git (https://github.com/cjappl/llvm-project a247682ba7507b4a2babafe8b637ffc217bad9c6)"}

I worry that looking any more deeply into this representation may become brittle over time.

Basically, if we check for the following relative ordering:
define.foo
call.
__rtsan_realtime_enter
call.*__rtsan_realtime_exit
ret

Is that overly confining? How often does the function representation change? Or the order shuffle? I don't know the answers to this question.

As inspiration, I took from tsan.c, which looks very similar:

int foo(int *a) { return *a; }
// CHECK: __tsan_init

and asan:

int foo(int *a) { return *a; }
// CHECK-ASAN: __asan_init
// CHECK-KASAN: __asan_{{.*}}load4_noabort
// CHECK-HWASAN: __hwasan_init
// CHECK-KHWASAN: __hwasan_tls

Both of which just check for presence of the initialization code.

As an additional wrinkle, I'm not sure if the lit system allows for relative checks/positional checks. We could possibly do it in some kind of more complex regex if we wanted to

// CHECK: __rtsan_realtime_exit
4 changes: 3 additions & 1 deletion compiler-rt/lib/rtsan/rtsan_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

using namespace __sanitizer;

using __rtsan::rtsan_init_is_running;
using __rtsan::rtsan_initialized;

namespace {
Expand All @@ -49,6 +48,9 @@ struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
} // namespace

void ExpectNotRealtime(const char *intercepted_function_name) {
if (!rtsan_initialized)
__rtsan_init();

__rtsan::GetContextForThisThread().ExpectNotRealtime(
intercepted_function_name);
}
Expand Down
15 changes: 7 additions & 8 deletions compiler-rt/lib/rtsan/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,13 @@ endif()
foreach(arch ${RTSAN_TEST_ARCH})
set(RtsanTestObjects)

# TODO: Re-enable once -fsanitize=realtime exists in clang driver
#generate_compiler_rt_tests(RtsanTestObjects
# RtsanUnitTests "Rtsan-${arch}-Test" ${arch}
# COMPILE_DEPS ${RTSAN_UNITTEST_HEADERS}
# SOURCES ${RTSAN_INST_TEST_SOURCES} ${COMPILER_RT_GOOGLETEST_SOURCES}
# DEPS rtsan
# CFLAGS ${RTSAN_UNITTEST_CFLAGS} -fsanitize=realtime
# LINK_FLAGS ${RTSAN_UNITTEST_LINK_FLAGS} -fsanitize=realtime)
generate_compiler_rt_tests(RtsanTestObjects
RtsanUnitTests "Rtsan-${arch}-Test" ${arch}
COMPILE_DEPS ${RTSAN_UNITTEST_HEADERS}
SOURCES ${RTSAN_INST_TEST_SOURCES} ${COMPILER_RT_GOOGLETEST_SOURCES}
DEPS rtsan
CFLAGS ${RTSAN_UNITTEST_CFLAGS} -fsanitize=realtime
LINK_FLAGS ${RTSAN_UNITTEST_LINK_FLAGS} -fsanitize=realtime)

set(RTSAN_TEST_RUNTIME RTRtsanTest.${arch})
if(APPLE)
Expand Down
11 changes: 0 additions & 11 deletions compiler-rt/test/rtsan/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@




######
# TODO: Full lit tests coming in a future review when we introduce the codegen
######




set(RTSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})

set(RTSAN_TESTSUITES)
Expand Down
17 changes: 17 additions & 0 deletions compiler-rt/test/rtsan/test_rtsan.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %clangxx -fsanitize=realtime %s -o %t
// RUN: not %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: ios

// Intent: Ensure that an intercepted call in a [[clang::nonblocking]] function
// is flagged as an error. Basic smoke test.

#include <stdlib.h>

void violation() [[clang::nonblocking]] { void *Ptr = malloc(2); }

int main() {
violation();
return 0;
// CHECK: {{.*Real-time violation.*}}
// CHECK: {{.*malloc*}}
}
23 changes: 23 additions & 0 deletions compiler-rt/test/rtsan/test_rtsan_inactive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// RUN: %clangxx %s -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: ios

// Intent: Ensure [[clang::nonblocking]] has no impact if -fsanitize=realtime is not used

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

// In this test, we don't use the -fsanitize=realtime flag, so nothing
// should happen here
void violation() [[clang::nonblocking]] { void *Ptr = malloc(2); }

int main() {
printf("Starting run\n");
violation();
printf("No violations ended the program\n");
return 0;
// CHECK: {{.*Starting run.*}}
// CHECK NOT: {{.*Real-time violation.*}}
// CHECK NOT: {{.*malloc*}}
// CHECK: {{.*No violations ended the program.*}}
}
2 changes: 1 addition & 1 deletion compiler-rt/test/sanitizer_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set(SANITIZER_COMMON_TESTSUITES)
# FIXME(dliew): We should switch to COMPILER_RT_SANITIZERS_TO_BUILD instead of
# the hard coded `SUPPORTED_TOOLS_INIT` list once we know that the other
# sanitizers work.
set(SUPPORTED_TOOLS_INIT asan lsan hwasan msan tsan ubsan)
set(SUPPORTED_TOOLS_INIT asan lsan hwasan msan rtsan tsan ubsan)
set(SUPPORTED_TOOLS)
foreach(SANITIZER_TOOL ${SUPPORTED_TOOLS_INIT})
string(TOUPPER ${SANITIZER_TOOL} SANITIZER_TOOL_UPPER)
Expand Down
3 changes: 3 additions & 0 deletions compiler-rt/test/sanitizer_common/lit.common.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
tool_options = "HWASAN_OPTIONS"
if not config.has_lld:
config.unsupported = True
elif config.tool_name == "rtsan":
tool_cflags = ["-fsanitize=realtime"]
tool_options = "RTSAN_OPTIONS"
elif config.tool_name == "tsan":
tool_cflags = ["-fsanitize=thread"]
tool_options = "TSAN_OPTIONS"
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ enum AttributeKindCodes {
ATTR_KIND_SANITIZE_NUMERICAL_STABILITY = 93,
ATTR_KIND_INITIALIZES = 94,
ATTR_KIND_HYBRID_PATCHABLE = 95,
ATTR_KIND_NONBLOCKING = 96,
};

enum ComdatSelectionKindCodes {
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ def ReadNone : EnumAttr<"readnone", [ParamAttr]>;
/// Function only reads from memory.
def ReadOnly : EnumAttr<"readonly", [ParamAttr]>;

/// Function is marked to be non-blocking
def NonBlocking : EnumAttr<"nonblocking", [FnAttr]>;

/// Return value is always equal to this argument.
def Returned : EnumAttr<"returned", [ParamAttr]>;

Expand Down
Loading