[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:
Vitaly Buka 2024-12-19 16:38:07 -08:00 committed by GitHub
parent 44201679c6
commit c2aee50620
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 63 additions and 13 deletions

View File

@ -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``.

View File

@ -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

View File

@ -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 |

View File

@ -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
//

View File

@ -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")

View File

@ -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;

View File

@ -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;
};

View File

@ -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)

View File

@ -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")

View File

@ -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) {

View File

@ -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) {