Vendor import of compiler-rt trunk r321414:
https://llvm.org/svn/llvm-project/compiler-rt/trunk@321414
This commit is contained in:
parent
a14b3e1ff3
commit
845f385a17
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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'.
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 @@ def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
|
||||
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
|
||||
|
@ -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})
|
||||
|
34
lib/builtins/aarch64/chkstk.S
Normal file
34
lib/builtins/aarch64/chkstk.S
Normal file
@ -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__
|
@ -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;
|
||||
|
@ -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>();
|
||||
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<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_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_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); }
|
||||
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" {
|
||||
|
@ -44,6 +44,19 @@ void __hwasan_load8(uptr);
|
||||
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
|
||||
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
#include "WindowsMMap.h"
|
||||
#else
|
||||
|
@ -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}
|
||||
|
5
lib/sanitizer_common/sancov_begin.S
Normal file
5
lib/sanitizer_common/sancov_begin.S
Normal file
@ -0,0 +1,5 @@
|
||||
.type __start___sancov_guards,@object
|
||||
.globl __start___sancov_guards
|
||||
.section __sancov_guards,"aw",@progbits
|
||||
.p2align 2
|
||||
__start___sancov_guards:
|
5
lib/sanitizer_common/sancov_end.S
Normal file
5
lib/sanitizer_common/sancov_end.S
Normal file
@ -0,0 +1,5 @@
|
||||
.type __stop___sancov_guards,@object
|
||||
.globl __stop___sancov_guards
|
||||
.section __sancov_guards,"aw",@progbits
|
||||
.p2align 2
|
||||
__stop___sancov_guards:
|
@ -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
|
||||
|
118
lib/sanitizer_common/sanitizer_atomic_clang_mips.h
Normal file
118
lib/sanitizer_common/sanitizer_atomic_clang_mips.h
Normal file
@ -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
|
||||
|
@ -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;
|
||||
|
@ -26,12 +26,32 @@
|
||||
'_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',
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
80
test/sanitizer_common/TestCases/Linux/new_delete_test.cc
Normal file
80
test/sanitizer_common/TestCases/Linux/new_delete_test.cc
Normal file
@ -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)));
|
||||
}
|
1
test/ubsan/TestCases/Misc/Inputs/returns-unexpectedly.c
Normal file
1
test/ubsan/TestCases/Misc/Inputs/returns-unexpectedly.c
Normal file
@ -0,0 +1 @@
|
||||
void returns_unexpectedly() {}
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user