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
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
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -995,6 +996,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
FPM.addPass(BoundsCheckingPass());
});

if (LangOpts.Sanitize.has(SanitizerKind::Realtime)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Now that we have the llvm work done (in the earlier commit), we now check if the sanitizer is enabled, and insert this "Pass" that we defined in LLVM.

As for where it should live registerScalarOptimizerLateEPCallback was my guess, as it says it is "very late in the pipeline" but we likely have to ask reviewers what is appropriate

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) {
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 @@ -2411,6 +2411,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
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 @@ -1408,6 +1408,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 @@ -1433,6 +1435,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 @@ -3506,6 +3513,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
9 changes: 9 additions & 0 deletions clang/test/CodeGen/rtsan_insert_at_entry.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=realtime -emit-llvm -o - %s | FileCheck %s

// The first instruction after the function is entred should be a call to
// enable the realtime sanitizer stack

int foo(int *a) [[clang::nonblocking]] { return *a; }
// CHECK: define{{.*}}foo
// CHECK-NEXT: entry:
// CHECK-NEXT: call{{.*}}__rtsan_realtime_enter
9 changes: 9 additions & 0 deletions clang/test/CodeGen/rtsan_insert_at_exit.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=realtime -emit-llvm -o - %s | FileCheck %s

// __rtsan_realtime_exit should be inserted at all function returns

int bar(int* x) [[clang::nonblocking]] {
return *x;
}
// CHECK: call{{.*}}__rtsan_realtime_exit
// CHECK-NEXT: ret
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was not able to figure out how to induce a multiple return statement in clang-IR. I may have to try to run a much more complex file through it.

That would be an additional test, but this one is good to start us out.

7 changes: 7 additions & 0 deletions clang/test/CodeGen/rtsan_nonblocking_attribute_inserted.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// RUN: %clang -target x86_64-unknown-linux -fsanitize=realtime %s -S -emit-llvm -o - | FileCheck %s

float process(float *a) [[clang::nonblocking]] { return *a; }

// CHECK: define{{.*}}process{{.*}}#0 {
// CHECK: attributes #0 = {
// CHECK-SAME: {{.*nonblocking.*}}
14 changes: 14 additions & 0 deletions clang/test/Driver/rtsan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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

// Ensure the rtsan_realtime calls are never optimized away

int foo(int *a) [[clang::nonblocking]] { return *a; }
// CHECK: __rtsan_realtime_enter
// 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.*}}
}
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
35 changes: 35 additions & 0 deletions llvm/include/llvm/Transforms/Instrumentation/RealtimeSanitizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===--------- Definition of the RealtimeSanitizer class ---------*- 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
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H

#include "llvm/IR/PassManager.h"
#include "llvm/Transforms/Instrumentation/RealtimeSanitizerOptions.h"

namespace llvm {

struct RealtimeSanitizerOptions {};

class RealtimeSanitizerPass : public PassInfoMixin<RealtimeSanitizerPass> {
public:
RealtimeSanitizerPass(const RealtimeSanitizerOptions &Options);
PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);

static bool isRequired() { return true; }

private:
RealtimeSanitizerOptions Options{};
};

} // namespace llvm

#endif // LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZER_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//===--------- Definition of the RealtimeSanitizer options -------*- 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
//
//===----------------------------------------------------------------------===//
// This file defines data types used to set Realtime Sanitizer options.
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
#define LLVM_TRANSFORMS_INSTRUMENTATION_REALTIMESANITIZEROPTIONS_H
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, old school c-style include guards seems to be the move around here!


namespace llvm {} // namespace llvm
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Kept as a placeholder, as we need to add Options very soon to have different exit modes etc. I can delete this if it looks too wonky


#endif
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2109,6 +2109,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::ReadOnly;
case bitc::ATTR_KIND_RETURNED:
return Attribute::Returned;
case bitc::ATTR_KIND_NONBLOCKING:
return Attribute::NonBlocking;
case bitc::ATTR_KIND_RETURNS_TWICE:
return Attribute::ReturnsTwice;
case bitc::ATTR_KIND_S_EXT:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE;
case Attribute::OptimizeNone:
return bitc::ATTR_KIND_OPTIMIZE_NONE;
case Attribute::NonBlocking:
return bitc::ATTR_KIND_NONBLOCKING;
case Attribute::ReadNone:
return bitc::ATTR_KIND_READ_NONE;
case Attribute::ReadOnly:
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
#include "llvm/Transforms/Instrumentation/PGOForceFunctionAttrs.h"
#include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
#include "llvm/Transforms/Instrumentation/PoisonChecking.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"
Expand Down Expand Up @@ -1207,6 +1208,11 @@ parseRegAllocFastPassOptions(PassBuilder &PB, StringRef Params) {
return Opts;
}

Expected<RealtimeSanitizerOptions> parseRtSanPassOptions(StringRef Params) {
RealtimeSanitizerOptions Result;
return Result;
}

} // namespace

/// Tests whether a pass name starts with a valid prefix for a default pipeline
Expand Down
Loading