Skip to content
Merged
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 @@ -3165,6 +3165,11 @@ def NoSanitize : InheritableAttr {
bool hasCoverage() const {
return llvm::is_contained(sanitizers(), "coverage");
}

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

}];
}

Expand Down
38 changes: 30 additions & 8 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#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 @@ -748,8 +749,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const bool SanitizeBounds = SanOpts.hasOneOf(SanitizerKind::Bounds);
SanitizerMask no_sanitize_mask;
bool NoSanitizeCoverage = false;
bool NoSanitizeRealtime = false;

for (auto *Attr : D->specific_attrs<NoSanitizeAttr>()) {
// The realtime sanitizer is not handled by SanOpts
// if it is enabled, it should remain enabled
if (Attr->hasRealtime()) {
NoSanitizeRealtime = true;
continue;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Alright, this feels like a kind of hack here.

Basically the idea is what I described in the original description of this PR. On line 1573, if the realtime sanitizer is disabled, it is turned off. That sounds stupid to type out, but it's important.

If the realtime sanitizer is turned off, the block on line 1573 is never tripped, and we never get the opportunity to add the bypass call in.

Our options:

  1. Don't respect the __nosanitize attribute, which would mean we just remove this entire change in this function
  2. do this some other way?? Not sure how...

The psuedocode (implemented here) feels hacky:

This feels a little hacky because it's essentially saying "Do not ACTUALLY turn off the RADSan if the flag tells you to". This means that while SanOpts will be accurate for all other sanitizers, it will not be accurate for RADSan.

Choose a reason for hiding this comment

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

After having a think, this doesn't feel that bad to me. Fundamentally what "no sanitize" means for a RADSan-sanitized function is different to what "no sanitize" means in other sanitizers. For RADSan, it's not really "turning it off" - it just means that we have to do something different: inserting the radsan_off() and radsan_on() calls! I'm not sure there's another way, as you imply as well. With a clear enough comment, I feel like this is a reasonable approach!


no_sanitize_mask |= Attr->getMask();
// SanitizeCoverage is not handled by SanOpts.
if (Attr->hasCoverage())
Expand All @@ -767,6 +776,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (no_sanitize_mask & SanitizerKind::KernelHWAddress)
SanOpts.set(SanitizerKind::HWAddress, false);

if (NoSanitizeRealtime)
{
Fn->addFnAttr(llvm::Attribute::NoSanitizeRealtime);
}

if (SanitizeBounds && !SanOpts.hasOneOf(SanitizerKind::Bounds))
Fn->addFnAttr(llvm::Attribute::NoSanitizeBounds);

Expand Down Expand Up @@ -1366,18 +1380,18 @@ void InsertRadsanFunctionCallBeforeInstruction(llvm::Function *Fn,
builder.CreateCall(func, {});
}

void InsertRadsanEnter(llvm::Function *Fn) {
void insertCallAtFunctionEntryPoint(llvm::Function *Fn, std::string const &InsertFnName) {

InsertRadsanFunctionCallBeforeInstruction(Fn, Fn->front().front(),
"radsan_realtime_enter");
InsertFnName);
}

void InsertRadsanExit(llvm::Function *Fn) {
void insertCallAtAllFunctionExitPoints(llvm::Function *Fn, std::string const &InsertFnName) {
for (auto &bb : *Fn) {
for (auto &i : bb) {
if (auto *ri = dyn_cast<llvm::ReturnInst>(&i)) {
InsertRadsanFunctionCallBeforeInstruction(Fn, i,
"radsan_realtime_exit");
InsertFnName);
}
}
}
Expand Down Expand Up @@ -1545,17 +1559,25 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
}

if (SanOpts.has(SanitizerKind::Realtime)) {
if (Fn->hasFnAttribute(llvm::Attribute::AttrKind::Realtime)) {
{ InsertRadsanEnter(Fn); }
if (Fn->hasFnAttribute(llvm::Attribute::NoSanitizeRealtime)) {
insertCallAtFunctionEntryPoint(Fn, "radsan_off");
}

if (Fn->hasFnAttribute(llvm::Attribute::Realtime)) {
insertCallAtFunctionEntryPoint(Fn, "radsan_realtime_enter");
}
}

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

if (SanOpts.has(SanitizerKind::Realtime)) {
if (Fn->hasFnAttribute(llvm::Attribute::AttrKind::Realtime)) {
{ InsertRadsanExit(Fn); }
if (Fn->hasFnAttribute(llvm::Attribute::NoSanitizeRealtime)) {
insertCallAtAllFunctionExitPoints(Fn, "radsan_on");
}

if (Fn->hasFnAttribute(llvm::Attribute::Realtime)) {
insertCallAtAllFunctionExitPoints(Fn, "radsan_realtime_exit");
}
}

Expand Down
41 changes: 41 additions & 0 deletions compiler-rt/test/radsan/TestCases/test_bypass_nosanitize.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %clangxx -fsanitize=realtime %s -o %t
// RUN: not %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: ios

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

__attribute__((no_sanitize("realtime")))
void bypassedLock(pthread_mutex_t& Mutex) {
pthread_mutex_lock(&Mutex);
}

__attribute__((no_sanitize("realtime")))
void bypassedUnlock(pthread_mutex_t& Mutex) {
pthread_mutex_unlock(&Mutex);
}

void violationLock(pthread_mutex_t& Mutex) {
pthread_mutex_lock(&Mutex);
}

[[clang::realtime]] void process(pthread_mutex_t& Mutex) {
bypassedLock(Mutex);
bypassedUnlock(Mutex);

violationLock(Mutex);
bypassedUnlock(Mutex);
}

int main() {
pthread_mutex_t Mutex;
pthread_mutex_init(&Mutex, NULL);

process(Mutex);
return 0;
// CHECK: {{.*Real-time violation.*pthread_mutex_lock.*}}
// CHECK: {{.*violationLock*}}
// CHECK-NOT: {{.*pthread_mutex_unlock.*}}
// CHECK-NOT: {{.*bypassedUnlock.*}}
// CHECK-NOT: {{.*bypassedLock.*}}
}
5 changes: 5 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,11 @@ example:
``nosanitize_coverage``
This attribute indicates that SanitizerCoverage instrumentation is disabled
for this function.
``nosanitize_realtime``
This attribute indicates that SanitizerRealtime is disabled for this
function. If called from a function marked ``clang::realtime``, no
errors that would normally be reported by SanitizerRealtime will be
reported.
``null_pointer_is_valid``
If ``null_pointer_is_valid`` is set, then the ``null`` address
in address-space 0 is considered to be a valid address for memory loads and
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 @@ -714,6 +714,7 @@ enum AttributeKindCodes {
ATTR_KIND_MEMORY = 86,
ATTR_KIND_NOFPCLASS = 87,
ATTR_KIND_REALTIME = 88,
ATTR_KIND_NO_SANITIZE_REALTIME = 89,
};

enum ComdatSelectionKindCodes {
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ def NoSanitizeBounds : EnumAttr<"nosanitize_bounds", [FnAttr]>;
/// No SanitizeCoverage instrumentation.
def NoSanitizeCoverage : EnumAttr<"nosanitize_coverage", [FnAttr]>;

/// No SanitizeRealtime instrumentation.
def NoSanitizeRealtime : EnumAttr<"nosanitize_realtime", [FnAttr]>;

/// Null pointer in address space zero is valid.
def NullPointerIsValid : EnumAttr<"null_pointer_is_valid", [FnAttr]>;

Expand All @@ -218,6 +221,7 @@ def ReadNone : EnumAttr<"readnone", [ParamAttr]>;
/// Function only reads from memory.
def ReadOnly : EnumAttr<"readonly", [ParamAttr]>;

/// Function is marked to be analyzed by the realtime sanitizer.
def Realtime : EnumAttr<"realtime", [FnAttr]>;

/// Return value is always equal to this argument.
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::Returned;
case bitc::ATTR_KIND_REALTIME:
return Attribute::Realtime;
case bitc::ATTR_KIND_NO_SANITIZE_REALTIME:
return Attribute::NoSanitizeRealtime;
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 @@ -743,6 +743,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_OPTIMIZE_NONE;
case Attribute::Realtime:
return bitc::ATTR_KIND_REALTIME;
case Attribute::NoSanitizeRealtime:
return bitc::ATTR_KIND_NO_SANITIZE_REALTIME;
case Attribute::ReadNone:
return bitc::ATTR_KIND_READ_NONE;
case Attribute::ReadOnly:
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
case Attribute::NoProfile:
case Attribute::SkipProfile:
case Attribute::Realtime:
case Attribute::NoSanitizeRealtime:
break;
// These attributes cannot be applied to functions.
case Attribute::Alignment:
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Bitcode/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,12 @@ define void @f86() nosanitize_bounds
ret void;
}

; CHECK: define void @f89() #53
define void @f89() nosanitize_realtime
{
ret void;
}

; CHECK: define void @f87() [[FNRETTHUNKEXTERN:#[0-9]+]]
define void @f87() fn_ret_thunk_extern { ret void }

Expand Down Expand Up @@ -564,6 +570,7 @@ define void @f88() skipprofile { ret void }
; CHECK: attributes #50 = { disable_sanitizer_instrumentation }
; CHECK: attributes #51 = { uwtable(sync) }
; CHECK: attributes #52 = { nosanitize_bounds }
; CHECK: attributes #53 = { nosanitize_realtime }
; CHECK: attributes [[FNRETTHUNKEXTERN]] = { fn_ret_thunk_extern }
; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }
7 changes: 5 additions & 2 deletions llvm/test/Bitcode/compatibility.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,7 @@ exit:
; CHECK: select <2 x i1> <i1 true, i1 false>, <2 x i8> <i8 2, i8 3>, <2 x i8> <i8 3, i8 2>

call void @f.nobuiltin() builtin
; CHECK: call void @f.nobuiltin() #51
; CHECK: call void @f.nobuiltin() #52

call fastcc noalias ptr @f.noalias() noinline
; CHECK: call fastcc noalias ptr @f.noalias() #12
Expand Down Expand Up @@ -1980,6 +1980,8 @@ declare void @f.nosanitize_bounds() nosanitize_bounds
declare void @f.allockind() allockind("alloc,uninitialized")
; CHECK: declare void @f.allockind() #50

declare void @f.nosanitize_realtime() nosanitize_realtime
; CHECK: declare void @f.nosanitize_realtime() #51

; CHECK: declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
declare nofpclass(snan) float @nofpclass_snan(float nofpclass(snan))
Expand Down Expand Up @@ -2102,7 +2104,8 @@ define float @nofpclass_callsites(float %arg) {
; CHECK: attributes #48 = { allocsize(1,0) }
; CHECK: attributes #49 = { nosanitize_bounds }
; CHECK: attributes #50 = { allockind("alloc,uninitialized") }
; CHECK: attributes #51 = { builtin }
; CHECK: attributes #51 = { nosanitize_realtime }
; CHECK: attributes #52 = { builtin }
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Why did I do 51 instead of 52? These orderings are very specific, it seems. I could not get them to play nicely if I appended this, so I put it at 51.

It seems like it compiles a bunch of little functions and checks the output is sane. All of the rest of them seem to be copy/paste but builtin is different somehow. This may be the reason it is last and should remain last


;; Metadata

Expand Down
2 changes: 1 addition & 1 deletion llvm/utils/emacs/llvm-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
'("alwaysinline" "argmemonly" "allocsize" "builtin" "cold" "convergent" "dereferenceable" "dereferenceable_or_null" "hot" "immarg" "inaccessiblememonly"
"inaccessiblemem_or_argmemonly" "inalloca" "inlinehint" "jumptable" "minsize" "mustprogress" "naked" "nobuiltin" "nonnull" "nocapture"
"nocallback" "nocf_check" "noduplicate" "nofree" "noimplicitfloat" "noinline" "nomerge" "nonlazybind" "noprofile" "noredzone" "noreturn"
"norecurse" "nosync" "noundef" "nounwind" "nosanitize_bounds" "nosanitize_coverage" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
"norecurse" "nosync" "noundef" "nounwind" "nosanitize_bounds" "nosanitize_coverage" "nosanitize_realtime" "null_pointer_is_valid" "optforfuzzing" "optnone" "optsize" "preallocated" "readnone" "readonly" "returned" "returns_twice"
"shadowcallstack" "signext" "speculatable" "speculative_load_hardening" "ssp" "sspreq" "sspstrong" "safestack" "sanitize_address" "sanitize_hwaddress" "sanitize_memtag"
"sanitize_thread" "sanitize_memory" "strictfp" "swifterror" "uwtable" "vscale_range" "willreturn" "writeonly" "zeroext") 'symbols) . font-lock-constant-face)
;; Variables
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/llvm.grm
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ FuncAttr ::= noreturn
| mustprogress
| nosanitize_bounds
| nosanitize_coverage
| nosanitize_realtime
;

OptFuncAttrs ::= + _ | OptFuncAttrs FuncAttr ;
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/vim/syntax/llvm.vim
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ syn keyword llvmKeyword
\ nounwind
\ nosanitize_bounds
\ nosanitize_coverage
\ nosanitize_realtime
\ null_pointer_is_valid
\ optforfuzzing
\ optnone
Expand Down
1 change: 1 addition & 0 deletions llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ patterns:
\\bnounwind\\b|\
\\bnosanitize_bounds\\b|\
\\bnosanitize_coverage\\b|\
\\bnosanitize_realtime\\b|\
\\bnull_pointer_is_valid\\b|\
\\boptforfuzzing\\b|\
\\boptnone\\b|\
Expand Down