jfb created this revision. Herald added subscribers: Sanitizers, cfe-commits, ributzka, dexonsmith, jkorous, cryptoad, mgorny. Herald added projects: clang, Sanitizers. jfb edited the summary of this revision.
Yes, this is April 1st and the patch isn't particularly serious. There is a ␇ UBSan runtime available. It is named in honor of Bell Labs (who gave us the C programming language and Undefined Behavior), the ASCII "bell" character (value `07`), and famed violinist Joshua Bell. It is not related to the city of Bell in California. This runtime will emit sound, most traditionally the terminal's bell sound, when undefined behavior occurs. To use the minimal runtime, add `-fsanitize-bel-runtime` to the clang command line options. For example, if you're used to compiling with `-fsanitize=undefined`, you could enable the minimal runtime with `-fsanitize=undefined -fsanitize-bel-runtime`. When combined with `-fsanitize-recover=undefined`, the ␇ runtime will simply chime on Undefined Behavior without killing the program for each chime. To avoid Pavlovian effects, the ␇ runtime uses Advanced Compiler Techniques called "heuristics" to avoid chiming too often at the same location. On macOS, the ␇ runtime will helpfully announce what specific undefined behavior you've encountered, and then taunt you. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D77219 Files: clang/docs/UndefinedBehaviorSanitizer.rst clang/include/clang/Basic/CodeGenOptions.def clang/include/clang/Driver/Options.td clang/include/clang/Driver/SanitizerArgs.h clang/lib/CodeGen/CGExpr.cpp clang/lib/Driver/SanitizerArgs.cpp clang/lib/Driver/ToolChains/CommonArgs.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/test/CodeGen/unsigned-overflow-bel.c clang/test/Driver/fsanitize.c clang/test/Driver/sanitizer-ld.c compiler-rt/cmake/config-ix.cmake compiler-rt/lib/ubsan_bel/CMakeLists.txt compiler-rt/lib/ubsan_bel/ubsan.syms.extra compiler-rt/lib/ubsan_bel/ubsan_bel_handlers.cpp compiler-rt/test/ubsan_bel/CMakeLists.txt compiler-rt/test/ubsan_bel/TestCases/alignment-assumption.c compiler-rt/test/ubsan_bel/TestCases/implicit-integer-sign-change.c compiler-rt/test/ubsan_bel/TestCases/implicit-signed-integer-truncation-or-sign-change.c compiler-rt/test/ubsan_bel/TestCases/implicit-signed-integer-truncation.c compiler-rt/test/ubsan_bel/TestCases/implicit-unsigned-integer-truncation.c compiler-rt/test/ubsan_bel/TestCases/nullptr-and-nonzero-offset.c compiler-rt/test/ubsan_bel/TestCases/recover-dedup-limit.cpp compiler-rt/test/ubsan_bel/TestCases/recover-dedup.cpp compiler-rt/test/ubsan_bel/TestCases/test-darwin-interface.c compiler-rt/test/ubsan_bel/TestCases/uadd-overflow.cpp compiler-rt/test/ubsan_bel/lit.common.cfg.py compiler-rt/test/ubsan_bel/lit.site.cfg.py.in
Index: compiler-rt/test/ubsan_bel/lit.site.cfg.py.in =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/lit.site.cfg.py.in @@ -0,0 +1,11 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.target_cflags = "@UBSAN_TEST_TARGET_CFLAGS@" +config.target_arch = "@UBSAN_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/lit.common.cfg.py") Index: compiler-rt/test/ubsan_bel/lit.common.cfg.py =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/lit.common.cfg.py @@ -0,0 +1,40 @@ +# -*- Python -*- + +import os + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if attr_value == None: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg.py " % attr_name) + return attr_value + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) +config.name = 'UBSan-Bel-' + config.target_arch + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +target_cflags = [get_required_attr(config, "target_cflags")] +clang_ubsan_cflags = ["-fsanitize-bel-runtime"] + target_cflags +clang_ubsan_cxxflags = config.cxx_mode_flags + clang_ubsan_cflags + +# Define %clang and %clangxx substitutions to use in test RUN lines. +config.substitutions.append( ("%clang ", build_invocation(clang_ubsan_cflags)) ) +config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags)) ) + +# Default test suffixes. +config.suffixes = ['.c', '.cpp'] + +# Check that the host supports UndefinedBehaviorSanitizerBel tests +if config.host_os not in ['Linux', 'FreeBSD', 'NetBSD', 'Darwin', 'OpenBSD']: # TODO: Windows + config.unsupported = True + +# Don't target x86_64h if the test machine can't execute x86_64h binaries. +if '-arch x86_64h' in target_cflags and 'x86_64h' not in config.available_features: + config.unsupported = True + +config.available_features.add('arch=' + config.target_arch) Index: compiler-rt/test/ubsan_bel/TestCases/uadd-overflow.cpp =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/uadd-overflow.cpp @@ -0,0 +1,10 @@ +// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=all %s -o %t && not --crash %run %t 2>&1 | FileCheck %s + +#include <stdint.h> + +int main() { + uint32_t k = 0x87654321; + k += 0xedcba987; + // CHECK: add-overflow +} Index: compiler-rt/test/ubsan_bel/TestCases/test-darwin-interface.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/test-darwin-interface.c @@ -0,0 +1,16 @@ +// Check that the ubsan and ubsan-minimal runtimes have the same symbols, +// making exceptions as necessary. +// +// REQUIRES: x86_64-darwin + +// RUN: nm -jgU `%clangxx -fsanitize-minimal-runtime -fsanitize=undefined %s -o %t '-###' 2>&1 | grep "libclang_rt.ubsan_minimal_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.ubsan_minimal_osx_dynamic.dylib\)".*/\1/'` | grep "^___ubsan_handle" \ +// RUN: | sed 's/_minimal//g' \ +// RUN: > %t.minimal.symlist +// +// RUN: nm -jgU `%clangxx -fno-sanitize-minimal-runtime -fsanitize=undefined %s -o %t '-###' 2>&1 | grep "libclang_rt.ubsan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.ubsan_osx_dynamic.dylib\)".*/\1/'` | grep "^___ubsan_handle" \ +// RUN: | grep -vE "^___ubsan_handle_dynamic_type_cache_miss" \ +// RUN: | grep -vE "^___ubsan_handle_cfi_bad_type" \ +// RUN: | sed 's/_v1//g' \ +// RUN: > %t.full.symlist +// +// RUN: diff %t.minimal.symlist %t.full.symlist Index: compiler-rt/test/ubsan_bel/TestCases/recover-dedup.cpp =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/recover-dedup.cpp @@ -0,0 +1,39 @@ +// RUN: %clangxx -w -fsanitize=signed-integer-overflow,nullability-return,returns-nonnull-attribute -fsanitize-recover=all %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <stdint.h> +#include <stdio.h> + +int *_Nonnull h() { + // CHECK: nullability-return + return NULL; +} + +__attribute__((returns_nonnull)) +int *i() { + // CHECK: nonnull-return + return NULL; +} + +__attribute__((noinline)) +int f(int x, int y) { + // CHECK: mul-overflow + return x * y; +} + +__attribute__((noinline)) +int g(int x, int y) { + // CHECK: mul-overflow + return x * (y + 1); +} + +int main() { + h(); + i(); + int x = 2; + for (int i = 0; i < 10; ++i) + x = f(x, x); + x = 2; + for (int i = 0; i < 10; ++i) + x = g(x, x); + // CHECK-NOT: mul-overflow +} Index: compiler-rt/test/ubsan_bel/TestCases/recover-dedup-limit.cpp =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/recover-dedup-limit.cpp @@ -0,0 +1,41 @@ +// RUN: %clangxx -fsanitize=signed-integer-overflow -fsanitize-recover=all %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <stdint.h> + +#define OVERFLOW \ + x = 0x7FFFFFFE; \ + x += __LINE__ + +int main() { + int32_t x; + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + OVERFLOW; // CHECK: add-overflow + + // CHECK-NOT: add-overflow + OVERFLOW; // CHECK: too many errors + // CHECK-NOT: add-overflow + OVERFLOW; + OVERFLOW; + OVERFLOW; +} Index: compiler-rt/test/ubsan_bel/TestCases/nullptr-and-nonzero-offset.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/nullptr-and-nonzero-offset.c @@ -0,0 +1,22 @@ +// RUN: %clang -fsanitize=pointer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-C --implicit-check-not="pointer-overflow" +// RUN: %clangxx -fsanitize=pointer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-CPP --implicit-check-not="pointer-overflow" + +#include <stdlib.h> + +int main(int argc, char *argv[]) { + char *base, *result; + + base = (char *)0; + result = base + 0; + // CHECK-C: pointer-overflow + + base = (char *)0; + result = base + 1; + // CHECK: pointer-overflow + + base = (char *)1; + result = base - 1; + // CHECK: pointer-overflow + + return 0; +} Index: compiler-rt/test/ubsan_bel/TestCases/implicit-unsigned-integer-truncation.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/implicit-unsigned-integer-truncation.c @@ -0,0 +1,25 @@ +// RUN: %clang -fsanitize=implicit-unsigned-integer-truncation %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include <stdint.h> + +int main() { +// CHECK-NOT: implicit-conversion + + // Negative tests. Even if they produce unexpected results, this sanitizer does not care. + int8_t n0 = (~((uint32_t)(0))); // ~0 -> -1, but do not warn. + uint8_t n2 = 128; + uint8_t n3 = 255; + // Bools do not count + _Bool b0 = (~((uint32_t)(0))); + _Bool b1 = 255; + + // Explicit and-ing of bits will silence it. + uint8_t nc0 = ((~((uint32_t)(0))) & 255); + + // Positive tests. + uint8_t t0 = (~((uint32_t)(0))); +// CHECK: implicit-conversion +// CHECK-NOT: implicit-conversion + + return 0; +} Index: compiler-rt/test/ubsan_bel/TestCases/implicit-signed-integer-truncation.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/implicit-signed-integer-truncation.c @@ -0,0 +1,25 @@ +// RUN: %clang -fsanitize=implicit-signed-integer-truncation %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include <stdint.h> + +int main() { +// CHECK-NOT: implicit-conversion + + // Negative tests. Even if they produce unexpected results, this sanitizer does not care. + int8_t n0 = (~((uint32_t)(0))); // ~0 -> -1, but do not warn. + uint8_t n2 = 128; + uint8_t n3 = 255; + // Bools do not count + _Bool b0 = (~((uint32_t)(0))); + _Bool b1 = 255; + + // Explicit and-ing of bits will silence it. + uint8_t nc0 = ((int32_t)(-1)) & 255; + + // Positive tests. + uint8_t t0 = (int32_t)(-1); +// CHECK: implicit-conversion +// CHECK-NOT: implicit-conversion + + return 0; +} Index: compiler-rt/test/ubsan_bel/TestCases/implicit-signed-integer-truncation-or-sign-change.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/implicit-signed-integer-truncation-or-sign-change.c @@ -0,0 +1,17 @@ +// RUN: %clang -fsanitize=implicit-signed-integer-truncation,implicit-integer-sign-change %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include <stdint.h> + +int main() { +// CHECK-NOT: implicit-conversion + + // Explicitly casting hides it, + int8_t n0 = (int8_t)((uint32_t)-1); + + // Positive tests. + int8_t t0 = (uint32_t)-1; +// CHECK: implicit-conversion +// CHECK-NOT: implicit-conversion + + return 0; +} Index: compiler-rt/test/ubsan_bel/TestCases/implicit-integer-sign-change.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/implicit-integer-sign-change.c @@ -0,0 +1,17 @@ +// RUN: %clang -fsanitize=implicit-integer-sign-change %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include <stdint.h> + +int main() { +// CHECK-NOT: implicit-conversion + + // Explicitly casting hides it, + int32_t n0 = (int32_t)(~((uint32_t)0)); + + // Positive tests. + int32_t t0 = (~((uint32_t)0)); +// CHECK: implicit-conversion +// CHECK-NOT: implicit-conversion + + return 0; +} Index: compiler-rt/test/ubsan_bel/TestCases/alignment-assumption.c =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/TestCases/alignment-assumption.c @@ -0,0 +1,17 @@ +// RUN: %clang -fsanitize=alignment %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK + +#include <stdlib.h> + +int main(int argc, char* argv[]) { +// CHECK-NOT: alignment-assumption + +char *ptr = (char *)malloc(2); + +__builtin_assume_aligned(ptr + 1, 0x8000); +// CHECK: alignment-assumption +// CHECK-NOT: alignment-assumption + +free(ptr); + +return 0; +} Index: compiler-rt/test/ubsan_bel/CMakeLists.txt =================================================================== --- /dev/null +++ compiler-rt/test/ubsan_bel/CMakeLists.txt @@ -0,0 +1,26 @@ +set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(UBSAN_TEST_ARCH ${UBSAN_SUPPORTED_ARCH}) +if(APPLE) + darwin_filter_host_archs(UBSAN_SUPPORTED_ARCH UBSAN_TEST_ARCH) +endif() + +set(UBSAN_TESTSUITES) +set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND UBSAN_TEST_DEPS ubsan-bel) +endif() + +foreach(arch ${UBSAN_TEST_ARCH}) + get_test_cc_for_arch(${arch} UBSAN_TEST_TARGET_CC UBSAN_TEST_TARGET_CFLAGS) + set(CONFIG_NAME ${arch}) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg.py) + list(APPEND UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +add_lit_testsuite(check-ubsan-bel "Running UndefinedBehaviorSanitizerBel tests" + ${UBSAN_TESTSUITES} + DEPENDS ${UBSAN_TEST_DEPS}) +set_target_properties(check-ubsan-bel PROPERTIES FOLDER "Compiler-RT Misc") Index: compiler-rt/lib/ubsan_bel/ubsan_bel_handlers.cpp =================================================================== --- /dev/null +++ compiler-rt/lib/ubsan_bel/ubsan_bel_handlers.cpp @@ -0,0 +1,158 @@ +//===-- ubsan_bel_handlers.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Entry points for the UBSan ␇ runtime. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_atomic.h" +#include "sanitizer_common/sanitizer_platform.h" + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <random> + +static void message(const char *msg, void *address = nullptr) { +#if SANITIZER_MAC + auto quip = []() { + static const char *quips[] = { + "I'm so sorry", + "Maybe running the program again will avoid the problem next time", + "That sounds pretty bad", + "This must have hurt", + "Please stop", + "Did you have to?", + "I bet you didn't know this particular thing was undefined!", + "Why would you even do this?", + "Wow, that was a sweet jump!", + "This Is Just To Say: I have optimized out the statements that were in the program and which you were probably saving for correctness. Forgive me, they were delicious. So undefined, and so fast", + "Now go away or I shall taunt you a second time", + "Explain to me again how sheep's bladders may be employed to prevent earthquakes", + "You sons of silly persons", + }; + static std::random_device r; + static std::default_random_engine e(r()); + static std::uniform_int_distribution<int> d(0, sizeof(quips) / sizeof(quips[0]) - 1); + return quips[d(e)]; + }; + char buf[2048] = { '\0' }; + size_t pos = 0; + const size_t end = sizeof(buf) / sizeof(buf[0]) - 1; + auto cp = [&] (const char *what) { + while (*what && pos < end) + buf[pos++] = *what++; + }; + cp("say \"Undefined Behavior "); + cp(msg); + if (address && (pos + 28 < end)) { + cp(" at address "); + pos += sprintf(&buf[pos], "%16llx", (uint64_t)address); + } + cp("... "); + cp(quip()); + cp("\""); + system(buf); +#else + // Plain Old Bell (POB). + (void)msg; + write(2, "\a", strlen("\a")); +#endif +} + +static const int kMaxCallerPcs = 20; +static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; +static __sanitizer::atomic_uint32_t caller_pcs_sz; + +__attribute__((noinline)) static bool report_this_error(void *caller_p) { + uintptr_t caller = reinterpret_cast<uintptr_t>(caller_p); + if (caller == 0) return false; + while (true) { + unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz); + if (sz > kMaxCallerPcs) return false; + if (sz > 0 && sz < kMaxCallerPcs) { + uintptr_t p; + for (unsigned i = 0; i < sz; ++i) { + p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]); + if (p == 0) break; // Concurrent update. + if (p == caller) return false; + } + if (p == 0) continue; + } + + if (!__sanitizer::atomic_compare_exchange_strong( + &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst)) + continue; + + if (sz == kMaxCallerPcs) { + message("is over 9000, there's no way that could be right"); +#if SANITIZER_MAC + system("open https://www.youtube.com/watch?v=SiMHTK15Pik"); +#endif + return false; + } + __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller); + return true; + } +} + +#if SANITIZER_DEBUG +namespace __sanitizer { +// The DCHECK macro needs this symbol to be defined. +void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { + message("Sanitizer CHECK failed: "); + message(file); + message(":?? : "); // FIXME: Show line number. + message(cond); + abort(); +} +} // namespace __sanitizer +#endif + +#define INTERFACE extern "C" __attribute__((visibility("default"))) + +#define HANDLER_RECOVER(name, msg) \ + INTERFACE void __ubsan_handle_##name##_bel() { \ + if (!report_this_error(__builtin_return_address(0))) return; \ + message(msg, __builtin_return_address(0)); \ + } + +#define HANDLER_NORECOVER(name, msg) \ + INTERFACE void __ubsan_handle_##name##_bel_abort() { \ + message(msg, __builtin_return_address(0)); \ + abort(); \ + } + +#define HANDLER(name, msg) \ + HANDLER_RECOVER(name, msg) \ + HANDLER_NORECOVER(name, msg) + +HANDLER(type_mismatch, "type mismatch") +HANDLER(alignment_assumption, "alignment assumption") +HANDLER(add_overflow, "add overflow") +HANDLER(sub_overflow, "subtraction overflow") +HANDLER(mul_overflow, "multiplication overflow") +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_RECOVER(builtin_unreachable, "builtin unreachable") +HANDLER_RECOVER(missing_return, "missing return") +HANDLER(vla_bound_not_positive, "variable length array bound not positive") +HANDLER(float_cast_overflow, "float cast overflow") +HANDLER(load_invalid_value, "load invalid value") +HANDLER(invalid_builtin, "invalid builtin") +HANDLER(function_type_mismatch, "function type mismatch") +HANDLER(implicit_conversion, "implicit conversion") +HANDLER(nonnull_arg, "non-null argument") +HANDLER(nonnull_return, "non-null return") +HANDLER(nullability_arg, "nullability argument") +HANDLER(nullability_return, "nullability return") +HANDLER(pointer_overflow, "pointer overflow") +HANDLER(cfi_check_fail, "control flow integrity check fail") Index: compiler-rt/lib/ubsan_bel/ubsan.syms.extra =================================================================== --- /dev/null +++ compiler-rt/lib/ubsan_bel/ubsan.syms.extra @@ -0,0 +1 @@ +__ubsan_* Index: compiler-rt/lib/ubsan_bel/CMakeLists.txt =================================================================== --- /dev/null +++ compiler-rt/lib/ubsan_bel/CMakeLists.txt @@ -0,0 +1,53 @@ +# Build for the bel undefined behavior sanitizer runtime support library. + +set(UBSAN_BEL_SOURCES + ubsan_bel_handlers.cpp + ) + +include_directories(..) + +set(UBSAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF UBSAN_CFLAGS) + +set(UBSAN_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) + +set(UBSAN_DYNAMIC_LIBS ${SANITIZER_COMMON_LINK_LIBS}) + +add_compiler_rt_component(ubsan-bel) + +# Common parts of bel UBSan runtime. +add_compiler_rt_object_libraries(RTUbsan_bel + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${UBSAN_COMMON_SUPPORTED_ARCH} + SOURCES ${UBSAN_BEL_SOURCES} CFLAGS ${UBSAN_CFLAGS}) + + +if(COMPILER_RT_HAS_UBSAN_BEL) + # Standalone bel UBSan runtimes. + add_compiler_rt_runtime(clang_rt.ubsan_bel + STATIC + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan_bel + CFLAGS ${UBSAN_CFLAGS} + PARENT_TARGET ubsan-bel) + + add_compiler_rt_runtime(clang_rt.ubsan_bel + SHARED + OS ${SANITIZER_COMMON_SUPPORTED_OS} + ARCHS ${UBSAN_SUPPORTED_ARCH} + OBJECT_LIBS RTUbsan_bel + CFLAGS ${UBSAN_CFLAGS} + LINK_FLAGS ${UBSAN_LINK_FLAGS} + LINK_LIBS ${UBSAN_DYNAMIC_LIBS} + PARENT_TARGET ubsan-bel) + + if (SANITIZER_USE_SYMBOLS AND NOT APPLE) + set(ARCHS_FOR_SYMBOLS ${UBSAN_SUPPORTED_ARCH}) + list(REMOVE_ITEM ARCHS_FOR_SYMBOLS i386 i686) + add_sanitizer_rt_symbols(clang_rt.ubsan_bel + ARCHS ${ARCHS_FOR_SYMBOLS} + PARENT_TARGET ubsan-bel + EXTRA ubsan.syms.extra) + endif() +endif() Index: compiler-rt/cmake/config-ix.cmake =================================================================== --- compiler-rt/cmake/config-ix.cmake +++ compiler-rt/cmake/config-ix.cmake @@ -615,7 +615,7 @@ endif() message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}") -set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo;ubsan_minimal;gwp_asan) +set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo;ubsan_minimal;ubsan_bel;gwp_asan) set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})") list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}") @@ -708,8 +708,10 @@ if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux|FreeBSD|NetBSD|OpenBSD|Android|Darwin") set(COMPILER_RT_HAS_UBSAN_MINIMAL TRUE) + set(COMPILER_RT_HAS_UBSAN_BEL TRUE) else() set(COMPILER_RT_HAS_UBSAN_MINIMAL FALSE) + set(COMPILER_RT_HAS_UBSAN_BEL FALSE) endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND SAFESTACK_SUPPORTED_ARCH AND Index: clang/test/Driver/sanitizer-ld.c =================================================================== --- clang/test/Driver/sanitizer-ld.c +++ clang/test/Driver/sanitizer-ld.c @@ -374,6 +374,21 @@ // CHECK-UBSAN-MINIMAL-DARWIN: "{{.*}}ld{{(.exe)?}}" // CHECK-UBSAN-MINIMAL-DARWIN: "{{.*}}libclang_rt.ubsan_minimal_osx_dynamic.dylib" +// RUN: %clang -fsanitize=undefined -fsanitize-bel-runtime %s -### -o %t.o 2>&1 \ +// RUN: -target i386-unknown-linux -fuse-ld=ld \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-UBSAN-BEL-LINUX %s +// CHECK-UBSAN-BEL-LINUX: "{{.*}}ld{{(.exe)?}}" +// CHECK-UBSAN-BEL-LINUX: "--whole-archive" "{{.*}}libclang_rt.ubsan_bel-i386.a" "--no-whole-archive" +// CHECK-UBSAN-BEL-LINUX: "-lpthread" + +// RUN: %clang -fsanitize=undefined -fsanitize-bel-runtime %s -### -o %t.o 2>&1 \ +// RUN: -target x86_64-apple-darwin -fuse-ld=ld \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-UBSAN-BEL-DARWIN %s +// CHECK-UBSAN-BEL-DARWIN: "{{.*}}ld{{(.exe)?}}" +// CHECK-UBSAN-BEL-DARWIN: "{{.*}}libclang_rt.ubsan_bel_osx_dynamic.dylib" + // RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \ // RUN: -target x86_64-apple-darwin -fuse-ld=ld -static-libsan \ // RUN: --sysroot=%S/Inputs/basic_linux_tree \ @@ -745,6 +760,15 @@ // CHECK-SCUDO-MINIMAL-LINUX: "--whole-archive" "{{.*}}libclang_rt.scudo_minimal-i386.a" "--no-whole-archive" // CHECK-SCUDO-MINIMAL-LINUX: "-lpthread" +// RUN: %clang -fsanitize=scudo -fsanitize-bel-runtime %s -### -o %t.o 2>&1 \ +// RUN: -target i386-unknown-linux -fuse-ld=ld \ +// RUN: --sysroot=%S/Inputs/basic_linux_tree \ +// RUN: | FileCheck --check-prefix=CHECK-SCUDO-BEL-LINUX %s +// CHECK-SCUDO-BEL-LINUX: "{{.*}}ld{{(.exe)?}}" +// CHECK-SCUDO-BEL-LINUX: "-pie" +// CHECK-SCUDO-BEL-LINUX: "--whole-archive" "{{.*}}libclang_rt.scudo_bel-i386.a" "--no-whole-archive" +// CHECK-SCUDO-BEL-LINUX: "-lpthread" + // RUN: %clang -no-canonical-prefixes %s -### -o %t.so -shared 2>&1 \ // RUN: -target i386-unknown-linux -fuse-ld=ld -fsanitize=scudo -shared-libsan \ // RUN: -resource-dir=%S/Inputs/resource_dir \ Index: clang/test/Driver/fsanitize.c =================================================================== --- clang/test/Driver/fsanitize.c +++ clang/test/Driver/fsanitize.c @@ -809,6 +809,44 @@ // CHECK-SCS-MINIMAL: "-fsanitize=shadow-call-stack" // CHECK-SCS-MINIMAL: "-fsanitize-minimal-runtime" +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-BEL +// CHECK-ASAN-BEL: error: invalid argument '-fsanitize-bel-runtime' not allowed with '-fsanitize=address' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-BEL +// CHECK-TSAN-BEL: error: invalid argument '-fsanitize-bel-runtime' not allowed with '-fsanitize=thread' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-BEL +// CHECK-UBSAN-BEL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){17}"}} +// CHECK-UBSAN-BEL: "-fsanitize-bel-runtime" + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize=function -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-FUNCTION-BEL +// CHECK-UBSAN-FUNCTION-BEL: error: invalid argument '-fsanitize=function' not allowed with '-fsanitize-bel-runtime' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fsanitize=vptr -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-VPTR-BEL +// CHECK-UBSAN-VPTR-BEL: error: invalid argument '-fsanitize=vptr' not allowed with '-fsanitize-bel-runtime' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-bel-runtime -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-UBSAN-BEL +// CHECK-ASAN-UBSAN-BEL: error: invalid argument '-fsanitize-bel-runtime' not allowed with '-fsanitize=address' +// RUN: %clang -target x86_64-linux-gnu -fsanitize=hwaddress -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-HWASAN-BEL +// CHECK-HWASAN-BEL: error: invalid argument '-fsanitize-bel-runtime' not allowed with '-fsanitize=hwaddress' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -flto -fvisibility=hidden -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-BEL +// CHECK-CFI-BEL: "-fsanitize=cfi-derived-cast,cfi-icall,cfi-mfcall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall" +// CHECK-CFI-BEL: "-fsanitize-trap=cfi-derived-cast,cfi-icall,cfi-mfcall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall" +// CHECK-CFI-BEL: "-fsanitize-bel-runtime" + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fno-sanitize-trap=cfi-icall -flto -fvisibility=hidden -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOTRAP-BEL +// CHECK-CFI-NOTRAP-BEL: error: invalid argument 'fsanitize-bel-runtime' only allowed with 'fsanitize-trap=cfi' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fno-sanitize-trap=cfi-icall -fno-sanitize=cfi-icall -flto -fvisibility=hidden -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-NOICALL-BEL +// CHECK-CFI-NOICALL-BEL: "-fsanitize=cfi-derived-cast,cfi-mfcall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall" +// CHECK-CFI-NOICALL-BEL: "-fsanitize-trap=cfi-derived-cast,cfi-mfcall,cfi-unrelated-cast,cfi-nvcall,cfi-vcall" +// CHECK-CFI-NOICALL-BEL: "-fsanitize-bel-runtime" + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=shadow-call-stack -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCS-BEL +// CHECK-SCS-BEL: "-fsanitize=shadow-call-stack" +// CHECK-SCS-BEL: "-fsanitize-bel-runtime" + // RUN: %clang -target aarch64-linux-gnu -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO // RUN: %clang -target arm-linux-androideabi -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO // RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO @@ -837,6 +875,14 @@ // CHECK-SCUDO-UBSAN-MINIMAL: "-fsanitize={{.*}}scudo" // CHECK-SCUDO-UBSAN-MINIMAL: "-fsanitize-minimal-runtime" +// RUN: %clang -target x86_64-linux-gnu -fsanitize=scudo -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-BEL +// CHECK-SCUDO-BEL: "-fsanitize=scudo" +// CHECK-SCUDO-BEL: "-fsanitize-bel-runtime" + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined,scudo -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SCUDO-UBSAN-BEL +// CHECK-SCUDO-UBSAN-BEL: "-fsanitize={{.*}}scudo" +// CHECK-SCUDO-UBSAN-BEL: "-fsanitize-bel-runtime" + // RUN: %clang -target powerpc-unknown-linux -fsanitize=scudo %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SCUDO // CHECK-NO-SCUDO: unsupported option @@ -886,5 +932,8 @@ // RUN: %clang -fsanitize=float-divide-by-zero -fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-DIVBYZERO,CHECK-DIVBYZERO-MINIMAL // CHECK-DIVBYZERO-MINIMAL: "-fsanitize-minimal-runtime" +// RUN: %clang -fsanitize=float-divide-by-zero -fsanitize-bel-runtime %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-DIVBYZERO,CHECK-DIVBYZERO-BEL +// CHECK-DIVBYZERO-BEL: "-fsanitize-bel-runtime" + // RUN: %clang -fsanitize=undefined,float-divide-by-zero %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-DIVBYZERO-UBSAN // CHECK-DIVBYZERO-UBSAN: "-fsanitize={{.*}},float-divide-by-zero,{{.*}}" Index: clang/test/CodeGen/unsigned-overflow-bel.c =================================================================== --- /dev/null +++ clang/test/CodeGen/unsigned-overflow-bel.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsanitize=unsigned-integer-overflow -fsanitize-bel-runtime %s -emit-llvm -o - | FileCheck %s + +unsigned long li, lj, lk; + +// CHECK-LABEL: define void @testlongadd() +void testlongadd() { + // CHECK: call void @__ubsan_handle_add_overflow_bel_abort() + li = lj + lk; +} + +// CHECK-LABEL: define void @testlongsub() +void testlongsub() { + // CHECK: call void @__ubsan_handle_sub_overflow_bel_abort() + li = lj - lk; +} + +// CHECK-LABEL: define void @testlongmul() +void testlongmul() { + // CHECK: call void @__ubsan_handle_mul_overflow_bel_abort() + li = lj * lk; +} Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1184,6 +1184,7 @@ OPT_fno_sanitize_memory_use_after_dtor, false); Opts.SanitizeMinimalRuntime = Args.hasArg(OPT_fsanitize_minimal_runtime); + Opts.SanitizeBelRuntime = Args.hasArg(OPT_fsanitize_bel_runtime); Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso); Opts.SanitizeCfiICallGeneralizePointers = Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers); Index: clang/lib/Driver/ToolChains/CommonArgs.cpp =================================================================== --- clang/lib/Driver/ToolChains/CommonArgs.cpp +++ clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -635,12 +635,16 @@ if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) SharedRuntimes.push_back("ubsan_minimal"); + else if (SanArgs.requiresBelRuntime()) + SharedRuntimes.push_back("ubsan_bel"); else SharedRuntimes.push_back("ubsan_standalone"); } if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) SharedRuntimes.push_back("scudo_minimal"); + else if (SanArgs.requiresBelRuntime()) + SharedRuntimes.push_back("scudo_bel"); else SharedRuntimes.push_back("scudo"); } @@ -689,6 +693,8 @@ if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) { if (SanArgs.requiresMinimalRuntime()) { StaticRuntimes.push_back("ubsan_minimal"); + } else if (SanArgs.requiresBelRuntime()) { + StaticRuntimes.push_back("ubsan_bel"); } else { StaticRuntimes.push_back("ubsan_standalone"); if (SanArgs.linkCXXRuntimes()) @@ -717,6 +723,10 @@ StaticRuntimes.push_back("scudo_minimal"); if (SanArgs.linkCXXRuntimes()) StaticRuntimes.push_back("scudo_cxx_minimal"); + } else if (SanArgs.requiresBelRuntime()) { + StaticRuntimes.push_back("scudo_bel"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_cxx_bel"); } else { StaticRuntimes.push_back("scudo"); if (SanArgs.linkCXXRuntimes()) Index: clang/lib/Driver/SanitizerArgs.cpp =================================================================== --- clang/lib/Driver/SanitizerArgs.cpp +++ clang/lib/Driver/SanitizerArgs.cpp @@ -33,6 +33,8 @@ static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr; static const SanitizerMask NotAllowedWithMinimalRuntime = SanitizerKind::Function | SanitizerKind::Vptr; +static const SanitizerMask NotAllowedWithBelRuntime = + SanitizerKind::Function | SanitizerKind::Vptr; static const SanitizerMask RequiresPIE = SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo; static const SanitizerMask NeedsUnwindTables = @@ -71,6 +73,8 @@ SanitizerKind::CFIUnrelatedCast; static const SanitizerMask CompatibleWithMinimalRuntime = TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack; +static const SanitizerMask CompatibleWithBelRuntime = + TrappingSupported | SanitizerKind::Scudo | SanitizerKind::ShadowCallStack; enum CoverageFeature { CoverageFunc = 1 << 0, @@ -209,7 +213,7 @@ // All of these include ubsan. if (needsAsanRt() || needsMsanRt() || needsHwasanRt() || needsTsanRt() || needsDfsanRt() || needsLsanRt() || needsCfiDiagRt() || - (needsScudoRt() && !requiresMinimalRuntime())) + (needsScudoRt() && !requiresMinimalRuntime() && !requiresBelRuntime())) return false; return (Sanitizers.Mask & NeedsUbsanRt & ~TrapSanitizers.Mask) || @@ -266,6 +270,10 @@ Args.hasFlag(options::OPT_fsanitize_minimal_runtime, options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); + BelRuntime = + Args.hasFlag(options::OPT_fsanitize_bel_runtime, + options::OPT_fno_sanitize_bel_runtime, BelRuntime); + // The object size sanitizer should not be enabled at -O0. Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); bool RemoveObjectSizeAtO0 = @@ -315,6 +323,17 @@ Add &= ~NotAllowedWithMinimalRuntime; } + if (BelRuntime) { + if (SanitizerMask KindsToDiagnose = + Add & NotAllowedWithBelRuntime & ~DiagnosedKinds) { + std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << "-fsanitize-bel-runtime"; + DiagnosedKinds |= KindsToDiagnose; + } + Add &= ~NotAllowedWithBelRuntime; + } + // FIXME: Make CFI on member function calls compatible with cross-DSO CFI. // There are currently two problems: // - Virtual function call checks need to pass a pointer to the function @@ -371,6 +390,9 @@ if (MinimalRuntime) { Add &= ~NotAllowedWithMinimalRuntime; } + if (BelRuntime) { + Add &= ~NotAllowedWithBelRuntime; + } if (CfiCrossDso) Add &= ~SanitizerKind::CFIMFCall; Add &= Supported; @@ -668,6 +690,21 @@ << "fsanitize-trap=cfi"; } + if (BelRuntime) { + SanitizerMask IncompatibleMask = + Kinds & ~setGroupBits(CompatibleWithBelRuntime); + if (IncompatibleMask) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-bel-runtime" + << lastArgumentForMask(D, Args, IncompatibleMask); + + SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds; + if (NonTrappingCfi) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "fsanitize-bel-runtime" + << "fsanitize-trap=cfi"; + } + // Parse -f(no-)?sanitize-coverage flags if coverage is supported by the // enabled sanitizers. for (const auto *Arg : Args) { @@ -1010,6 +1047,9 @@ if (MinimalRuntime) CmdArgs.push_back("-fsanitize-minimal-runtime"); + if (BelRuntime) + CmdArgs.push_back("-fsanitize-bel-runtime"); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + Twine(AsanFieldPadding))); Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -3014,13 +3014,16 @@ bool NeedsAbortSuffix = IsFatal && RecoverKind != CheckRecoverableKind::Unrecoverable; bool MinimalRuntime = CGF.CGM.getCodeGenOpts().SanitizeMinimalRuntime; + bool BelRuntime = CGF.CGM.getCodeGenOpts().SanitizeBelRuntime; const SanitizerHandlerInfo &CheckInfo = SanitizerHandlers[CheckHandler]; const StringRef CheckName = CheckInfo.Name; std::string FnName = "__ubsan_handle_" + CheckName.str(); - if (CheckInfo.Version && !MinimalRuntime) + if (CheckInfo.Version && !MinimalRuntime && !BelRuntime) FnName += "_v" + llvm::utostr(CheckInfo.Version); if (MinimalRuntime) FnName += "_minimal"; + if (BelRuntime) + FnName += "_bel"; if (NeedsAbortSuffix) FnName += "_abort"; bool MayReturn = @@ -3109,7 +3112,7 @@ // representing operand values. SmallVector<llvm::Value *, 4> Args; SmallVector<llvm::Type *, 4> ArgTypes; - if (!CGM.getCodeGenOpts().SanitizeMinimalRuntime) { + if (!(CGM.getCodeGenOpts().SanitizeMinimalRuntime || CGM.getCodeGenOpts().SanitizeBelRuntime)) { Args.reserve(DynamicArgs.size() + 1); ArgTypes.reserve(DynamicArgs.size() + 1); Index: clang/include/clang/Driver/SanitizerArgs.h =================================================================== --- clang/include/clang/Driver/SanitizerArgs.h +++ clang/include/clang/Driver/SanitizerArgs.h @@ -51,6 +51,7 @@ bool TsanFuncEntryExit = true; bool TsanAtomics = true; bool MinimalRuntime = false; + bool BelRuntime = false; // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; @@ -74,6 +75,7 @@ } bool needsUbsanRt() const; bool requiresMinimalRuntime() const { return MinimalRuntime; } + bool requiresBelRuntime() const { return BelRuntime; } bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); } bool needsSafeStackRt() const { return SafeStackRuntime; } bool needsCfiRt() const; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1096,6 +1096,8 @@ Group<f_clang_Group>; def fno_sanitize_minimal_runtime : Flag<["-"], "fno-sanitize-minimal-runtime">, Group<f_clang_Group>; +def fsanitize_bel_runtime : Flag<["-"], "fsanitize-bel-runtime">, Group<f_clang_Group>; +def fno_sanitize_bel_runtime : Flag<["-"], "fno-sanitize-bel-runtime">, Group<f_clang_Group>; def fsanitize_link_runtime : Flag<["-"], "fsanitize-link-runtime">, Group<f_clang_Group>; def fno_sanitize_link_runtime : Flag<["-"], "fno-sanitize-link-runtime">, Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -209,6 +209,7 @@ CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI. CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime for ///< diagnostics. +CODEGENOPT(SanitizeBelRuntime, 1, 0) ///< Use "_bel" sanitizer runtime for diagnostics. CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in ///< CFI icall function signatures CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical Index: clang/docs/UndefinedBehaviorSanitizer.rst =================================================================== --- clang/docs/UndefinedBehaviorSanitizer.rst +++ clang/docs/UndefinedBehaviorSanitizer.rst @@ -214,6 +214,28 @@ ``-fsanitize=undefined``, you could enable the minimal runtime with ``-fsanitize=undefined -fsanitize-minimal-runtime``. +␇ Runtime +========= + +There is a ␇ UBSan runtime available. It is named in honor of Bell Labs (who +gave us the C programming language and Undefined Behavior), the ASCII "bell" +character (value `07`), and famed violinist Joshua Bell. It is not related to +the city of Bell in California. This runtime will emit sound, most traditionally +the terminal's bell sound, when undefined behavior occurs. + +To use the minimal runtime, add ``-fsanitize-bel-runtime`` to the clang command +line options. For example, if you're used to compiling with +``-fsanitize=undefined``, you could enable the minimal runtime with +``-fsanitize=undefined -fsanitize-bel-runtime``. + +When combined with ``-fsanitize-recover=undefined``, the ␇ runtime will simply +chime on Undefined Behavior without killing the program for each chime. To avoid +Pavlovian effects, the ␇ runtime uses Advanced Compiler Techniques called +"heuristics" to avoid chiming too often at the same location. + +On macOS, the ␇ runtime will helpfully announce what specific undefined behavior +you've encountered, and then taunt you. + Stack traces and report symbolization ===================================== If you want UBSan to print symbolized stack trace for each error report, you
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits