Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
CodeGenOpts.SanitizeMinimalRuntime),
/*MayReturn=*/
CodeGenOpts.SanitizeRecover.has(SanitizerKind::LocalBounds),
/*HandlerPreserveAllRegs=*/
static_cast<bool>(CodeGenOpts.SanitizeHandlerPreserveAllRegs),
};
}
FPM.addPass(BoundsCheckingPass(Options));
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3789,6 +3789,8 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
bool NeedsAbortSuffix =
IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable;
bool MinimalRuntime = CGF.CGM.getCodeGenOpts().SanitizeMinimalRuntime;
bool HandlerPreserveAllRegs =
CGF.CGM.getCodeGenOpts().SanitizeHandlerPreserveAllRegs;
const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler];
const StringRef CheckName = CheckInfo.Name;
std::string FnName = "__ubsan_handle_" + CheckName.str();
Expand All @@ -3798,6 +3800,8 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
FnName += "_minimal";
if (NeedsAbortSuffix)
FnName += "_abort";
else if (MinimalRuntime && HandlerPreserveAllRegs)
FnName += "_preserve";
bool MayReturn =
!IsFatal || RecoverKind == CheckRecoverableKind::AlwaysRecoverable;

Expand All @@ -3818,6 +3822,10 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
(CGF.CurCodeDecl && CGF.CurCodeDecl->hasAttr<OptimizeNoneAttr>());
if (NoMerge)
HandlerCall->addFnAttr(llvm::Attribute::NoMerge);
if (MinimalRuntime && HandlerPreserveAllRegs) {
// N.B. there is also a clang::CallingConv which is not what we want here.
HandlerCall->setCallingConv(llvm::CallingConv::PreserveAll);
}
if (!MayReturn) {
HandlerCall->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
Expand Down
36 changes: 36 additions & 0 deletions clang/test/CodeGen/cfi-icall-trap-recover-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

// RUN: %clang_cc1 -fsanitize=cfi-icall -fno-sanitize-trap=cfi-icall -fsanitize-recover=cfi-icall -fsanitize-minimal-runtime -flto -fvisibility=hidden -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=RECOVER_MIN %s

// RUN: %clang_cc1 -fsanitize=cfi-icall -fno-sanitize-trap=cfi-icall -fsanitize-recover=cfi-icall -fsanitize-minimal-runtime -fsanitize-handler-preserve-all-regs -flto -fvisibility=hidden -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=PRESERVE_MIN %s


// TRAP-LABEL: define hidden void @f(
// TRAP-SAME: ) #[[ATTR0:[0-9]+]] !type [[META6:![0-9]+]] !type [[META7:![0-9]+]] {
// TRAP-NEXT: [[ENTRY:.*:]]
Expand All @@ -34,6 +37,11 @@
// RECOVER_MIN-NEXT: [[ENTRY:.*:]]
// RECOVER_MIN-NEXT: ret void
//
// PRESERVE_MIN-LABEL: define hidden void @f(
// PRESERVE_MIN-SAME: ) #[[ATTR0:[0-9]+]] !type [[META6:![0-9]+]] !type [[META7:![0-9]+]] {
// PRESERVE_MIN-NEXT: [[ENTRY:.*:]]
// PRESERVE_MIN-NEXT: ret void
//
void f() {
}

Expand Down Expand Up @@ -146,6 +154,27 @@ void xf();
// RECOVER_MIN-NEXT: call void (...) [[TMP2]]()
// RECOVER_MIN-NEXT: ret void
//
// PRESERVE_MIN-LABEL: define hidden void @g(
// PRESERVE_MIN-SAME: i32 noundef [[B:%.*]]) #[[ATTR0]] !type [[META8:![0-9]+]] !type [[META9:![0-9]+]] {
// PRESERVE_MIN-NEXT: [[ENTRY:.*:]]
// PRESERVE_MIN-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4
// PRESERVE_MIN-NEXT: [[FP:%.*]] = alloca ptr, align 8
// PRESERVE_MIN-NEXT: store i32 [[B]], ptr [[B_ADDR]], align 4
// PRESERVE_MIN-NEXT: [[TMP0:%.*]] = load i32, ptr [[B_ADDR]], align 4
// PRESERVE_MIN-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
// PRESERVE_MIN-NEXT: [[TMP1:%.*]] = zext i1 [[TOBOOL]] to i64
// PRESERVE_MIN-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], ptr @f, ptr @xf
// PRESERVE_MIN-NEXT: store ptr [[COND]], ptr [[FP]], align 8
// PRESERVE_MIN-NEXT: [[TMP2:%.*]] = load ptr, ptr [[FP]], align 8
// PRESERVE_MIN-NEXT: [[TMP3:%.*]] = call i1 @llvm.type.test(ptr [[TMP2]], metadata !"_ZTSFvE"), !nosanitize [[META10:![0-9]+]]
// PRESERVE_MIN-NEXT: br i1 [[TMP3]], label %[[CONT:.*]], label %[[HANDLER_CFI_CHECK_FAIL:.*]], !prof [[PROF11:![0-9]+]], !nosanitize [[META10]]
// PRESERVE_MIN: [[HANDLER_CFI_CHECK_FAIL]]:
// PRESERVE_MIN-NEXT: call preserve_allcc void @__ubsan_handle_cfi_check_fail_minimal_preserve() #[[ATTR4:[0-9]+]], !nosanitize [[META10]]
// PRESERVE_MIN-NEXT: br label %[[CONT]], !nosanitize [[META10]]
// PRESERVE_MIN: [[CONT]]:
// PRESERVE_MIN-NEXT: call void (...) [[TMP2]]()
// PRESERVE_MIN-NEXT: ret void
//
void g(int b) {
void (*fp)() = b ? f : xf;
fp();
Expand Down Expand Up @@ -186,3 +215,10 @@ void g(int b) {
// RECOVER_MIN: [[META10]] = !{}
// RECOVER_MIN: [[PROF11]] = !{!"branch_weights", i32 1048575, i32 1}
//.
// PRESERVE_MIN: [[META6]] = !{i64 0, !"_ZTSFvE"}
// PRESERVE_MIN: [[META7]] = !{i64 0, !"_ZTSFvE.generalized"}
// PRESERVE_MIN: [[META8]] = !{i64 0, !"_ZTSFviE"}
// PRESERVE_MIN: [[META9]] = !{i64 0, !"_ZTSFviE.generalized"}
// PRESERVE_MIN: [[META10]] = !{}
// PRESERVE_MIN: [[PROF11]] = !{!"branch_weights", i32 1048575, i32 1}
//.
24 changes: 24 additions & 0 deletions clang/test/CodeGenCXX/cfi-vcall-trap-recover-runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

// RUN: %clang_cc1 -fsanitize=cfi-vcall -fno-sanitize-trap=cfi-vcall -fsanitize-recover=cfi-vcall -fsanitize-minimal-runtime -flto -fvisibility=hidden -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=RECOVER_MIN %s

// RUN: %clang_cc1 -fsanitize=cfi-vcall -fno-sanitize-trap=cfi-vcall -fsanitize-recover=cfi-vcall -fsanitize-minimal-runtime -flto -fvisibility=hidden -triple x86_64-unknown-linux -fwhole-program-vtables -fsanitize-handler-preserve-all-regs -emit-llvm -o - %s | FileCheck --check-prefix=PRESERVE_MIN %s

struct S1 {
virtual void f();
};
Expand Down Expand Up @@ -111,6 +113,25 @@ struct S1 {
// RECOVER_MIN-NEXT: call void [[TMP3]](ptr noundef nonnull align 8 dereferenceable(8) [[TMP0]])
// RECOVER_MIN-NEXT: ret void
//
// PRESERVE_MIN-LABEL: define hidden void @_Z3s1fP2S1(
// PRESERVE_MIN-SAME: ptr noundef [[S1:%.*]]) #[[ATTR0:[0-9]+]] {
// PRESERVE_MIN-NEXT: [[ENTRY:.*:]]
// PRESERVE_MIN-NEXT: [[S1_ADDR:%.*]] = alloca ptr, align 8
// PRESERVE_MIN-NEXT: store ptr [[S1]], ptr [[S1_ADDR]], align 8
// PRESERVE_MIN-NEXT: [[TMP0:%.*]] = load ptr, ptr [[S1_ADDR]], align 8
// PRESERVE_MIN-NEXT: [[VTABLE:%.*]] = load ptr, ptr [[TMP0]], align 8
// PRESERVE_MIN-NEXT: [[TMP1:%.*]] = call i1 @llvm.type.test(ptr [[VTABLE]], metadata !"_ZTS2S1"), !nosanitize [[META5:![0-9]+]]
// PRESERVE_MIN-NEXT: [[TMP2:%.*]] = call i1 @llvm.type.test(ptr [[VTABLE]], metadata !"all-vtables"), !nosanitize [[META5]]
// PRESERVE_MIN-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[HANDLER_CFI_CHECK_FAIL:.*]], !prof [[PROF6:![0-9]+]], !nosanitize [[META5]]
// PRESERVE_MIN: [[HANDLER_CFI_CHECK_FAIL]]:
// PRESERVE_MIN-NEXT: call preserve_allcc void @__ubsan_handle_cfi_check_fail_minimal_preserve() #[[ATTR3:[0-9]+]], !nosanitize [[META5]]
// PRESERVE_MIN-NEXT: br label %[[CONT]], !nosanitize [[META5]]
// PRESERVE_MIN: [[CONT]]:
// PRESERVE_MIN-NEXT: [[VFN:%.*]] = getelementptr inbounds ptr, ptr [[VTABLE]], i64 0
// PRESERVE_MIN-NEXT: [[TMP3:%.*]] = load ptr, ptr [[VFN]], align 8
// PRESERVE_MIN-NEXT: call void [[TMP3]](ptr noundef nonnull align 8 dereferenceable(8) [[TMP0]])
// PRESERVE_MIN-NEXT: ret void
//
void s1f(S1 *s1) {
s1->f();
}
Expand All @@ -130,3 +151,6 @@ void s1f(S1 *s1) {
// RECOVER_MIN: [[META5]] = !{}
// RECOVER_MIN: [[PROF6]] = !{!"branch_weights", i32 1048575, i32 1}
//.
// PRESERVE_MIN: [[META5]] = !{}
// PRESERVE_MIN: [[PROF6]] = !{!"branch_weights", i32 1048575, i32 1}
//.
7 changes: 7 additions & 0 deletions compiler-rt/test/ubsan_minimal/TestCases/override-callback.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_min_runtime -fsanitize=implicit-integer-sign-change %s -o %t && %run %t 2>&1 | FileCheck %s
// RUN: %clang_min_runtime -fsanitize=implicit-integer-sign-change -fsanitize-handler-preserve-all-regs %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=PRESERVE
// RUN: %clang_min_runtime -fsanitize=implicit-integer-sign-change -fno-sanitize-recover=all %s -o %t && not --crash %run %t 2>&1 | FileCheck %s
// RUN: %clang_min_runtime -fsanitize=implicit-integer-sign-change -fno-sanitize-recover=all -DOVERRIDE=1 %s -o %t && not --crash %run %t 2>&1 | FileCheck %s --check-prefixes=FATAL

Expand All @@ -12,6 +13,11 @@ void __ubsan_report_error(const char *kind, uintptr_t caller) {
fprintf(stderr, "CUSTOM_CALLBACK: %s\n", kind);
}

[[clang::preserve_all]] void __ubsan_report_error_preserve(const char *kind,
uintptr_t caller) {
fprintf(stderr, "CUSTOM_CALLBACK_PRESERVE: %s\n", kind);
}

#if OVERRIDE
void __ubsan_report_error_fatal(const char *kind, uintptr_t caller) {
fprintf(stderr, "FATAL_CALLBACK: %s\n", kind);
Expand All @@ -21,5 +27,6 @@ void __ubsan_report_error_fatal(const char *kind, uintptr_t caller) {
int main(int argc, const char **argv) {
int32_t t0 = (~((uint32_t)0));
// CHECK: CUSTOM_CALLBACK: implicit-conversion
// PRESERVE: CUSTOM_CALLBACK_PRESERVE: implicit-conversion
// FATAL: FATAL_CALLBACK: implicit-conversion
}
6 changes: 4 additions & 2 deletions llvm/include/llvm/Transforms/Instrumentation/BoundsChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ class BoundsCheckingPass : public PassInfoMixin<BoundsCheckingPass> {
public:
struct Options {
struct Runtime {
Runtime(bool MinRuntime, bool MayReturn)
: MinRuntime(MinRuntime), MayReturn(MayReturn) {}
Runtime(bool MinRuntime, bool MayReturn, bool HandlerPreserveAllRegs)
: MinRuntime(MinRuntime), MayReturn(MayReturn),
HandlerPreserveAllRegs(HandlerPreserveAllRegs) {}
bool MinRuntime;
bool MayReturn;
bool HandlerPreserveAllRegs;
};
std::optional<Runtime> Rt; // Trap if empty.
bool Merge = false;
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1590,21 +1590,31 @@ parseBoundsCheckingOptions(StringRef Params) {
Options.Rt = {
/*MinRuntime=*/false,
/*MayReturn=*/true,
/*HandlerPreserveAllRegs=*/false,
};
} else if (ParamName == "rt-abort") {
Options.Rt = {
/*MinRuntime=*/false,
/*MayReturn=*/false,
/*HandlerPreserveAllRegs=*/false,
};
} else if (ParamName == "min-rt") {
Options.Rt = {
/*MinRuntime=*/true,
/*MayReturn=*/true,
/*HandlerPreserveAllRegs=*/false,
};
} else if (ParamName == "min-rt-handler-preserve-all-regs") {
Options.Rt = {
/*MinRuntime=*/true,
/*MayReturn=*/true,
/*HandlerPreserveAllRegs=*/true,
};
} else if (ParamName == "min-rt-abort") {
Options.Rt = {
/*MinRuntime=*/true,
/*MayReturn=*/false,
/*HandlerPreserveAllRegs=*/false,
};
} else if (ParamName == "merge") {
Options.Merge = true;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ getRuntimeCallName(const BoundsCheckingPass::Options::Runtime &Opts) {
Name += "_minimal";
if (!Opts.MayReturn)
Name += "_abort";
else if (Opts.HandlerPreserveAllRegs && Opts.MinRuntime)
Name += "_preserve";
return Name;
}

Expand Down
17 changes: 17 additions & 0 deletions llvm/test/Instrumentation/BoundsChecking/runtimes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
; RUN: opt < %s -passes='bounds-checking<rt-abort>' -S | FileCheck %s --check-prefixes=RTABORT-NOMERGE
; RUN: opt < %s -passes='bounds-checking<min-rt>' -S | FileCheck %s --check-prefixes=MINRT-NOMERGE
; RUN: opt < %s -passes='bounds-checking<min-rt-abort>' -S | FileCheck %s --check-prefixes=MINRTABORT-NOMERGE
; RUN: opt < %s -passes='bounds-checking<min-rt-handler-preserve-all-regs>' -S | FileCheck %s --check-prefixes=MINRT-PRESERVE-NOMERGE
;
; RUN: opt < %s -passes='bounds-checking<trap;guard=3>' -S | FileCheck %s --check-prefixes=TR-GUARD-COMMON,TR-GUARD-THREE
; RUN: opt < %s -passes='bounds-checking<trap;guard=13>' -S | FileCheck %s --check-prefixes=TR-GUARD-COMMON,TR-GUARD-THIRTEEN
Expand Down Expand Up @@ -111,6 +112,22 @@ define void @f1(i64 %x) nounwind {
; MINRT-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal() #[[ATTR1:[0-9]+]], !nosanitize [[META0]]
; MINRT-NOMERGE-NEXT: br label %[[BB7]], !nosanitize [[META0]]
;
; MINRT-PRESERVE-NOMERGE-LABEL: define void @f1(
; MINRT-PRESERVE-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP2:%.*]] = alloca i128, i64 [[X]], align 8
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP3:%.*]] = sub i64 [[TMP1]], 0, !nosanitize [[META0:![0-9]+]]
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP4:%.*]] = icmp ult i64 [[TMP3]], 16, !nosanitize [[META0]]
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP5:%.*]] = or i1 false, [[TMP4]], !nosanitize [[META0]]
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP6:%.*]] = or i1 false, [[TMP5]], !nosanitize [[META0]]
; MINRT-PRESERVE-NOMERGE-NEXT: br i1 [[TMP6]], label %[[TRAP:.*]], label %[[BB7:.*]]
; MINRT-PRESERVE-NOMERGE: [[BB7]]:
; MINRT-PRESERVE-NOMERGE-NEXT: [[TMP8:%.*]] = load i128, ptr [[TMP2]], align 4
; MINRT-PRESERVE-NOMERGE-NEXT: ret void
; MINRT-PRESERVE-NOMERGE: [[TRAP]]:
; MINRT-PRESERVE-NOMERGE-NEXT: call void @__ubsan_handle_local_out_of_bounds_minimal_preserve() #[[ATTR1:[0-9]+]], !nosanitize [[META0]]
; MINRT-PRESERVE-NOMERGE-NEXT: br label %[[BB7]], !nosanitize [[META0]]
;
; MINRTABORT-NOMERGE-LABEL: define void @f1(
; MINRTABORT-NOMERGE-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
; MINRTABORT-NOMERGE-NEXT: [[TMP1:%.*]] = mul i64 16, [[X]]
Expand Down
Loading