[ubsan] Runtime and driver support for local-bounds (#120515)
Implements ``-f[no-]sanitize-trap=local-bounds``, and ``-f[no-]sanitize-recover=local-bounds``. LLVM part is here #120513.
This commit is contained in:
parent
44201679c6
commit
c2aee50620
@ -1206,6 +1206,8 @@ Sanitizers
|
||||
``-fsanitize=type`` flag. This sanitizer detects violations of C/C++ type-based
|
||||
aliasing rules.
|
||||
|
||||
- Implemented ``-f[no-]sanitize-trap=local-bounds``, and ``-f[no-]sanitize-recover=local-bounds``.
|
||||
|
||||
Python Binding Changes
|
||||
----------------------
|
||||
- Fixed an issue that led to crashes when calling ``Type.get_exception_specification_kind``.
|
||||
|
@ -1028,9 +1028,20 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
|
||||
// of the pipeline.
|
||||
if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
|
||||
PB.registerScalarOptimizerLateEPCallback(
|
||||
[](FunctionPassManager &FPM, OptimizationLevel Level) {
|
||||
FPM.addPass(
|
||||
BoundsCheckingPass(BoundsCheckingPass::ReportingMode::Trap));
|
||||
[this](FunctionPassManager &FPM, OptimizationLevel Level) {
|
||||
BoundsCheckingPass::ReportingMode Mode;
|
||||
if (CodeGenOpts.SanitizeTrap.has(SanitizerKind::LocalBounds)) {
|
||||
Mode = BoundsCheckingPass::ReportingMode::Trap;
|
||||
} else if (CodeGenOpts.SanitizeMinimalRuntime) {
|
||||
Mode = CodeGenOpts.SanitizeRecover.has(SanitizerKind::LocalBounds)
|
||||
? BoundsCheckingPass::ReportingMode::MinRuntime
|
||||
: BoundsCheckingPass::ReportingMode::MinRuntimeAbort;
|
||||
} else {
|
||||
Mode = CodeGenOpts.SanitizeRecover.has(SanitizerKind::LocalBounds)
|
||||
? BoundsCheckingPass::ReportingMode::FullRuntime
|
||||
: BoundsCheckingPass::ReportingMode::FullRuntimeAbort;
|
||||
}
|
||||
FPM.addPass(BoundsCheckingPass(Mode));
|
||||
});
|
||||
|
||||
// Don't add sanitizers if we are here from ThinLTO PostLink. That already
|
||||
|
@ -27,9 +27,9 @@ using namespace llvm::opt;
|
||||
|
||||
static const SanitizerMask NeedsUbsanRt =
|
||||
SanitizerKind::Undefined | SanitizerKind::Integer |
|
||||
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
|
||||
SanitizerKind::CFI | SanitizerKind::FloatDivideByZero |
|
||||
SanitizerKind::ObjCCast;
|
||||
SanitizerKind::LocalBounds | SanitizerKind::ImplicitConversion |
|
||||
SanitizerKind::Nullability | SanitizerKind::CFI |
|
||||
SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
|
||||
static const SanitizerMask NeedsUbsanCxxRt =
|
||||
SanitizerKind::Vptr | SanitizerKind::CFI;
|
||||
static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
|
||||
@ -69,7 +69,8 @@ static const SanitizerMask TrappingSupported =
|
||||
SanitizerKind::LocalBounds | SanitizerKind::CFI |
|
||||
SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
|
||||
static const SanitizerMask MergeDefault = SanitizerKind::Undefined;
|
||||
static const SanitizerMask TrappingDefault = SanitizerKind::CFI;
|
||||
static const SanitizerMask TrappingDefault =
|
||||
SanitizerKind::CFI | SanitizerKind::LocalBounds;
|
||||
static const SanitizerMask CFIClasses =
|
||||
SanitizerKind::CFIVCall | SanitizerKind::CFINVCall |
|
||||
SanitizerKind::CFIMFCall | SanitizerKind::CFIDerivedCast |
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsanitize=local-bounds -fsanitize-trap=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
|
||||
// RUN: %clang_cc1 -fsanitize=array-bounds -O -emit-llvm -triple x86_64-apple-darwin10 %s -o - | not FileCheck %s
|
||||
// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s
|
||||
//
|
||||
|
@ -53,6 +53,7 @@ UBSAN_CHECK(ImplicitSignedIntegerTruncationOrSignChange,
|
||||
UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base")
|
||||
UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent")
|
||||
UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
|
||||
UBSAN_CHECK(LocalOutOfBounds, "local-out-of-bounds", "local-bounds")
|
||||
UBSAN_CHECK(UnreachableCall, "unreachable-call", "unreachable")
|
||||
UBSAN_CHECK(MissingReturn, "missing-return", "return")
|
||||
UBSAN_CHECK(NonPositiveVLAIndex, "non-positive-vla-index", "vla-bound")
|
||||
|
@ -405,6 +405,28 @@ void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,
|
||||
Die();
|
||||
}
|
||||
|
||||
static void handleLocalOutOfBoundsImpl(ReportOptions Opts) {
|
||||
// FIXME: Pass more diagnostic info.
|
||||
SymbolizedStackHolder CallerLoc;
|
||||
CallerLoc.reset(getCallerLocation(Opts.pc));
|
||||
Location Loc;
|
||||
Loc = CallerLoc;
|
||||
ErrorType ET = ErrorType::LocalOutOfBounds;
|
||||
ScopedReport R(Opts, Loc, ET);
|
||||
Diag(Loc, DL_Error, ET, "access out of bounds");
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_local_out_of_bounds() {
|
||||
GET_REPORT_OPTIONS(false);
|
||||
handleLocalOutOfBoundsImpl(Opts);
|
||||
}
|
||||
|
||||
void __ubsan::__ubsan_handle_local_out_of_bounds_abort() {
|
||||
GET_REPORT_OPTIONS(true);
|
||||
handleLocalOutOfBoundsImpl(Opts);
|
||||
Die();
|
||||
}
|
||||
|
||||
static void handleBuiltinUnreachableImpl(UnreachableData *Data,
|
||||
ReportOptions Opts) {
|
||||
ErrorType ET = ErrorType::UnreachableCall;
|
||||
|
@ -90,6 +90,9 @@ struct OutOfBoundsData {
|
||||
/// \brief Handle an array index out of bounds error.
|
||||
RECOVERABLE(out_of_bounds, OutOfBoundsData *Data, ValueHandle Index)
|
||||
|
||||
/// \brief Handle an local object access out of bounds error.
|
||||
RECOVERABLE(local_out_of_bounds)
|
||||
|
||||
struct UnreachableData {
|
||||
SourceLocation Loc;
|
||||
};
|
||||
|
@ -46,6 +46,8 @@ INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1_abort)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_local_out_of_bounds)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_local_out_of_bounds_abort)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort)
|
||||
INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds)
|
||||
|
@ -138,6 +138,7 @@ HANDLER(negate_overflow, "negate-overflow")
|
||||
HANDLER(divrem_overflow, "divrem-overflow")
|
||||
HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
|
||||
HANDLER(out_of_bounds, "out-of-bounds")
|
||||
HANDLER(local_out_of_bounds, "local-out-of-bounds")
|
||||
HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
|
||||
HANDLER_RECOVER(missing_return, "missing-return")
|
||||
HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
|
||||
|
@ -1,7 +1,8 @@
|
||||
// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && %run %t 1
|
||||
// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && not --crash %run %t 3
|
||||
|
||||
// FIXME: it's always trap for now.
|
||||
// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds %s -O3 -o %t && not %run %t 3 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds -fsanitize-recover=local-bounds %s -O3 -o %t && %run %t 3 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds -fsanitize-recover=local-bounds -g %s -O3 -o %t && %run %t 3 2>&1 | FileCheck %s --check-prefixes=LINE
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@ -14,12 +15,17 @@ __attribute__((noinline)) void init(S *s) {
|
||||
__asm__ __volatile__("" : : "r"(s) : "memory");
|
||||
}
|
||||
|
||||
__attribute__((noinline, no_sanitize("memory"))) int test(char i) {
|
||||
__attribute__((noinline, no_sanitize("memory", "address", "hwaddress"))) int
|
||||
test(char i) {
|
||||
S a;
|
||||
init(&a);
|
||||
S b;
|
||||
init(&b);
|
||||
return ((int *)(&a))[i];
|
||||
// CHECK: error: access out of bounds
|
||||
// CHECK: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior
|
||||
// LINE: local_bounds.cpp:[[#@LINE-3]]:{{.*}}runtime error: access out of bounds
|
||||
// LINE: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior {{.*}}local_bounds.cpp:[[#@LINE-4]]:
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && %run %t 1
|
||||
// RUN: %clangxx -fsanitize=local-bounds %s -O3 -o %t && not --crash %run %t 3
|
||||
|
||||
// FIXME: it's always trap for now.
|
||||
// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds %s -O3 -o %t && not --crash %run %t 3 2>&1 | FileCheck %s
|
||||
// RUN: %clangxx -fsanitize=local-bounds -fno-sanitize-trap=local-bounds -fsanitize-recover=local-bounds %s -O3 -o %t && %run %t 3 2>&1 | FileCheck %s
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@ -20,6 +20,7 @@ __attribute__((noinline, no_sanitize("memory"))) int test(char i) {
|
||||
S b;
|
||||
init(&b);
|
||||
return ((int *)(&a))[i];
|
||||
// CHECK: ubsan: local-out-of-bounds by 0x{{[[:xdigit:]]+$}}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user