Author: Vitaly Buka Date: 2024-12-19T16:38:07-08:00 New Revision: c2aee5062087f193cb5756f378c248c7d91b7245
URL: https://github.com/llvm/llvm-project/commit/c2aee5062087f193cb5756f378c248c7d91b7245 DIFF: https://github.com/llvm/llvm-project/commit/c2aee5062087f193cb5756f378c248c7d91b7245.diff LOG: [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. Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/CodeGen/BackendUtil.cpp clang/lib/Driver/SanitizerArgs.cpp clang/test/CodeGen/bounds-checking.c compiler-rt/lib/ubsan/ubsan_checks.inc compiler-rt/lib/ubsan/ubsan_handlers.cpp compiler-rt/lib/ubsan/ubsan_handlers.h compiler-rt/lib/ubsan/ubsan_interface.inc compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index edb2e4a10ded05..b8d92a6c881c68 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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``. diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index b1003f2ce5032e..e6c9d77d29f6f1 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -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 diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 0b1f4f0112ac01..7726e464f2b458 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -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 | diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c index 1eedae9d8be0f8..f9319ca61670c3 100644 --- a/clang/test/CodeGen/bounds-checking.c +++ b/clang/test/CodeGen/bounds-checking.c @@ -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 // diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index 846cd89ee19f8b..b1d09a9024e7ed 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -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") diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index a419cf0b2b5557..ac7001c74afb50 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -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; diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.h b/compiler-rt/lib/ubsan/ubsan_handlers.h index 4ffa1439a1323f..521caa96bc771b 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/compiler-rt/lib/ubsan/ubsan_handlers.h @@ -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; }; diff --git a/compiler-rt/lib/ubsan/ubsan_interface.inc b/compiler-rt/lib/ubsan/ubsan_interface.inc index cb27feb5d7e99b..0eb109f37d4458 100644 --- a/compiler-rt/lib/ubsan/ubsan_interface.inc +++ b/compiler-rt/lib/ubsan/ubsan_interface.inc @@ -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) diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index 98662c5881c9f9..c3ffd41bcacc0b 100644 --- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -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") diff --git a/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp index edfe439c92790d..d5e0b46a0f8be8 100644 --- a/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp +++ b/compiler-rt/test/ubsan/TestCases/Misc/local_bounds.cpp @@ -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) { diff --git a/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp index edfe439c92790d..c972e1ecfc0171 100644 --- a/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp +++ b/compiler-rt/test/ubsan_minimal/TestCases/local_bounds.cpp @@ -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) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits