diff options
36 files changed, 705 insertions, 199 deletions
| diff --git a/cmake/Modules/AddCompilerRT.cmake b/cmake/Modules/AddCompilerRT.cmake index d4f636857665..139b6140011c 100644 --- a/cmake/Modules/AddCompilerRT.cmake +++ b/cmake/Modules/AddCompilerRT.cmake @@ -469,7 +469,7 @@ macro(add_custom_libcxx name prefix)      message(FATAL_ERROR "libcxx not found!")    endif() -  cmake_parse_arguments(LIBCXX "" "" "DEPS;CFLAGS" ${ARGN}) +  cmake_parse_arguments(LIBCXX "" "" "DEPS;CFLAGS;CMAKE_ARGS" ${ARGN})    foreach(flag ${LIBCXX_CFLAGS})      set(flagstr "${flagstr} ${flag}")    endforeach() @@ -491,6 +491,7 @@ macro(add_custom_libcxx name prefix)                 -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>                 -DLLVM_PATH=${LLVM_MAIN_SRC_DIR}                 -DLIBCXX_STANDALONE_BUILD=On +               ${LIBCXX_CMAKE_ARGS}      LOG_BUILD 1      LOG_CONFIGURE 1      LOG_INSTALL 1 diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index ada471953663..9e0c4774829f 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -486,7 +486,7 @@ set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING  list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")  if (SANITIZER_COMMON_SUPPORTED_ARCH AND NOT LLVM_USE_SANITIZER AND -    (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia" OR +    (OS_NAME MATCHES "Android|Darwin|Linux|FreeBSD|NetBSD|Fuchsia|SunOS" OR      (OS_NAME MATCHES "Windows" AND (NOT MINGW AND NOT CYGWIN))))    set(COMPILER_RT_HAS_SANITIZER_COMMON TRUE)  else() @@ -505,7 +505,7 @@ else()    set(COMPILER_RT_HAS_ASAN FALSE)  endif() -if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD") +if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD|SunOS")    set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME TRUE)  else()    set(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME FALSE) @@ -556,7 +556,7 @@ else()  endif()  if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND -    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia") +    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia|SunOS")    set(COMPILER_RT_HAS_UBSAN TRUE)  else()    set(COMPILER_RT_HAS_UBSAN FALSE) diff --git a/include/sanitizer/allocator_interface.h b/include/sanitizer/allocator_interface.h index 2d35804b3764..89f328301db3 100644 --- a/include/sanitizer/allocator_interface.h +++ b/include/sanitizer/allocator_interface.h @@ -32,7 +32,7 @@ extern "C" {    size_t __sanitizer_get_allocated_size(const volatile void *p);    /* Number of bytes, allocated and not yet freed by the application. */ -  size_t __sanitizer_get_current_allocated_bytes(); +  size_t __sanitizer_get_current_allocated_bytes(void);    /* Number of bytes, mmaped by the allocator to fulfill allocation requests.       Generally, for request of X bytes, allocator can reserve and add to free @@ -40,17 +40,17 @@ extern "C" {       All these chunks count toward the heap size. Currently, allocator never       releases memory to OS (instead, it just puts freed chunks to free       lists). */ -  size_t __sanitizer_get_heap_size(); +  size_t __sanitizer_get_heap_size(void);    /* Number of bytes, mmaped by the allocator, which can be used to fulfill       allocation requests. When a user program frees memory chunk, it can first       fall into quarantine and will count toward __sanitizer_get_free_bytes()       later. */ -  size_t __sanitizer_get_free_bytes(); +  size_t __sanitizer_get_free_bytes(void);    /* Number of bytes in unmapped pages, that are released to OS. Currently,       always returns 0. */ -  size_t __sanitizer_get_unmapped_bytes(); +  size_t __sanitizer_get_unmapped_bytes(void);    /* Malloc hooks that may be optionally provided by user.       __sanitizer_malloc_hook(ptr, size) is called immediately after @@ -81,7 +81,7 @@ extern "C" {       resources in attempt to reduce process RSS.       Currently available with ASan only.    */ -  void __sanitizer_purge_allocator(); +  void __sanitizer_purge_allocator(void);  #ifdef __cplusplus  }  // extern "C" diff --git a/include/sanitizer/asan_interface.h b/include/sanitizer/asan_interface.h index e689a730e2c3..f2d77143b931 100644 --- a/include/sanitizer/asan_interface.h +++ b/include/sanitizer/asan_interface.h @@ -64,19 +64,19 @@ extern "C" {    // Useful for calling from a debugger to get information about an ASan error.    // Returns 1 if an error has been (or is being) reported, otherwise returns 0. -  int __asan_report_present(); +  int __asan_report_present(void);    // Useful for calling from a debugger to get information about an ASan error.    // If an error has been (or is being) reported, the following functions return    // the pc, bp, sp, address, access type (0 = read, 1 = write), access size and    // bug description (e.g. "heap-use-after-free"). Otherwise they return 0. -  void *__asan_get_report_pc(); -  void *__asan_get_report_bp(); -  void *__asan_get_report_sp(); -  void *__asan_get_report_address(); -  int __asan_get_report_access_type(); -  size_t __asan_get_report_access_size(); -  const char *__asan_get_report_description(); +  void *__asan_get_report_pc(void); +  void *__asan_get_report_bp(void); +  void *__asan_get_report_sp(void); +  void *__asan_get_report_address(void); +  int __asan_get_report_access_type(void); +  size_t __asan_get_report_access_size(void); +  const char *__asan_get_report_description(void);    // Useful for calling from the debugger to get information about a pointer.    // Returns the category of the given pointer as a constant string. @@ -118,21 +118,21 @@ extern "C" {    // User may provide function that would be called right when ASan detects    // an error. This can be used to notice cases when ASan detects an error, but    // the program crashes before ASan report is printed. -  void __asan_on_error(); +  void __asan_on_error(void);    // Prints accumulated stats to stderr. Used for debugging. -  void __asan_print_accumulated_stats(); +  void __asan_print_accumulated_stats(void);    // This function may be optionally provided by user and should return    // a string containing ASan runtime options. See asan_flags.h for details. -  const char* __asan_default_options(); +  const char* __asan_default_options(void);    // The following 2 functions facilitate garbage collection in presence of    // asan's fake stack.    // Returns an opaque handler to be used later in __asan_addr_is_in_fake_stack.    // Returns NULL if the current thread does not have a fake stack. -  void *__asan_get_current_fake_stack(); +  void *__asan_get_current_fake_stack(void);    // If fake_stack is non-NULL and addr belongs to a fake frame in    // fake_stack, returns the address on real stack that corresponds to diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h index 4a1de968b0ee..6d4326f74021 100644 --- a/include/sanitizer/common_interface_defs.h +++ b/include/sanitizer/common_interface_defs.h @@ -115,7 +115,7 @@ extern "C" {        const void *beg, const void *mid, const void *end);    // Print the stack trace leading to this call. Useful for debugging user code. -  void __sanitizer_print_stack_trace(); +  void __sanitizer_print_stack_trace(void);    // Symbolizes the supplied 'pc' using the format string 'fmt'.    // Outputs at most 'out_buf_size' bytes into 'out_buf'. diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index 081033cec8e5..bc95a5caf82c 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -20,10 +20,10 @@ extern "C" {  #endif    // Record and dump coverage info. -  void __sanitizer_cov_dump(); +  void __sanitizer_cov_dump(void);    // Clear collected coverage info. -  void __sanitizer_cov_reset(); +  void __sanitizer_cov_reset(void);    // Dump collected coverage info. Sorts pcs by module into individual .sancov    // files. diff --git a/include/sanitizer/esan_interface.h b/include/sanitizer/esan_interface.h index 4aff8d47bbd1..c755ed330000 100644 --- a/include/sanitizer/esan_interface.h +++ b/include/sanitizer/esan_interface.h @@ -37,11 +37,11 @@ extern "C" {  // This function can be called mid-run (or at the end of a run for  // a server process that doesn't shut down normally) to request that  // data for that point in the run be reported from the tool. -void COMPILER_RT_WEAK __esan_report(); +void COMPILER_RT_WEAK __esan_report(void);  // This function returns the number of samples that the esan tool has collected  // to this point.  This is useful for testing. -unsigned int COMPILER_RT_WEAK __esan_get_sample_count(); +unsigned int COMPILER_RT_WEAK __esan_get_sample_count(void);  #ifdef __cplusplus  } // extern "C" diff --git a/include/sanitizer/hwasan_interface.h b/include/sanitizer/hwasan_interface.h index f70d87875968..0c306cf279e2 100644 --- a/include/sanitizer/hwasan_interface.h +++ b/include/sanitizer/hwasan_interface.h @@ -21,10 +21,10 @@ extern "C" {  #endif    // This function may be optionally provided by user and should return    // a string containing HWASan runtime options. See asan_flags.h for details. -  const char* __hwasan_default_options(); +  const char* __hwasan_default_options(void); -  void __hwasan_enable_allocator_tagging(); -  void __hwasan_disable_allocator_tagging(); +  void __hwasan_enable_allocator_tagging(void); +  void __hwasan_disable_allocator_tagging(void);  #ifdef __cplusplus  }  // extern "C" diff --git a/include/sanitizer/lsan_interface.h b/include/sanitizer/lsan_interface.h index e3e509ff7d9f..731b37314125 100644 --- a/include/sanitizer/lsan_interface.h +++ b/include/sanitizer/lsan_interface.h @@ -21,8 +21,8 @@ extern "C" {  #endif    // Allocations made between calls to __lsan_disable() and __lsan_enable() will    // be treated as non-leaks. Disable/enable pairs may be nested. -  void __lsan_disable(); -  void __lsan_enable(); +  void __lsan_disable(void); +  void __lsan_enable(void);    // The heap object into which p points will be treated as a non-leak.    void __lsan_ignore_object(const void *p); @@ -49,7 +49,7 @@ extern "C" {    // the time of first invocation of this function.    // By calling this function early during process shutdown, you can instruct    // LSan to ignore shutdown-only leaks which happen later on. -  void __lsan_do_leak_check(); +  void __lsan_do_leak_check(void);    // Check for leaks now. Returns zero if no leaks have been found or if leak    // detection is disabled, non-zero otherwise. @@ -58,7 +58,7 @@ extern "C" {    // terminate the process. It does not affect the behavior of    // __lsan_do_leak_check() or the end-of-process leak check, and is not    // affected by them. -  int __lsan_do_recoverable_leak_check(); +  int __lsan_do_recoverable_leak_check(void);    // The user may optionally provide this function to disallow leak checking    // for the program it is linked into (if the return value is non-zero). This @@ -66,15 +66,15 @@ extern "C" {    // that is unsupported.    // To avoid dead stripping, you may need to define this function with    // __attribute__((used)) -  int __lsan_is_turned_off(); +  int __lsan_is_turned_off(void);    // This function may be optionally provided by user and should return    // a string containing LSan runtime options. See lsan_flags.inc for details. -  const char *__lsan_default_options(); +  const char *__lsan_default_options(void);    // This function may be optionally provided by the user and should return    // a string containing LSan suppressions. -  const char *__lsan_default_suppressions(); +  const char *__lsan_default_suppressions(void);  #ifdef __cplusplus  }  // extern "C" diff --git a/include/sanitizer/msan_interface.h b/include/sanitizer/msan_interface.h index 6d6a3765241b..a87c954c15ec 100644 --- a/include/sanitizer/msan_interface.h +++ b/include/sanitizer/msan_interface.h @@ -31,10 +31,10 @@ extern "C" {    int __msan_origin_is_descendant_or_same(uint32_t this_id, uint32_t prev_id);    /* Returns non-zero if tracking origins. */ -  int __msan_get_track_origins(); +  int __msan_get_track_origins(void);    /* Returns the origin id of the latest UMR in the calling thread. */ -  uint32_t __msan_get_umr_origin(); +  uint32_t __msan_get_umr_origin(void);    /* Make memory region fully initialized (without changing its contents). */    void __msan_unpoison(const volatile void *a, size_t size); @@ -82,7 +82,7 @@ extern "C" {    void __msan_dump_shadow(const volatile void *x, size_t size);    /* Returns true if running under a dynamic tool (DynamoRio-based). */ -  int  __msan_has_dynamic_component(); +  int  __msan_has_dynamic_component(void);    /* Tell MSan about newly allocated memory (ex.: custom allocator).       Memory will be marked uninitialized, with origin at the call site. */ @@ -93,7 +93,7 @@ extern "C" {    /* This function may be optionally provided by user and should return       a string containing Msan runtime options. See msan_flags.h for details. */ -  const char* __msan_default_options(); +  const char* __msan_default_options(void);    /* Deprecated. Call __sanitizer_set_death_callback instead. */    void __msan_set_death_callback(void (*callback)(void)); diff --git a/include/sanitizer/scudo_interface.h b/include/sanitizer/scudo_interface.h index cab7e0f5f344..ec7a9e4e150c 100644 --- a/include/sanitizer/scudo_interface.h +++ b/include/sanitizer/scudo_interface.h @@ -20,7 +20,7 @@ extern "C" {  #endif    // This function may be optionally provided by a user and should return    // a string containing Scudo runtime options. See scudo_flags.h for details. -  const char* __scudo_default_options(); +  const char* __scudo_default_options(void);    // This function allows to set the RSS limit at runtime. This can be either    // the hard limit (HardLimit=1) or the soft limit (HardLimit=0). The limit diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index da82e485b581..fbd72f69298f 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -175,6 +175,11 @@ else()                                      EXTRA asan.syms.extra)        set(VERSION_SCRIPT_FLAG             -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/clang_rt.asan-dynamic-${arch}.vers) +      # The Solaris 11.4 linker supports a subset of GNU ld version scripts, +      # but requires a special option to enable it. +      if (OS_NAME MATCHES "SunOS") +          list(APPEND VERSION_SCRIPT_FLAG -Wl,-z,gnu-version-script-compat) +      endif()        set_property(SOURCE          ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc          APPEND PROPERTY diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index cd5d89ba2219..68b6f093b533 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -280,7 +280,7 @@ def BreakpadSymbolizerFactory(binary):  def SystemSymbolizerFactory(system, addr, binary, arch):    if system == 'Darwin':      return DarwinSymbolizer(addr, binary, arch) -  elif system in ['Linux', 'FreeBSD', 'NetBSD']: +  elif system in ['Linux', 'FreeBSD', 'NetBSD', 'SunOS']:      return Addr2LineSymbolizer(binary) @@ -370,7 +370,7 @@ class SymbolizationLoop(object):        self.binary_name_filter = binary_name_filter        self.dsym_hint_producer = dsym_hint_producer        self.system = os.uname()[0] -      if self.system not in ['Linux', 'Darwin', 'FreeBSD', 'NetBSD']: +      if self.system not in ['Linux', 'Darwin', 'FreeBSD', 'NetBSD','SunOS']:          raise Exception('Unknown system')        self.llvm_symbolizers = {}        self.last_llvm_symbolizer = None diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index 6fa958319121..6a0faf8ebf0e 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -446,6 +446,12 @@ set(aarch64_SOURCES    ${GENERIC_TF_SOURCES}    ${GENERIC_SOURCES}) +if (MINGW) +  set(aarch64_SOURCES +      ${aarch64_SOURCES} +      aarch64/chkstk.S) +endif() +  set(armhf_SOURCES ${arm_SOURCES})  set(armv7_SOURCES ${arm_SOURCES})  set(armv7s_SOURCES ${arm_SOURCES}) diff --git a/lib/builtins/aarch64/chkstk.S b/lib/builtins/aarch64/chkstk.S new file mode 100644 index 000000000000..89ec90b08a13 --- /dev/null +++ b/lib/builtins/aarch64/chkstk.S @@ -0,0 +1,34 @@ +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + +#include "../assembly.h" + +// __chkstk routine +// This routine is windows specific. +// http://msdn.microsoft.com/en-us/library/ms648426.aspx + +// This clobbers registers x16 and x17. +// Does not modify any memory or the stack pointer. + +//      mov     x15, #256 // Number of bytes of stack, in units of 16 byte +//      bl      __chkstk +//      sub     sp, sp, x15, lsl #4 + +#ifdef __aarch64__ + +#define PAGE_SIZE 4096 + +        .p2align 2 +DEFINE_COMPILERRT_FUNCTION(__chkstk) +        lsl    x16, x15, #4 +        mov    x17, sp +1: +        sub    x17, x17, #PAGE_SIZE +        subs   x16, x16, #PAGE_SIZE +        ldr    xzr, [x17] +        b.gt   1b + +        ret +END_COMPILERRT_FUNCTION(__chkstk) + +#endif // __aarch64__ diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h index dc65cd72091a..c3f241b905b1 100644 --- a/lib/fuzzer/FuzzerTracePC.h +++ b/lib/fuzzer/FuzzerTracePC.h @@ -276,6 +276,7 @@ void TracePC::CollectFeatures(Callback HandleFeature) const {    // Step function, grows similar to 8 * Log_2(A).    auto StackDepthStepFunction = [](uint32_t A) -> uint32_t { +    if (!A) return A;      uint32_t Log2 = Log(A);      if (Log2 < 3) return A;      Log2 -= 3; diff --git a/lib/hwasan/hwasan.cc b/lib/hwasan/hwasan.cc index fcc40eb90182..8b1e5a7846af 100644 --- a/lib/hwasan/hwasan.cc +++ b/lib/hwasan/hwasan.cc @@ -252,40 +252,112 @@ static void SigIll() {    // __builtin_unreachable();  } -template<bool IsStore, unsigned LogSize> -__attribute__((always_inline, nodebug)) -static void CheckAddress(uptr p) { +enum class ErrorAction { Abort, Recover }; +enum class AccessType { Load, Store }; + +template <ErrorAction EA, AccessType AT, unsigned LogSize> +__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {    tag_t ptr_tag = GetTagFromPointer(p);    uptr ptr_raw = p & ~kAddressTagMask;    tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw); -  if (UNLIKELY(ptr_tag != mem_tag)) SigIll<0x100 + 0x10 * IsStore + LogSize>(); +  if (UNLIKELY(ptr_tag != mem_tag)) { +    SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) + +           0x10 * (AT == AccessType::Store) + LogSize>(); +    if (EA == ErrorAction::Abort) __builtin_unreachable(); +  }  } -template<bool IsStore> -__attribute__((always_inline, nodebug)) -static void CheckAddressSized(uptr p, uptr sz) { +template <ErrorAction EA, AccessType AT> +__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p, +                                                                      uptr sz) {    CHECK_NE(0, sz);    tag_t ptr_tag = GetTagFromPointer(p);    uptr ptr_raw = p & ~kAddressTagMask;    tag_t *shadow_first = (tag_t *)MEM_TO_SHADOW(ptr_raw);    tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1);    for (tag_t *t = shadow_first; t <= shadow_last; ++t) -    if (UNLIKELY(ptr_tag != *t)) SigIll<0x100 + 0x10 * IsStore + 0xf>(); -} - -void __hwasan_load(uptr p, uptr sz) { CheckAddressSized<false>(p, sz); } -void __hwasan_load1(uptr p) { CheckAddress<false, 0>(p); } -void __hwasan_load2(uptr p) { CheckAddress<false, 1>(p); } -void __hwasan_load4(uptr p) { CheckAddress<false, 2>(p); } -void __hwasan_load8(uptr p) { CheckAddress<false, 3>(p); } -void __hwasan_load16(uptr p) { CheckAddress<false, 4>(p); } - -void __hwasan_store(uptr p, uptr sz) { CheckAddressSized<true>(p, sz); } -void __hwasan_store1(uptr p) { CheckAddress<true, 0>(p); } -void __hwasan_store2(uptr p) { CheckAddress<true, 1>(p); } -void __hwasan_store4(uptr p) { CheckAddress<true, 2>(p); } -void __hwasan_store8(uptr p) { CheckAddress<true, 3>(p); } -void __hwasan_store16(uptr p) { CheckAddress<true, 4>(p); } +    if (UNLIKELY(ptr_tag != *t)) { +      SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) + +             0x10 * (AT == AccessType::Store) + 0xf>(); +      if (EA == ErrorAction::Abort) __builtin_unreachable(); +    } +} + +void __hwasan_load(uptr p, uptr sz) { +  CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz); +} +void __hwasan_load1(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Load, 0>(p); +} +void __hwasan_load2(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Load, 1>(p); +} +void __hwasan_load4(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Load, 2>(p); +} +void __hwasan_load8(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Load, 3>(p); +} +void __hwasan_load16(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Load, 4>(p); +} + +void __hwasan_load_noabort(uptr p, uptr sz) { +  CheckAddressSized<ErrorAction::Recover, AccessType::Load>(p, sz); +} +void __hwasan_load1_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Load, 0>(p); +} +void __hwasan_load2_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Load, 1>(p); +} +void __hwasan_load4_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Load, 2>(p); +} +void __hwasan_load8_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Load, 3>(p); +} +void __hwasan_load16_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Load, 4>(p); +} + +void __hwasan_store(uptr p, uptr sz) { +  CheckAddressSized<ErrorAction::Abort, AccessType::Store>(p, sz); +} +void __hwasan_store1(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Store, 0>(p); +} +void __hwasan_store2(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Store, 1>(p); +} +void __hwasan_store4(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Store, 2>(p); +} +void __hwasan_store8(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Store, 3>(p); +} +void __hwasan_store16(uptr p) { +  CheckAddress<ErrorAction::Abort, AccessType::Store, 4>(p); +} + +void __hwasan_store_noabort(uptr p, uptr sz) { +  CheckAddressSized<ErrorAction::Recover, AccessType::Store>(p, sz); +} +void __hwasan_store1_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Store, 0>(p); +} +void __hwasan_store2_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Store, 1>(p); +} +void __hwasan_store4_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Store, 2>(p); +} +void __hwasan_store8_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Store, 3>(p); +} +void __hwasan_store16_noabort(uptr p) { +  CheckAddress<ErrorAction::Recover, AccessType::Store, 4>(p); +}  #if !SANITIZER_SUPPORTS_WEAK_HOOKS  extern "C" { diff --git a/lib/hwasan/hwasan_interface_internal.h b/lib/hwasan/hwasan_interface_internal.h index 08b77534e0ae..7e95271ac0af 100644 --- a/lib/hwasan/hwasan_interface_internal.h +++ b/lib/hwasan/hwasan_interface_internal.h @@ -45,6 +45,19 @@ SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_load16(uptr);  SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load_noabort(uptr, uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load1_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load2_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load4_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load8_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load16_noabort(uptr); + +SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store(uptr, uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store1(uptr); @@ -57,6 +70,19 @@ void __hwasan_store8(uptr);  SANITIZER_INTERFACE_ATTRIBUTE  void __hwasan_store16(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store_noabort(uptr, uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store1_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store2_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store4_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store8_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store16_noabort(uptr); +  // Returns the offset of the first tag mismatch or -1 if the whole range is  // good.  SANITIZER_INTERFACE_ATTRIBUTE diff --git a/lib/hwasan/hwasan_linux.cc b/lib/hwasan/hwasan_linux.cc index 9b8613171cbd..48dea8eb6ff4 100644 --- a/lib/hwasan/hwasan_linux.cc +++ b/lib/hwasan/hwasan_linux.cc @@ -174,12 +174,14 @@ struct AccessInfo {    uptr size;    bool is_store;    bool is_load; +  bool recover;  };  #if defined(__aarch64__)  static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {    // Access type is encoded in HLT immediate as 0x1XY, -  // where X is 1 for store, 0 for load. +  // where X&1 is 1 for store, 0 for load, +  // and X&2 is 1 if the error is recoverable.    // Valid values of Y are 0 to 4, which are interpreted as log2(access_size),    // and 0xF, which means that access size is stored in X1 register.    // Access address is always in X0 register. @@ -189,7 +191,8 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {    if ((code & 0xff00) != 0x100)      return AccessInfo{0, 0, false, false}; // Not ours.    bool is_store = code & 0x10; -  unsigned size_log = code & 0xff; +  bool recover = code & 0x20; +  unsigned size_log = code & 0xf;    if (size_log > 4 && size_log != 0xf)      return AccessInfo{0, 0, false, false}; // Not ours. @@ -200,6 +203,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {      ai.size = uc->uc_mcontext.regs[1];    else      ai.size = 1U << size_log; +  ai.recover = recover;    return ai;  }  #else @@ -223,7 +227,7 @@ static bool HwasanOnSIGILL(int signo, siginfo_t *info, ucontext_t *uc) {    ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store);    ++hwasan_report_count; -  if (flags()->halt_on_error) +  if (flags()->halt_on_error || !ai.recover)      Die();    uc->uc_mcontext.pc += 4; diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc index 721926791029..5cc76e4bc08c 100644 --- a/lib/msan/msan_new_delete.cc +++ b/lib/msan/msan_new_delete.cc @@ -22,9 +22,10 @@  using namespace __msan;  // NOLINT -// Fake std::nothrow_t to avoid including <new>. +// Fake std::nothrow_t and std::align_val_t to avoid including <new>.  namespace std {    struct nothrow_t {}; +  enum class align_val_t: size_t {};  }  // namespace std @@ -34,6 +35,11 @@ namespace std {    void *res = msan_malloc(size, &stack);\    if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\    return res +#define OPERATOR_NEW_BODY_ALIGN(nothrow) \ +  GET_MALLOC_STACK_TRACE;\ +  void *res = msan_memalign((uptr)align, size, &stack);\ +  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ +  return res;  INTERCEPTOR_ATTRIBUTE  void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } @@ -47,6 +53,18 @@ INTERCEPTOR_ATTRIBUTE  void *operator new[](size_t size, std::nothrow_t const&) {    OPERATOR_NEW_BODY(true /*nothrow*/);  } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) +{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }  #define OPERATOR_DELETE_BODY \    GET_MALLOC_STACK_TRACE; \ @@ -62,5 +80,29 @@ INTERCEPTOR_ATTRIBUTE  void operator delete[](void *ptr, std::nothrow_t const&) {    OPERATOR_DELETE_BODY;  } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, std::nothrow_t const&) +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size, std::align_val_t align) NOEXCEPT +{ OPERATOR_DELETE_BODY; } +  #endif // MSAN_REPLACE_OPERATORS_NEW_AND_DELETE diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c index 110562383412..7f49d0f9fae1 100644 --- a/lib/profile/InstrProfilingUtil.c +++ b/lib/profile/InstrProfilingUtil.c @@ -9,6 +9,7 @@  #ifdef _WIN32  #include <direct.h> +#include <process.h>  #include <windows.h>  #include "WindowsMMap.h"  #else diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 60caa5c4ffc9..e0226ae4975f 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -20,12 +20,15 @@ set(SANITIZER_SOURCES_NOTERMINATION    sanitizer_platform_limits_linux.cc    sanitizer_platform_limits_netbsd.cc    sanitizer_platform_limits_posix.cc +  sanitizer_platform_limits_solaris.cc    sanitizer_posix.cc    sanitizer_printf.cc    sanitizer_procmaps_common.cc    sanitizer_procmaps_freebsd.cc    sanitizer_procmaps_linux.cc    sanitizer_procmaps_mac.cc +  sanitizer_procmaps_solaris.cc +  sanitizer_solaris.cc    sanitizer_stackdepot.cc    sanitizer_stacktrace.cc    sanitizer_stacktrace_printer.cc @@ -40,7 +43,7 @@ set(SANITIZER_SOURCES_NOTERMINATION    sanitizer_thread_registry.cc    sanitizer_win.cc) -if(UNIX AND NOT APPLE) +if(UNIX AND NOT APPLE AND NOT OS_NAME MATCHES "SunOS")    list(APPEND SANITIZER_SOURCES_NOTERMINATION      sanitizer_linux_x86_64.S)    list(APPEND SANITIZER_SOURCES_NOTERMINATION @@ -122,6 +125,7 @@ set(SANITIZER_HEADERS    sanitizer_platform_interceptors.h    sanitizer_platform_limits_netbsd.h    sanitizer_platform_limits_posix.h +  sanitizer_platform_limits_solaris.h    sanitizer_posix.h    sanitizer_procmaps.h    sanitizer_quarantine.h @@ -216,6 +220,38 @@ add_compiler_rt_object_libraries(RTSanitizerCommonLibcNoHooks    CFLAGS ${SANITIZER_NO_WEAK_HOOKS_CFLAGS}    DEFS ${SANITIZER_COMMON_DEFINITIONS}) +if(OS_NAME MATCHES "SunOS") +  # Solaris ld doesn't support the non-standard GNU ld extension of adding +  # __start_SECNAME and __stop_SECNAME labels to sections whose names are +  # valid C identifiers.  Instead we add our own definitions for the +  # __sancov_guards section. +  add_compiler_rt_object_libraries(SancovBegin +    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +    SOURCES sancov_begin.S +    CFLAGS ${SANITIZER_CFLAGS} +    DEFS ${SANITIZER_COMMON_DEFINITIONS}) + +  add_compiler_rt_runtime(clang_rt.sancov_begin +    STATIC +    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +    OBJECT_LIBS SancovBegin +    CFLAGS ${SANITIZER_CFLAGS} +    DEFS ${SANITIZER_COMMON_DEFINITIONS}) + +  add_compiler_rt_object_libraries(SancovEnd +    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +    SOURCES sancov_end.S +    CFLAGS ${SANITIZER_CFLAGS} +    DEFS ${SANITIZER_COMMON_DEFINITIONS}) + +  add_compiler_rt_runtime(clang_rt.sancov_end +    STATIC +    ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} +    OBJECT_LIBS SancovEnd +    CFLAGS ${SANITIZER_CFLAGS} +    DEFS ${SANITIZER_COMMON_DEFINITIONS}) +endif() +  if(WIN32)    add_compiler_rt_object_libraries(SanitizerCommonWeakInterception      ${SANITIZER_COMMON_SUPPORTED_OS} diff --git a/lib/sanitizer_common/sancov_begin.S b/lib/sanitizer_common/sancov_begin.S new file mode 100644 index 000000000000..c8ad0a0bcb5c --- /dev/null +++ b/lib/sanitizer_common/sancov_begin.S @@ -0,0 +1,5 @@ +	.type		__start___sancov_guards,@object +	.globl		__start___sancov_guards +        .section        __sancov_guards,"aw",@progbits +        .p2align        2 +__start___sancov_guards: diff --git a/lib/sanitizer_common/sancov_end.S b/lib/sanitizer_common/sancov_end.S new file mode 100644 index 000000000000..31117b1c0b56 --- /dev/null +++ b/lib/sanitizer_common/sancov_end.S @@ -0,0 +1,5 @@ +	.type		__stop___sancov_guards,@object +	.globl		__stop___sancov_guards +        .section        __sancov_guards,"aw",@progbits +        .p2align        2 +__stop___sancov_guards: diff --git a/lib/sanitizer_common/sanitizer_atomic_clang.h b/lib/sanitizer_common/sanitizer_atomic_clang.h index 65b3a38f0d51..cd41c920f1b1 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang.h @@ -78,17 +78,7 @@ INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,    typedef typename T::Type Type;    Type cmpv = *cmp;    Type prev; -#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 -  if (sizeof(*a) == 8) { -    Type volatile *val_ptr = const_cast<Type volatile *>(&a->val_dont_use); -    prev = __mips_sync_val_compare_and_swap<u64>( -        reinterpret_cast<u64 volatile *>(val_ptr), (u64)cmpv, (u64)xchg); -  } else { -    prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); -  } -#else    prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); -#endif    if (prev == cmpv) return true;    *cmp = prev;    return false; @@ -104,6 +94,13 @@ INLINE bool atomic_compare_exchange_weak(volatile T *a,  }  // namespace __sanitizer +// This include provides explicit template instantiations for atomic_uint64_t +// on MIPS32, which does not directly support 8 byte atomics. It has to +// proceed the template definitions above. +#if defined(_MIPS_SIM) && defined(_ABIO32) +  #include "sanitizer_atomic_clang_mips.h" +#endif +  #undef ATOMIC_ORDER  #endif  // SANITIZER_ATOMIC_CLANG_H diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_mips.h b/lib/sanitizer_common/sanitizer_atomic_clang_mips.h new file mode 100644 index 000000000000..c64e6e542798 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_atomic_clang_mips.h @@ -0,0 +1,118 @@ +//===-- sanitizer_atomic_clang_mips.h ---------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of ThreadSanitizer/AddressSanitizer runtime. +// Not intended for direct inclusion. Include sanitizer_atomic.h. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ATOMIC_CLANG_MIPS_H +#define SANITIZER_ATOMIC_CLANG_MIPS_H + +namespace __sanitizer { + +// MIPS32 does not support atomics > 4 bytes. To address this lack of +// functionality, the sanitizer library provides helper methods which use an +// internal spin lock mechanism to emulate atomic oprations when the size is +// 8 bytes. +static void __spin_lock(volatile int *lock) { +  while (__sync_lock_test_and_set(lock, 1)) +    while (*lock) { +    } +} + +static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); } + +// Make sure the lock is on its own cache line to prevent false sharing. +// Put it inside a struct that is aligned and padded to the typical MIPS +// cacheline which is 32 bytes. +static struct { +  int lock; +  char pad[32 - sizeof(int)]; +} __attribute__((aligned(32))) lock = {0, {0}}; + +template <> +INLINE atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr, +                                              atomic_uint64_t::Type val, +                                              memory_order mo) { +  DCHECK(mo & +         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); +  DCHECK(!((uptr)ptr % sizeof(*ptr))); + +  atomic_uint64_t::Type ret; + +  __spin_lock(&lock.lock); +  ret = *(const_cast<atomic_uint64_t::Type volatile *>(&ptr->val_dont_use)); +  ptr->val_dont_use = ret + val; +  __spin_unlock(&lock.lock); + +  return ret; +} + +template <> +INLINE atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr, +                                              atomic_uint64_t::Type val, +                                              memory_order mo) { +  return atomic_fetch_add(ptr, -val, mo); +} + +template <> +INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr, +                                           atomic_uint64_t::Type *cmp, +                                           atomic_uint64_t::Type xchg, +                                           memory_order mo) { +  DCHECK(mo & +         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); +  DCHECK(!((uptr)ptr % sizeof(*ptr))); + +  typedef atomic_uint64_t::Type Type; +  Type cmpv = *cmp; +  Type prev; +  bool ret = false; + +  __spin_lock(&lock.lock); +  prev = *(const_cast<Type volatile *>(&ptr->val_dont_use)); +  if (prev == cmpv) { +    ret = true; +    ptr->val_dont_use = xchg; +  } +  __spin_unlock(&lock.lock); + +  return ret; +} + +template <> +INLINE atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr, +                                         memory_order mo) { +  DCHECK(mo & +         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); +  DCHECK(!((uptr)ptr % sizeof(*ptr))); + +  atomic_uint64_t::Type zero = 0; +  volatile atomic_uint64_t *Newptr = +      const_cast<volatile atomic_uint64_t *>(ptr); +  return atomic_fetch_add(Newptr, zero, mo); +} + +template <> +INLINE void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v, +                         memory_order mo) { +  DCHECK(mo & +         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst)); +  DCHECK(!((uptr)ptr % sizeof(*ptr))); + +  __spin_lock(&lock.lock); +  ptr->val_dont_use = v; +  __spin_unlock(&lock.lock); +} + +}  // namespace __sanitizer + +#endif  // SANITIZER_ATOMIC_CLANG_MIPS_H + diff --git a/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/lib/sanitizer_common/sanitizer_atomic_clang_other.h index d2acc311bf7d..35e2d007eda8 100644 --- a/lib/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -17,55 +17,6 @@  namespace __sanitizer { -// MIPS32 does not support atomic > 4 bytes. To address this lack of -// functionality, the sanitizer library provides helper methods which use an -// internal spin lock mechanism to emulate atomic oprations when the size is -// 8 bytes. -#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 -static void __spin_lock(volatile int *lock) { -  while (__sync_lock_test_and_set(lock, 1)) -    while (*lock) { -    } -} - -static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); } - - -// Make sure the lock is on its own cache line to prevent false sharing. -// Put it inside a struct that is aligned and padded to the typical MIPS -// cacheline which is 32 bytes. -static struct { -  int lock; -  char pad[32 - sizeof(int)]; -} __attribute__((aligned(32))) lock = {0}; - -template <class T> -T __mips_sync_fetch_and_add(volatile T *ptr, T val) { -  T ret; - -  __spin_lock(&lock.lock); - -  ret = *ptr; -  *ptr = ret + val; - -  __spin_unlock(&lock.lock); - -  return ret; -} - -template <class T> -T __mips_sync_val_compare_and_swap(volatile T *ptr, T oldval, T newval) { -  T ret; -  __spin_lock(&lock.lock); - -  ret = *ptr; -  if (ret == oldval) *ptr = newval; - -  __spin_unlock(&lock.lock); - -  return ret; -} -#endif  INLINE void proc_yield(int cnt) {    __asm__ __volatile__("" ::: "memory"); @@ -103,15 +54,8 @@ INLINE typename T::Type atomic_load(      // 64-bit load on 32-bit platform.      // Gross, but simple and reliable.      // Assume that it is not in read-only memory. -#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 -    typename T::Type volatile *val_ptr = -        const_cast<typename T::Type volatile *>(&a->val_dont_use); -    v = __mips_sync_fetch_and_add<u64>( -        reinterpret_cast<u64 volatile *>(val_ptr), 0); -#else      v = __sync_fetch_and_add(          const_cast<typename T::Type volatile *>(&a->val_dont_use), 0); -#endif    }    return v;  } @@ -141,14 +85,7 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {      typename T::Type cmp = a->val_dont_use;      typename T::Type cur;      for (;;) { -#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 -      typename T::Type volatile *val_ptr = -          const_cast<typename T::Type volatile *>(&a->val_dont_use); -      cur = __mips_sync_val_compare_and_swap<u64>( -          reinterpret_cast<u64 volatile *>(val_ptr), (u64)cmp, (u64)v); -#else        cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); -#endif        if (cmp == v)          break;        cmp = cur; diff --git a/lib/sanitizer_common/scripts/gen_dynamic_list.py b/lib/sanitizer_common/scripts/gen_dynamic_list.py index 1d4230607b92..25632ed77b94 100755 --- a/lib/sanitizer_common/scripts/gen_dynamic_list.py +++ b/lib/sanitizer_common/scripts/gen_dynamic_list.py @@ -26,12 +26,32 @@ new_delete = set([                    '_Znwm', '_ZnwmRKSt9nothrow_t',    # operator new(unsigned long)                    '_Znaj', '_ZnajRKSt9nothrow_t',    # operator new[](unsigned int)                    '_Znwj', '_ZnwjRKSt9nothrow_t',    # operator new(unsigned int) +                  # operator new(unsigned long, std::align_val_t) +                  '_ZnwmSt11align_val_t', '_ZnwmSt11align_val_tRKSt9nothrow_t', +                  # operator new(unsigned int, std::align_val_t) +                  '_ZnwjSt11align_val_t', '_ZnwjSt11align_val_tRKSt9nothrow_t', +                  # operator new[](unsigned long, std::align_val_t) +                  '_ZnamSt11align_val_t', '_ZnamSt11align_val_tRKSt9nothrow_t', +                  # operator new[](unsigned int, std::align_val_t) +                  '_ZnajSt11align_val_t', '_ZnajSt11align_val_tRKSt9nothrow_t',                    '_ZdaPv', '_ZdaPvRKSt9nothrow_t',  # operator delete[](void *)                    '_ZdlPv', '_ZdlPvRKSt9nothrow_t',  # operator delete(void *)                    '_ZdaPvm',                         # operator delete[](void*, unsigned long)                    '_ZdlPvm',                         # operator delete(void*, unsigned long)                    '_ZdaPvj',                         # operator delete[](void*, unsigned int)                    '_ZdlPvj',                         # operator delete(void*, unsigned int) +                  # operator delete(void*, std::align_val_t) +                  '_ZdlPvSt11align_val_t', '_ZdlPvSt11align_val_tRKSt9nothrow_t', +                  # operator delete[](void*, std::align_val_t) +                  '_ZdaPvSt11align_val_t', '_ZdaPvSt11align_val_tRKSt9nothrow_t', +                  # operator delete(void*, unsigned long,  std::align_val_t) +                  '_ZdlPvmSt11align_val_t', +                  # operator delete[](void*, unsigned long, std::align_val_t) +                  '_ZdaPvmSt11align_val_t', +                  # operator delete(void*, unsigned int,  std::align_val_t) +                  '_ZdlPvjSt11align_val_t', +                  # operator delete[](void*, unsigned int, std::align_val_t) +                  '_ZdaPvjSt11align_val_t',                    ])  versioned_functions = set(['memcpy', 'pthread_attr_getaffinity_np', diff --git a/lib/tsan/rtl/tsan_new_delete.cc b/lib/tsan/rtl/tsan_new_delete.cc index 4d03145c16ad..a1bb22690e0f 100644 --- a/lib/tsan/rtl/tsan_new_delete.cc +++ b/lib/tsan/rtl/tsan_new_delete.cc @@ -20,6 +20,7 @@ using namespace __tsan;  // NOLINT  namespace std {  struct nothrow_t {}; +enum class align_val_t: __sanitizer::uptr {};  }  // namespace std  DECLARE_REAL(void *, malloc, uptr size) @@ -38,6 +39,18 @@ DECLARE_REAL(void, free, void *ptr)    invoke_malloc_hook(p, size);  \    return p; +#define OPERATOR_NEW_BODY_ALIGN(mangled_name, nothrow) \ +  if (cur_thread()->in_symbolizer) \ +    return InternalAlloc(size, nullptr, (uptr)align); \ +  void *p = 0; \ +  {  \ +    SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ +    p = user_memalign(thr, pc, (uptr)align, size); \ +    if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ +  }  \ +  invoke_malloc_hook(p, size);  \ +  return p; +  SANITIZER_INTERFACE_ATTRIBUTE  void *operator new(__sanitizer::uptr size);  void *operator new(__sanitizer::uptr size) { @@ -62,6 +75,36 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {    OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/);  } +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new(__sanitizer::uptr size, std::align_val_t align); +void *operator new(__sanitizer::uptr size, std::align_val_t align) { +  OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_t, false /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new[](__sanitizer::uptr size, std::align_val_t align); +void *operator new[](__sanitizer::uptr size, std::align_val_t align) { +  OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_t, false /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new(__sanitizer::uptr size, std::align_val_t align, +                   std::nothrow_t const&); +void *operator new(__sanitizer::uptr size, std::align_val_t align, +                   std::nothrow_t const&) { +  OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_tRKSt9nothrow_t, +                          true /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new[](__sanitizer::uptr size, std::align_val_t align, +                     std::nothrow_t const&); +void *operator new[](__sanitizer::uptr size, std::align_val_t align, +                     std::nothrow_t const&) { +  OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_tRKSt9nothrow_t, +                          true /*nothrow*/); +} +  #define OPERATOR_DELETE_BODY(mangled_name) \    if (ptr == 0) return;  \    if (cur_thread()->in_symbolizer) \ @@ -93,3 +136,57 @@ void operator delete[](void *ptr, std::nothrow_t const&);  void operator delete[](void *ptr, std::nothrow_t const&) {    OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t);  } + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT; +void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT { +  OPERATOR_DELETE_BODY(_ZdlPvm); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT; +void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT { +  OPERATOR_DELETE_BODY(_ZdaPvm); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT; +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT { +  OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT; +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT { +  OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&); +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) { +  OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_tRKSt9nothrow_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, +                       std::nothrow_t const&); +void operator delete[](void *ptr, std::align_val_t align, +                       std::nothrow_t const&) { +  OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_tRKSt9nothrow_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, __sanitizer::uptr size, +                     std::align_val_t align) NOEXCEPT; +void operator delete(void *ptr, __sanitizer::uptr size, +                     std::align_val_t align) NOEXCEPT { +  OPERATOR_DELETE_BODY(_ZdlPvmSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, __sanitizer::uptr size, +                       std::align_val_t align) NOEXCEPT; +void operator delete[](void *ptr, __sanitizer::uptr size, +                       std::align_val_t align) NOEXCEPT { +  OPERATOR_DELETE_BODY(_ZdaPvmSt11align_val_t); +} diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 1112ce1cc5ff..f674c027cd91 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -297,7 +297,7 @@ void __ubsan::__ubsan_handle_out_of_bounds_abort(OutOfBoundsData *Data,  static void handleBuiltinUnreachableImpl(UnreachableData *Data,                                           ReportOptions Opts) {    ScopedReport R(Opts, Data->Loc, ErrorType::UnreachableCall); -  Diag(Data->Loc, DL_Error, "execution reached a __builtin_unreachable() call"); +  Diag(Data->Loc, DL_Error, "execution reached an unreachable program point");  }  void __ubsan::__ubsan_handle_builtin_unreachable(UnreachableData *Data) { diff --git a/test/asan/TestCases/Linux/aligned_delete_test.cc b/test/asan/TestCases/Linux/aligned_delete_test.cc index 5b9455e56553..9117198f91da 100644 --- a/test/asan/TestCases/Linux/aligned_delete_test.cc +++ b/test/asan/TestCases/Linux/aligned_delete_test.cc @@ -6,12 +6,10 @@  // RUN: %env_asan_opts=new_delete_type_mismatch=1:halt_on_error=false:detect_leaks=false %run %t 2>&1 | FileCheck %s  // RUN: %env_asan_opts=new_delete_type_mismatch=0                                        %run %t -// REQUIRES: asan-static-runtime -  #include <stdio.h>  // Define all new/delete to do not depend on the version provided by the -// plaform. The implementation is provided by ASan anyway. +// platform. The implementation is provided by ASan anyway.  namespace std {  struct nothrow_t {}; @@ -57,34 +55,8 @@ struct alignas(1024) S1024_1024 { char a[1024]; };  int main(int argc, char **argv) { -  fprintf(stderr, "Testing valid cases\n"); - -  delete break_optimization(new S12); -  operator delete(break_optimization(new S12), std::nothrow); -  delete [] break_optimization(new S12[100]); -  operator delete[](break_optimization(new S12[100]), std::nothrow); - -  delete break_optimization(new S12_128); -  operator delete(break_optimization(new S12_128), -                  std::align_val_t(alignof(S12_128))); -  operator delete(break_optimization(new S12_128), -                  std::align_val_t(alignof(S12_128)), std::nothrow); -  operator delete(break_optimization(new S12_128), sizeof(S12_128), -                  std::align_val_t(alignof(S12_128))); - -  delete [] break_optimization(new S12_128[100]); -  operator delete[](break_optimization(new S12_128[100]), -                    std::align_val_t(alignof(S12_128))); -  operator delete[](break_optimization(new S12_128[100]), -                    std::align_val_t(alignof(S12_128)), std::nothrow); -  operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100]), -                    std::align_val_t(alignof(S12_128))); - -  fprintf(stderr, "Done\n"); -  // CHECK: Testing valid cases -  // CHECK-NEXT: Done - -  // Explicit mismatched calls. +  // Check the mismatched calls only, all the valid cases are verified in +  // test/sanitizer_common/TestCases/Linux/new_delete_test.cc.    operator delete(break_optimization(new S12_128), std::nothrow);    // CHECK: AddressSanitizer: new-delete-type-mismatch diff --git a/test/hwasan/TestCases/halt-on-error.cc b/test/hwasan/TestCases/halt-on-error.cc index 97693d5bceba..fdf6d27d7939 100644 --- a/test/hwasan/TestCases/halt-on-error.cc +++ b/test/hwasan/TestCases/halt-on-error.cc @@ -1,4 +1,19 @@ -// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON +// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON,RECOVER + +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON,RECOVER +  // REQUIRES: stable-runtime  #include <stdlib.h> @@ -10,17 +25,18 @@ int main() {    free(x);    __hwasan_disable_allocator_tagging();    return x[2] + ((char *)x)[6] + ((char *)x)[9]; -  // CHECK: READ of size 4 at -  // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12 -  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main +  // COMMON: READ of size 4 at +  // When instrumenting with callbacks, main is actually #1, and #0 is __hwasan_load4. +  // COMMON: #{{.*}} in main {{.*}}halt-on-error.cc:27 +  // COMMON: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in -  // CHECK: READ of size 1 at -  // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12 -  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main +  // RECOVER: READ of size 1 at +  // RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27 +  // RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in -  // CHECK: READ of size 1 at -  // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12 -  // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main +  // RECOVER: READ of size 1 at +  // RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27 +  // RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in -  // CHECK-NOT: tag-mismatch +  // COMMON-NOT: tag-mismatch  } diff --git a/test/hwasan/TestCases/use-after-free.cc b/test/hwasan/TestCases/use-after-free.cc index a4d3ee89509f..37637898d7a1 100644 --- a/test/hwasan/TestCases/use-after-free.cc +++ b/test/hwasan/TestCases/use-after-free.cc @@ -1,7 +1,10 @@ -// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// RUN: %clangxx_hwasan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// RUN: %clangxx_hwasan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// RUN: %clangxx_hwasan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_hwasan -O0 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD +// RUN: %clangxx_hwasan -O1 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD +// RUN: %clangxx_hwasan -O2 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD +// RUN: %clangxx_hwasan -O3 -DLOAD %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,LOAD + +// RUN: %clangxx_hwasan -O0 -DSTORE %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,STORE +  // REQUIRES: stable-runtime  #include <stdlib.h> @@ -9,20 +12,28 @@  int main() {    __hwasan_enable_allocator_tagging(); -  char *x = (char*)malloc(10); +  char * volatile x = (char*)malloc(10);    free(x);    __hwasan_disable_allocator_tagging(); +#ifdef STORE +  x[5] = 42; +#endif +#ifdef LOAD    return x[5]; -  // CHECK: READ of size 1 at -  // CHECK: #0 {{.*}} in main {{.*}}use-after-free.cc:15 +#endif +  // LOAD: READ of size 1 at +  // LOAD: #0 {{.*}} in main {{.*}}use-after-free.cc:22 + +  // STORE: WRITE of size 1 at +  // STORE: #0 {{.*}} in main {{.*}}use-after-free.cc:19    // CHECK: freed here:    // CHECK: #0 {{.*}} in free {{.*}}hwasan_interceptors.cc -  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.cc:13 +  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.cc:16    // CHECK: previously allocated here:    // CHECK: #0 {{.*}} in __interceptor_malloc {{.*}}hwasan_interceptors.cc -  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.cc:12 +  // CHECK: #1 {{.*}} in main {{.*}}use-after-free.cc:15    // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main  } diff --git a/test/sanitizer_common/TestCases/Linux/new_delete_test.cc b/test/sanitizer_common/TestCases/Linux/new_delete_test.cc new file mode 100644 index 000000000000..5e5346a08df4 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/new_delete_test.cc @@ -0,0 +1,80 @@ +// RUN: %clangxx -std=c++1z -faligned-allocation -O0 %s -o %t && %run %t +// RUN: %clangxx -std=c++1z -faligned-allocation -fsized-deallocation -O0 %s -o %t && %run %t + +// ubsan does not intercept new/delete. +// UNSUPPORTED: ubsan + +// Check that all new/delete variants are defined and work with supported +// sanitizers. Sanitizer-specific failure modes tests are supposed to go to +// the particular sanitizier's test suites. + +#include <cstddef> + +// Define all new/delete to do not depend on the version provided by the +// platform. The implementation is provided by the sanitizer anyway. + +namespace std { +struct nothrow_t {}; +static const nothrow_t nothrow; +enum class align_val_t : size_t {}; +}  // namespace std + +void *operator new(size_t); +void *operator new[](size_t); +void *operator new(size_t, std::nothrow_t const&); +void *operator new[](size_t, std::nothrow_t const&); +void *operator new(size_t, std::align_val_t); +void *operator new[](size_t, std::align_val_t); +void *operator new(size_t, std::align_val_t, std::nothrow_t const&); +void *operator new[](size_t, std::align_val_t, std::nothrow_t const&); + +void operator delete(void*) throw(); +void operator delete[](void*) throw(); +void operator delete(void*, std::nothrow_t const&); +void operator delete[](void*, std::nothrow_t const&); +void operator delete(void*, size_t) throw(); +void operator delete[](void*, size_t) throw(); +void operator delete(void*, std::align_val_t) throw(); +void operator delete[](void*, std::align_val_t) throw(); +void operator delete(void*, std::align_val_t, std::nothrow_t const&); +void operator delete[](void*, std::align_val_t, std::nothrow_t const&); +void operator delete(void*, size_t, std::align_val_t) throw(); +void operator delete[](void*, size_t, std::align_val_t) throw(); + + +template<typename T> +inline T* break_optimization(T *arg) { +  __asm__ __volatile__("" : : "r" (arg) : "memory"); +  return arg; +} + + +struct S12 { int a, b, c; }; +struct alignas(128) S12_128 { int a, b, c; }; +struct alignas(256) S12_256 { int a, b, c; }; +struct alignas(512) S1024_512 { char a[1024]; }; +struct alignas(1024) S1024_1024 { char a[1024]; }; + + +int main(int argc, char **argv) { +  delete break_optimization(new S12); +  operator delete(break_optimization(new S12), std::nothrow); +  delete [] break_optimization(new S12[100]); +  operator delete[](break_optimization(new S12[100]), std::nothrow); + +  delete break_optimization(new S12_128); +  operator delete(break_optimization(new S12_128), +                  std::align_val_t(alignof(S12_128))); +  operator delete(break_optimization(new S12_128), +                  std::align_val_t(alignof(S12_128)), std::nothrow); +  operator delete(break_optimization(new S12_128), sizeof(S12_128), +                  std::align_val_t(alignof(S12_128))); + +  delete [] break_optimization(new S12_128[100]); +  operator delete[](break_optimization(new S12_128[100]), +                    std::align_val_t(alignof(S12_128))); +  operator delete[](break_optimization(new S12_128[100]), +                    std::align_val_t(alignof(S12_128)), std::nothrow); +  operator delete[](break_optimization(new S12_128[100]), sizeof(S12_128[100]), +                    std::align_val_t(alignof(S12_128))); +} diff --git a/test/ubsan/TestCases/Misc/Inputs/returns-unexpectedly.c b/test/ubsan/TestCases/Misc/Inputs/returns-unexpectedly.c new file mode 100644 index 000000000000..826ea0ca496a --- /dev/null +++ b/test/ubsan/TestCases/Misc/Inputs/returns-unexpectedly.c @@ -0,0 +1 @@ +void returns_unexpectedly() {} diff --git a/test/ubsan/TestCases/Misc/unreachable.cpp b/test/ubsan/TestCases/Misc/unreachable.cpp index e1206edb30d5..1b096721ce9c 100644 --- a/test/ubsan/TestCases/Misc/unreachable.cpp +++ b/test/ubsan/TestCases/Misc/unreachable.cpp @@ -1,6 +1,25 @@ -// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clang %S/Inputs/returns-unexpectedly.c -O3 -c -o %t.ru.o +// RUN: %clangxx -fsanitize=unreachable -O3 -o %t %s %t.ru.o +// RUN: not %run %t builtin 2>&1 | FileCheck %s -check-prefix=BUILTIN +// RUN: not %run %t noreturn-callee-marked 2>&1 | FileCheck %s -check-prefix=NORETURN1 +// RUN: not %run %t noreturn-caller-marked 2>&1 | FileCheck %s -check-prefix=NORETURN2 + +#include <string.h> + +void __attribute__((noreturn)) callee_marked_noreturn() { +  // NORETURN1: unreachable.cpp:[[@LINE+1]]:1: runtime error: execution reached an unreachable program point +} + +extern "C" void __attribute__((noreturn)) returns_unexpectedly();  int main(int, char **argv) { -  // CHECK: unreachable.cpp:5:3: runtime error: execution reached a __builtin_unreachable() call -  __builtin_unreachable(); +  if (strcmp(argv[1], "builtin") == 0) +    // BUILTIN: unreachable.cpp:[[@LINE+1]]:5: runtime error: execution reached an unreachable program point +    __builtin_unreachable(); +  else if (strcmp(argv[1], "noreturn-callee-marked") == 0) +    callee_marked_noreturn(); +  else if (strcmp(argv[1], "noreturn-caller-marked") == 0) +    // NORETURN2: unreachable.cpp:[[@LINE+1]]:5: runtime error: execution reached an unreachable program point +    returns_unexpectedly(); +  return 0;  } | 
