diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-08 17:13:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-08 17:13:22 +0000 |
commit | 2109e2e4181555140883e9ec46807746a0eabad2 (patch) | |
tree | 81e6d3c4fac52ac6256179942b7f365d01b084d6 | |
parent | 285f392c555459b82baeec68b944936685546972 (diff) |
Notes
36 files changed, 775 insertions, 115 deletions
diff --git a/include/xray/xray_interface.h b/include/xray/xray_interface.h index 52a7e1d9e944..c90025e38aae 100644 --- a/include/xray/xray_interface.h +++ b/include/xray/xray_interface.h @@ -15,10 +15,11 @@ #define XRAY_XRAY_INTERFACE_H #include <cstdint> +#include <stddef.h> extern "C" { -// Synchronize this with AsmPrinter::SledKind in LLVM. +/// Synchronize this with AsmPrinter::SledKind in LLVM. enum XRayEntryType { ENTRY = 0, EXIT = 1, @@ -26,32 +27,43 @@ enum XRayEntryType { LOG_ARGS_ENTRY = 3, }; -// Provide a function to invoke for when instrumentation points are hit. This is -// a user-visible control surface that overrides the default implementation. The -// function provided should take the following arguments: -// -// - function id: an identifier that indicates the id of a function; this id -// is generated by xray; the mapping between the function id -// and the actual function pointer is available through -// __xray_table. -// - entry type: identifies what kind of instrumentation point was encountered -// (function entry, function exit, etc.). See the enum -// XRayEntryType for more details. -// -// The user handler must handle correctly spurious calls after this handler is -// removed or replaced with another handler, because it would be too costly for -// XRay runtime to avoid spurious calls. -// To prevent circular calling, the handler function itself and all its -// direct&indirect callees must not be instrumented with XRay, which can be -// achieved by marking them all with: __attribute__((xray_never_instrument)) -// -// Returns 1 on success, 0 on error. +/// Provide a function to invoke for when instrumentation points are hit. This +/// is a user-visible control surface that overrides the default implementation. +/// The function provided should take the following arguments: +/// +/// - function id: an identifier that indicates the id of a function; this id +/// is generated by xray; the mapping between the function id +/// and the actual function pointer is available through +/// __xray_table. +/// - entry type: identifies what kind of instrumentation point was +/// encountered (function entry, function exit, etc.). See the +/// enum XRayEntryType for more details. +/// +/// The user handler must handle correctly spurious calls after this handler is +/// removed or replaced with another handler, because it would be too costly for +/// XRay runtime to avoid spurious calls. +/// To prevent circular calling, the handler function itself and all its +/// direct&indirect callees must not be instrumented with XRay, which can be +/// achieved by marking them all with: __attribute__((xray_never_instrument)) +/// +/// Returns 1 on success, 0 on error. extern int __xray_set_handler(void (*entry)(int32_t, XRayEntryType)); -// This removes whatever the currently provided handler is. Returns 1 on -// success, 0 on error. +/// This removes whatever the currently provided handler is. Returns 1 on +/// success, 0 on error. extern int __xray_remove_handler(); +/// Use XRay to log the first argument of each (instrumented) function call. +/// When this function exits, all threads will have observed the effect and +/// start logging their subsequent affected function calls (if patched). +/// +/// Returns 1 on success, 0 on error. +extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); + +/// Disables the XRay handler used to log first arguments of function calls. +/// Returns 1 on success, 0 on error. +extern int __xray_remove_handler_arg1(); + enum XRayPatchingStatus { NOT_INITIALIZED = 0, SUCCESS = 1, @@ -59,24 +71,31 @@ enum XRayPatchingStatus { FAILED = 3, }; -// This tells XRay to patch the instrumentation points. See XRayPatchingStatus -// for possible result values. +/// This tells XRay to patch the instrumentation points. See XRayPatchingStatus +/// for possible result values. extern XRayPatchingStatus __xray_patch(); -// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible -// result values. +/// Reverses the effect of __xray_patch(). See XRayPatchingStatus for possible +/// result values. extern XRayPatchingStatus __xray_unpatch(); -// Use XRay to log the first argument of each (instrumented) function call. -// When this function exits, all threads will have observed the effect and -// start logging their subsequent affected function calls (if patched). -// -// Returns 1 on success, 0 on error. -extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); +/// This patches a specific function id. See XRayPatchingStatus for possible +/// result values. +extern XRayPatchingStatus __xray_patch_function(int32_t FuncId); + +/// This unpatches a specific function id. See XRayPatchingStatus for possible +/// result values. +extern XRayPatchingStatus __xray_unpatch_function(int32_t FuncId); + +/// This function returns the address of the function provided a valid function +/// id. We return 0 if we encounter any error, even if 0 may be a valid function +/// address. +extern uintptr_t __xray_function_address(int32_t FuncId); + +/// This function returns the maximum valid function id. Returns 0 if we +/// encounter errors (when there are no instrumented functions, etc.). +extern size_t __xray_max_function_id(); -// Disables the XRay handler used to log first arguments of function calls. -// Returns 1 on success, 0 on error. -extern int __xray_remove_handler_arg1(); } #endif diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 905dd2e23870..c6969c979a59 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -443,6 +443,13 @@ INTERCEPTOR(void, _longjmp, void *env, int val) { } #endif +#if ASAN_INTERCEPT___LONGJMP_CHK +INTERCEPTOR(void, __longjmp_chk, void *env, int val) { + __asan_handle_no_return(); + REAL(__longjmp_chk)(env, val); +} +#endif + #if ASAN_INTERCEPT_SIGLONGJMP INTERCEPTOR(void, siglongjmp, void *env, int val) { __asan_handle_no_return(); @@ -758,6 +765,9 @@ void InitializeAsanInterceptors() { #if ASAN_INTERCEPT__LONGJMP ASAN_INTERCEPT_FUNC(_longjmp); #endif +#if ASAN_INTERCEPT___LONGJMP_CHK + ASAN_INTERCEPT_FUNC(__longjmp_chk); +#endif #if ASAN_INTERCEPT_SIGLONGJMP ASAN_INTERCEPT_FUNC(siglongjmp); #endif diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index d747c31a5d0f..93fca4f67366 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -58,6 +58,12 @@ # define ASAN_INTERCEPT_SIGLONGJMP 0 #endif +#if SANITIZER_LINUX && !SANITIZER_ANDROID +# define ASAN_INTERCEPT___LONGJMP_CHK 1 +#else +# define ASAN_INTERCEPT___LONGJMP_CHK 0 +#endif + // Android bug: https://code.google.com/p/android/issues/detail?id=61799 #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \ !(SANITIZER_ANDROID && defined(__i386)) diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt index c30d9b3633fe..e3779ca79ceb 100644 --- a/lib/builtins/CMakeLists.txt +++ b/lib/builtins/CMakeLists.txt @@ -167,6 +167,26 @@ set(GENERIC_SOURCES umodti3.c emutls.c) +set(GENERIC_TF_SOURCES + comparetf2.c + extenddftf2.c + extendsftf2.c + fixtfdi.c + fixtfsi.c + fixtfti.c + fixunstfdi.c + fixunstfsi.c + fixunstfti.c + floatditf.c + floatsitf.c + floattitf.c + floatunditf.c + floatunsitf.c + floatuntitf.c + multc3.c + trunctfdf2.c + trunctfsf2.c) + option(COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN "Skip the atomic builtin (this may be needed if system headers are unavailable)" Off) @@ -390,7 +410,8 @@ if(MINGW) udivmoddi4.c udivmodsi4.c udivsi3.c - umoddi3.c) + umoddi3.c + emutls.c) elseif(NOT WIN32) # TODO the EABI sources should only be added to EABI targets set(arm_SOURCES @@ -404,24 +425,7 @@ elseif(NOT WIN32) endif() set(aarch64_SOURCES - comparetf2.c - extenddftf2.c - extendsftf2.c - fixtfdi.c - fixtfsi.c - fixtfti.c - fixunstfdi.c - fixunstfsi.c - fixunstfti.c - floatditf.c - floatsitf.c - floattitf.c - floatunditf.c - floatunsitf.c - floatuntitf.c - multc3.c - trunctfdf2.c - trunctfsf2.c + ${GENERIC_TF_SOURCES} ${GENERIC_SOURCES}) set(armhf_SOURCES ${arm_SOURCES}) @@ -437,8 +441,10 @@ set(armv7em_SOURCES ${arm_SOURCES}) set(mips_SOURCES ${GENERIC_SOURCES}) set(mipsel_SOURCES ${mips_SOURCES}) -set(mips64_SOURCES ${mips_SOURCES}) -set(mips64el_SOURCES ${mips_SOURCES}) +set(mips64_SOURCES ${GENERIC_TF_SOURCES} + ${mips_SOURCES}) +set(mips64el_SOURCES ${GENERIC_TF_SOURCES} + ${mips_SOURCES}) set(wasm32_SOURCES ${GENERIC_SOURCES}) set(wasm64_SOURCES ${GENERIC_SOURCES}) diff --git a/lib/builtins/emutls.c b/lib/builtins/emutls.c index e8d5ddb22011..12aad3a42b76 100644 --- a/lib/builtins/emutls.c +++ b/lib/builtins/emutls.c @@ -98,7 +98,7 @@ static __inline emutls_address_array* emutls_getspecific() { #else -#include <Windows.h> +#include <windows.h> #include <malloc.h> #include <stdio.h> #include <assert.h> diff --git a/lib/builtins/int_types.h b/lib/builtins/int_types.h index 660385ecd6ae..a92238c5b730 100644 --- a/lib/builtins/int_types.h +++ b/lib/builtins/int_types.h @@ -60,9 +60,7 @@ typedef union }s; } udwords; -/* MIPS64 issue: PR 20098 */ -#if (defined(__LP64__) || defined(__wasm__)) && \ - !(defined(__mips__) && defined(__clang__)) +#if (defined(__LP64__) || defined(__wasm__) || defined(__mips64)) #define CRT_HAS_128BIT #endif diff --git a/lib/cfi/cfi_blacklist.txt b/lib/cfi/cfi_blacklist.txt index 1f0eeb355617..cc111be8120e 100644 --- a/lib/cfi/cfi_blacklist.txt +++ b/lib/cfi/cfi_blacklist.txt @@ -24,3 +24,8 @@ fun:_ZNSt3__19addressof* # Windows C++ stdlib headers that contain bad unrelated casts. src:*xmemory0 src:*xstddef + +# std::_Sp_counted_ptr_inplace::_Sp_counted_ptr_inplace() (libstdc++). +# This ctor is used by std::make_shared and needs to cast to uninitialized T* +# in order to call std::allocator_traits<T>::construct. +fun:_ZNSt23_Sp_counted_ptr_inplace* diff --git a/lib/scudo/CMakeLists.txt b/lib/scudo/CMakeLists.txt index 3a8f4ae4fa9e..14c199fa8227 100644 --- a/lib/scudo/CMakeLists.txt +++ b/lib/scudo/CMakeLists.txt @@ -14,6 +14,7 @@ set(SCUDO_SOURCES scudo_interceptors.cpp scudo_new_delete.cpp scudo_termination.cpp + scudo_tls_android.cpp scudo_tls_linux.cpp scudo_utils.cpp) diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 2ccdcd903dad..5420fc9649ca 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -368,11 +368,12 @@ struct ScudoAllocator { void *Ptr; uptr Salt; uptr AllocationAlignment = FromPrimary ? MinAlignment : Alignment; - ScudoThreadContext *ThreadContext = getThreadContext(); + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { Salt = getPrng(ThreadContext)->getNext(); Ptr = BackendAllocator.Allocate(getAllocatorCache(ThreadContext), NeededSize, AllocationAlignment); + ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); Salt = FallbackPrng.getNext(); @@ -434,9 +435,10 @@ struct ScudoAllocator { if (BypassQuarantine) { Chunk->eraseHeader(); void *Ptr = Chunk->getAllocBeg(Header); - ScudoThreadContext *ThreadContext = getThreadContext(); + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { getBackendAllocator().Deallocate(getAllocatorCache(ThreadContext), Ptr); + ThreadContext->unlock(); } else { SpinMutexLock Lock(&FallbackMutex); getBackendAllocator().Deallocate(&FallbackAllocatorCache, Ptr); @@ -445,12 +447,13 @@ struct ScudoAllocator { UnpackedHeader NewHeader = *Header; NewHeader.State = ChunkQuarantine; Chunk->compareExchangeHeader(&NewHeader, Header); - ScudoThreadContext *ThreadContext = getThreadContext(); + ScudoThreadContext *ThreadContext = getThreadContextAndLock(); if (LIKELY(ThreadContext)) { AllocatorQuarantine.Put(getQuarantineCache(ThreadContext), QuarantineCallback( getAllocatorCache(ThreadContext)), Chunk, Size); + ThreadContext->unlock(); } else { SpinMutexLock l(&FallbackMutex); AllocatorQuarantine.Put(&FallbackQuarantineCache, diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h index 2cac2de71cb0..f159deffb1d5 100644 --- a/lib/scudo/scudo_allocator.h +++ b/lib/scudo/scudo_allocator.h @@ -72,7 +72,13 @@ const uptr AlignedChunkHeaderSize = #if SANITIZER_CAN_USE_ALLOCATOR64 const uptr AllocatorSpace = ~0ULL; -const uptr AllocatorSize = 0x40000000000ULL; // 4TB. +# if defined(__aarch64__) && SANITIZER_ANDROID +const uptr AllocatorSize = 0x4000000000ULL; // 256G. +# elif defined(__aarch64__) +const uptr AllocatorSize = 0x10000000000ULL; // 1T. +# else +const uptr AllocatorSize = 0x40000000000ULL; // 4T. +# endif typedef DefaultSizeClassMap SizeClassMap; struct AP { static const uptr kSpaceBeg = AllocatorSpace; diff --git a/lib/scudo/scudo_tls.h b/lib/scudo/scudo_tls.h index 0d7d1bffd0b6..f6039bebec44 100644 --- a/lib/scudo/scudo_tls.h +++ b/lib/scudo/scudo_tls.h @@ -19,10 +19,16 @@ #include "scudo_allocator.h" #include "scudo_utils.h" +#include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform.h" + namespace __scudo { -struct ALIGNED(64) ScudoThreadContext { - public: +// Platform specific base thread context definitions. +#include "scudo_tls_context_android.inc" +#include "scudo_tls_context_linux.inc" + +struct ALIGNED(64) ScudoThreadContext : public ScudoThreadContextPlatform { AllocatorCache Cache; Xorshift128Plus Prng; uptr QuarantineCachePlaceHolder[4]; @@ -32,8 +38,9 @@ struct ALIGNED(64) ScudoThreadContext { void initThread(); -// Fastpath functions are defined in the following platform specific headers. -#include "scudo_tls_linux.h" +// Platform specific dastpath functions definitions. +#include "scudo_tls_android.inc" +#include "scudo_tls_linux.inc" } // namespace __scudo diff --git a/lib/scudo/scudo_tls_android.cpp b/lib/scudo/scudo_tls_android.cpp new file mode 100644 index 000000000000..0e3602b2faf0 --- /dev/null +++ b/lib/scudo/scudo_tls_android.cpp @@ -0,0 +1,95 @@ +//===-- scudo_tls_android.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure implementation for Android. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_LINUX && SANITIZER_ANDROID + +#include "scudo_tls.h" + +#include <pthread.h> + +namespace __scudo { + +static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; +static pthread_key_t PThreadKey; + +static atomic_uint32_t ThreadContextCurrentIndex; +static ScudoThreadContext *ThreadContexts; +static uptr NumberOfContexts; + +// sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. +static uptr getNumberOfCPUs() { + cpu_set_t CPUs; + CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); + return CPU_COUNT(&CPUs); +} + +static void initOnce() { + // Hack: TLS_SLOT_TSAN was introduced in N. To be able to use it on M for + // testing, we create an unused key. Since the key_data array follows the tls + // array, it basically gives us the extra entry we need. + // TODO(kostyak): remove and restrict to N and above. + CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); + initScudo(); + NumberOfContexts = getNumberOfCPUs(); + ThreadContexts = reinterpret_cast<ScudoThreadContext *>( + MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__)); + for (int i = 0; i < NumberOfContexts; i++) + ThreadContexts[i].init(); +} + +void initThread() { + pthread_once(&GlobalInitialized, initOnce); + // Initial context assignment is done in a plain round-robin fashion. + u32 Index = atomic_fetch_add(&ThreadContextCurrentIndex, 1, + memory_order_relaxed); + ScudoThreadContext *ThreadContext = + &ThreadContexts[Index % NumberOfContexts]; + *get_android_tls_ptr() = reinterpret_cast<uptr>(ThreadContext); +} + +ScudoThreadContext *getThreadContextAndLockSlow() { + ScudoThreadContext *ThreadContext; + // Go through all the contexts and find the first unlocked one. + for (u32 i = 0; i < NumberOfContexts; i++) { + ThreadContext = &ThreadContexts[i]; + if (ThreadContext->tryLock()) { + *get_android_tls_ptr() = reinterpret_cast<uptr>(ThreadContext); + return ThreadContext; + } + } + // No luck, find the one with the lowest precedence, and slow lock it. + u64 Precedence = UINT64_MAX; + for (u32 i = 0; i < NumberOfContexts; i++) { + u64 SlowLockPrecedence = ThreadContexts[i].getSlowLockPrecedence(); + if (SlowLockPrecedence && SlowLockPrecedence < Precedence) { + ThreadContext = &ThreadContexts[i]; + Precedence = SlowLockPrecedence; + } + } + if (LIKELY(Precedence != UINT64_MAX)) { + ThreadContext->lock(); + *get_android_tls_ptr() = reinterpret_cast<uptr>(ThreadContext); + return ThreadContext; + } + // Last resort (can this happen?), stick with the current one. + ThreadContext = + reinterpret_cast<ScudoThreadContext *>(*get_android_tls_ptr()); + ThreadContext->lock(); + return ThreadContext; +} + +} // namespace __scudo + +#endif // SANITIZER_LINUX && SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_android.inc b/lib/scudo/scudo_tls_android.inc new file mode 100644 index 000000000000..8ecad7a30a6c --- /dev/null +++ b/lib/scudo/scudo_tls_android.inc @@ -0,0 +1,44 @@ +//===-- scudo_tls_android.inc -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Scudo thread local structure fastpath functions implementation for Android. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_ANDROID_H_ +#define SCUDO_TLS_ANDROID_H_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && SANITIZER_ANDROID + +ALWAYS_INLINE void initThreadMaybe() { + if (LIKELY(*get_android_tls_ptr())) + return; + initThread(); +} + +ScudoThreadContext *getThreadContextAndLockSlow(); + +ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { + ScudoThreadContext *ThreadContext = + reinterpret_cast<ScudoThreadContext *>(*get_android_tls_ptr()); + CHECK(ThreadContext); + // Try to lock the currently associated context. + if (ThreadContext->tryLock()) + return ThreadContext; + // If it failed, go the slow path. + return getThreadContextAndLockSlow(); +} + +#endif // SANITIZER_LINUX && SANITIZER_ANDROID + +#endif // SCUDO_TLS_ANDROID_H_ diff --git a/lib/scudo/scudo_tls_context_android.inc b/lib/scudo/scudo_tls_context_android.inc new file mode 100644 index 000000000000..f1951319d487 --- /dev/null +++ b/lib/scudo/scudo_tls_context_android.inc @@ -0,0 +1,54 @@ +//===-- scudo_tls_context_android.inc ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Android specific base thread context definition. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_CONTEXT_ANDROID_INC_ +#define SCUDO_TLS_CONTEXT_ANDROID_INC_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && SANITIZER_ANDROID + +struct ScudoThreadContextPlatform { + INLINE bool tryLock() { + if (Mutex.TryLock()) { + atomic_store_relaxed(&SlowLockPrecedence, 0); + return true; + } + if (atomic_load_relaxed(&SlowLockPrecedence) == 0) + atomic_store_relaxed(&SlowLockPrecedence, NanoTime()); + return false; + } + + INLINE void lock() { + Mutex.Lock(); + atomic_store_relaxed(&SlowLockPrecedence, 0); + } + + INLINE void unlock() { + Mutex.Unlock(); + } + + INLINE u64 getSlowLockPrecedence() { + return atomic_load_relaxed(&SlowLockPrecedence); + } + + private: + StaticSpinMutex Mutex; + atomic_uint64_t SlowLockPrecedence; +}; + +#endif // SANITIZER_LINUX && SANITIZER_ANDROID + +#endif // SCUDO_TLS_CONTEXT_ANDROID_INC_ diff --git a/lib/scudo/scudo_tls_context_linux.inc b/lib/scudo/scudo_tls_context_linux.inc new file mode 100644 index 000000000000..8d292bdbc932 --- /dev/null +++ b/lib/scudo/scudo_tls_context_linux.inc @@ -0,0 +1,29 @@ +//===-- scudo_tls_context_linux.inc -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Linux specific base thread context definition. +/// +//===----------------------------------------------------------------------===// + +#ifndef SCUDO_TLS_CONTEXT_LINUX_INC_ +#define SCUDO_TLS_CONTEXT_LINUX_INC_ + +#ifndef SCUDO_TLS_H_ +# error "This file must be included inside scudo_tls.h." +#endif // SCUDO_TLS_H_ + +#if SANITIZER_LINUX && !SANITIZER_ANDROID + +struct ScudoThreadContextPlatform { + ALWAYS_INLINE void unlock() {} +}; + +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID + +#endif // SCUDO_TLS_CONTEXT_LINUX_INC_ diff --git a/lib/scudo/scudo_tls_linux.cpp b/lib/scudo/scudo_tls_linux.cpp index 3453367f8a53..5a9cc998bccf 100644 --- a/lib/scudo/scudo_tls_linux.cpp +++ b/lib/scudo/scudo_tls_linux.cpp @@ -14,7 +14,7 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID #include "scudo_tls.h" @@ -26,8 +26,10 @@ namespace __scudo { static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; static pthread_key_t PThreadKey; -thread_local ThreadState ScudoThreadState = ThreadNotInitialized; -thread_local ScudoThreadContext ThreadLocalContext; +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ThreadState ScudoThreadState = ThreadNotInitialized; +__attribute__((tls_model("initial-exec"))) +THREADLOCAL ScudoThreadContext ThreadLocalContext; static void teardownThread(void *Ptr) { uptr Iteration = reinterpret_cast<uptr>(Ptr); @@ -59,4 +61,4 @@ void initThread() { } // namespace __scudo -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID diff --git a/lib/scudo/scudo_tls_linux.h b/lib/scudo/scudo_tls_linux.inc index 0994f2d7b24d..242ee3329ea8 100644 --- a/lib/scudo/scudo_tls_linux.h +++ b/lib/scudo/scudo_tls_linux.inc @@ -1,4 +1,4 @@ -//===-- scudo_tls_linux.h ---------------------------------------*- C++ -*-===// +//===-- scudo_tls_linux.inc -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -19,17 +19,17 @@ # error "This file must be included inside scudo_tls.h." #endif // SCUDO_TLS_H_ -#include "sanitizer_common/sanitizer_platform.h" - -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID enum ThreadState : u8 { ThreadNotInitialized = 0, ThreadInitialized, ThreadTornDown, }; -extern thread_local ThreadState ScudoThreadState; -extern thread_local ScudoThreadContext ThreadLocalContext; +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ThreadState ScudoThreadState; +__attribute__((tls_model("initial-exec"))) +extern THREADLOCAL ScudoThreadContext ThreadLocalContext; ALWAYS_INLINE void initThreadMaybe() { if (LIKELY(ScudoThreadState != ThreadNotInitialized)) @@ -37,12 +37,12 @@ ALWAYS_INLINE void initThreadMaybe() { initThread(); } -ALWAYS_INLINE ScudoThreadContext *getThreadContext() { +ALWAYS_INLINE ScudoThreadContext *getThreadContextAndLock() { if (UNLIKELY(ScudoThreadState == ThreadTornDown)) return nullptr; return &ThreadLocalContext; } -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID #endif // SCUDO_TLS_LINUX_H_ diff --git a/lib/ubsan/CMakeLists.txt b/lib/ubsan/CMakeLists.txt index f35b40f3b1cc..7e10456e3142 100644 --- a/lib/ubsan/CMakeLists.txt +++ b/lib/ubsan/CMakeLists.txt @@ -9,6 +9,7 @@ set(UBSAN_SOURCES ) set(UBSAN_STANDALONE_SOURCES + ubsan_diag_standalone.cc ubsan_init_standalone.cc ) diff --git a/lib/ubsan/ubsan_diag_standalone.cc b/lib/ubsan/ubsan_diag_standalone.cc new file mode 100644 index 000000000000..df8ed5fcdf6d --- /dev/null +++ b/lib/ubsan/ubsan_diag_standalone.cc @@ -0,0 +1,37 @@ +//===-- ubsan_diag_standalone.cc ------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Diagnostic reporting for the standalone UBSan runtime. +// +//===----------------------------------------------------------------------===// + +#include "ubsan_platform.h" +#if CAN_SANITIZE_UB +#include "ubsan_diag.h" + +using namespace __ubsan; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_print_stack_trace() { + uptr top = 0; + uptr bottom = 0; + bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; + if (request_fast_unwind) + __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom); + + GET_REPORT_OPTIONS(false); + BufferedStackTrace stack; + stack.Unwind(kStackTraceMax, Opts.pc, Opts.bp, nullptr, top, bottom, + request_fast_unwind); + stack.Print(); +} +} // extern "C" + +#endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index de13ab893bec..d6a8f52a27b4 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -410,7 +410,8 @@ static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val, SourceLocation Loc = Data->Loc.acquire(); // This check could be more precise if we used different handlers for // -fsanitize=bool and -fsanitize=enum. - bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")); + bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) || + (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6)); ErrorType ET = IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad; diff --git a/lib/xray/xray_init.cc b/lib/xray/xray_init.cc index 6f558d656147..aa660baa9920 100644 --- a/lib/xray/xray_init.cc +++ b/lib/xray/xray_init.cc @@ -25,6 +25,8 @@ extern "C" { void __xray_init(); extern const XRaySledEntry __start_xray_instr_map[] __attribute__((weak)); extern const XRaySledEntry __stop_xray_instr_map[] __attribute__((weak)); +extern const XRayFunctionSledIndex __start_xray_fn_idx[] __attribute__((weak)); +extern const XRayFunctionSledIndex __stop_xray_fn_idx[] __attribute__((weak)); } using namespace __xray; @@ -55,6 +57,8 @@ void __xray_init() XRAY_NEVER_INSTRUMENT { __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); XRayInstrMap.Sleds = __start_xray_instr_map; XRayInstrMap.Entries = __stop_xray_instr_map - __start_xray_instr_map; + XRayInstrMap.SledsIndex = __start_xray_fn_idx; + XRayInstrMap.Functions = __stop_xray_fn_idx - __start_xray_fn_idx; } __sanitizer::atomic_store(&XRayInitialized, true, __sanitizer::memory_order_release); diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc index 26ec161fe860..26f0ab122db2 100644 --- a/lib/xray/xray_interface.cc +++ b/lib/xray/xray_interface.cc @@ -132,12 +132,48 @@ CleanupInvoker<Function> scopeCleanup(Function Fn) XRAY_NEVER_INSTRUMENT { return CleanupInvoker<Function>{Fn}; } +inline bool patchSled(const XRaySledEntry &Sled, bool Enable, + int32_t FuncId) XRAY_NEVER_INSTRUMENT { + // While we're here, we should patch the nop sled. To do that we mprotect + // the page containing the function to be writeable. + const uint64_t PageSize = GetPageSizeCached(); + void *PageAlignedAddr = + reinterpret_cast<void *>(Sled.Address & ~(PageSize - 1)); + std::size_t MProtectLen = (Sled.Address + cSledLength) - + reinterpret_cast<uint64_t>(PageAlignedAddr); + MProtectHelper Protector(PageAlignedAddr, MProtectLen); + if (Protector.MakeWriteable() == -1) { + printf("Failed mprotect: %d\n", errno); + return XRayPatchingStatus::FAILED; + } + + bool Success = false; + switch (Sled.Kind) { + case XRayEntryType::ENTRY: + Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_FunctionEntry); + break; + case XRayEntryType::EXIT: + Success = patchFunctionExit(Enable, FuncId, Sled); + break; + case XRayEntryType::TAIL: + Success = patchFunctionTailExit(Enable, FuncId, Sled); + break; + case XRayEntryType::LOG_ARGS_ENTRY: + Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); + break; + default: + Report("Unsupported sled kind '%d' @%04x\n", Sled.Address, int(Sled.Kind)); + return false; + } + return Success; +} + // controlPatching implements the common internals of the patching/unpatching // implementation. |Enable| defines whether we're enabling or disabling the // runtime XRay instrumentation. XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { if (!__sanitizer::atomic_load(&XRayInitialized, - __sanitizer::memory_order_acquire)) + __sanitizer::memory_order_acquire)) return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. uint8_t NotPatching = false; @@ -179,38 +215,7 @@ XRayPatchingStatus controlPatching(bool Enable) XRAY_NEVER_INSTRUMENT { ++FuncId; CurFun = F; } - - // While we're here, we should patch the nop sled. To do that we mprotect - // the page containing the function to be writeable. - void *PageAlignedAddr = - reinterpret_cast<void *>(Sled.Address & ~(PageSize - 1)); - std::size_t MProtectLen = (Sled.Address + cSledLength) - - reinterpret_cast<uint64_t>(PageAlignedAddr); - MProtectHelper Protector(PageAlignedAddr, MProtectLen); - if (Protector.MakeWriteable() == -1) { - printf("Failed mprotect: %d\n", errno); - return XRayPatchingStatus::FAILED; - } - - bool Success = false; - switch (Sled.Kind) { - case XRayEntryType::ENTRY: - Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_FunctionEntry); - break; - case XRayEntryType::EXIT: - Success = patchFunctionExit(Enable, FuncId, Sled); - break; - case XRayEntryType::TAIL: - Success = patchFunctionTailExit(Enable, FuncId, Sled); - break; - case XRayEntryType::LOG_ARGS_ENTRY: - Success = patchFunctionEntry(Enable, FuncId, Sled, __xray_ArgLoggerEntry); - break; - default: - Report("Unsupported sled kind: %d\n", int(Sled.Kind)); - continue; - } - (void)Success; + patchSled(Sled, Enable, FuncId); } __sanitizer::atomic_store(&XRayPatching, false, __sanitizer::memory_order_release); @@ -226,6 +231,64 @@ XRayPatchingStatus __xray_unpatch() XRAY_NEVER_INSTRUMENT { return controlPatching(false); } +XRayPatchingStatus patchFunction(int32_t FuncId, + bool Enable) XRAY_NEVER_INSTRUMENT { + if (!__sanitizer::atomic_load(&XRayInitialized, + __sanitizer::memory_order_acquire)) + return XRayPatchingStatus::NOT_INITIALIZED; // Not initialized. + + uint8_t NotPatching = false; + if (!__sanitizer::atomic_compare_exchange_strong( + &XRayPatching, &NotPatching, true, __sanitizer::memory_order_acq_rel)) + return XRayPatchingStatus::ONGOING; // Already patching. + + // Next, we look for the function index. + XRaySledMap InstrMap; + { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + InstrMap = XRayInstrMap; + } + + // If we don't have an index, we can't patch individual functions. + if (InstrMap.Functions == 0) + return XRayPatchingStatus::NOT_INITIALIZED; + + // FuncId must be a positive number, less than the number of functions + // instrumented. + if (FuncId <= 0 || static_cast<size_t>(FuncId) > InstrMap.Functions) { + Report("Invalid function id provided: %d\n", FuncId); + return XRayPatchingStatus::FAILED; + } + + // Now we patch ths sleds for this specific function. + auto SledRange = InstrMap.SledsIndex[FuncId - 1]; + auto *f = SledRange.Begin; + auto *e = SledRange.End; + + bool SucceedOnce = false; + while (f != e) + SucceedOnce |= patchSled(*f++, Enable, FuncId); + + __sanitizer::atomic_store(&XRayPatching, false, + __sanitizer::memory_order_release); + + if (!SucceedOnce) { + Report("Failed patching any sled for function '%d'.", FuncId); + return XRayPatchingStatus::FAILED; + } + + return XRayPatchingStatus::SUCCESS; +} + +XRayPatchingStatus __xray_patch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { + return patchFunction(FuncId, true); +} + +XRayPatchingStatus +__xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { + return patchFunction(FuncId, false); +} + int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { if (!__sanitizer::atomic_load(&XRayInitialized, __sanitizer::memory_order_acquire)) @@ -239,3 +302,15 @@ int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { return 1; } int __xray_remove_handler_arg1() { return __xray_set_handler_arg1(nullptr); } + +uintptr_t __xray_function_address(int32_t FuncId) XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + if (FuncId <= 0 || static_cast<size_t>(FuncId) > XRayInstrMap.Functions) + return 0; + return XRayInstrMap.SledsIndex[FuncId - 1].Begin->Address; +} + +size_t __xray_max_function_id() XRAY_NEVER_INSTRUMENT { + __sanitizer::SpinMutexLock Guard(&XRayInstrMapMutex); + return XRayInstrMap.Functions; +} diff --git a/lib/xray/xray_interface_internal.h b/lib/xray/xray_interface_internal.h index 0e3a251f3ad7..ef0c6b15809b 100644 --- a/lib/xray/xray_interface_internal.h +++ b/lib/xray/xray_interface_internal.h @@ -39,6 +39,11 @@ struct XRaySledEntry { #error "Unsupported word size." #endif }; + +struct XRayFunctionSledIndex { + const XRaySledEntry* Begin; + const XRaySledEntry* End; +}; } namespace __xray { @@ -46,6 +51,8 @@ namespace __xray { struct XRaySledMap { const XRaySledEntry *Sleds; size_t Entries; + const XRayFunctionSledIndex *SledsIndex; + size_t Functions; }; bool patchFunctionEntry(bool Enable, uint32_t FuncId, diff --git a/test/asan/TestCases/Linux/longjmp_chk.c b/test/asan/TestCases/Linux/longjmp_chk.c new file mode 100644 index 000000000000..99a4a163054c --- /dev/null +++ b/test/asan/TestCases/Linux/longjmp_chk.c @@ -0,0 +1,51 @@ +// Verify that use of longjmp() in a _FORTIFY_SOURCE'd library (without ASAN) +// is correctly intercepted such that the stack is unpoisoned. +// Note: it is essential that the external library is not built with ASAN, +// otherwise it would be able to unpoison the stack before use. +// +// RUN: %clang -DIS_LIBRARY -D_FORTIFY_SOURCE=2 -O2 %s -c -o %t.o +// RUN: %clang_asan -O2 %s %t.o -o %t +// RUN: %run %t + +#ifdef IS_LIBRARY +/* the library */ +#include <setjmp.h> +#include <assert.h> +#include <sanitizer/asan_interface.h> + +static jmp_buf jenv; + +void external_callme(void (*callback)(void)) { + if (setjmp(jenv) == 0) { + callback(); + } +} + +void external_longjmp(char *msg) { + longjmp(jenv, 1); +} + +void external_check_stack(void) { + char buf[256] = ""; + for (int i = 0; i < 256; i++) { + assert(!__asan_address_is_poisoned(buf + i)); + } +} +#else +/* main program */ +extern void external_callme(void (*callback)(void)); +extern void external_longjmp(char *msg); +extern void external_check_stack(void); + +static void callback(void) { + char msg[16]; /* Note: this triggers addition of a redzone. */ + /* Note: msg is passed to prevent compiler optimization from removing it. */ + external_longjmp(msg); +} + +int main() { + external_callme(callback); + external_check_stack(); + return 0; +} +#endif diff --git a/test/builtins/Unit/divxc3_test.c b/test/builtins/Unit/divxc3_test.c index d0cdb0169ebf..6517ef124891 100644 --- a/test/builtins/Unit/divxc3_test.c +++ b/test/builtins/Unit/divxc3_test.c @@ -19,6 +19,7 @@ #include <complex.h> #include <stdio.h> +// UNSUPPORTED: mips // REQUIRES: c99-complex // Returns: the quotient of (a + ib) / (c + id) diff --git a/test/builtins/Unit/fixunstfti_test.c b/test/builtins/Unit/fixunstfti_test.c index 019b72049dd9..eaf4b8fb5ffc 100644 --- a/test/builtins/Unit/fixunstfti_test.c +++ b/test/builtins/Unit/fixunstfti_test.c @@ -14,6 +14,8 @@ #include <stdio.h> +// UNSUPPORTED: mips + #if __LDBL_MANT_DIG__ == 113 #include "fp_test.h" diff --git a/test/builtins/Unit/fixunsxfti_test.c b/test/builtins/Unit/fixunsxfti_test.c index 28a7e9783c53..0a48a7332703 100644 --- a/test/builtins/Unit/fixunsxfti_test.c +++ b/test/builtins/Unit/fixunsxfti_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- fixunsxfti_test.c - Test __fixunsxfti -----------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/fixxfti_test.c b/test/builtins/Unit/fixxfti_test.c index c6d42c6e1310..e5e15ab780d4 100644 --- a/test/builtins/Unit/fixxfti_test.c +++ b/test/builtins/Unit/fixxfti_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- fixxfti_test.c - Test __fixxfti -----------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floattixf_test.c b/test/builtins/Unit/floattixf_test.c index 00644fae19c0..3de4729342d2 100644 --- a/test/builtins/Unit/floattixf_test.c +++ b/test/builtins/Unit/floattixf_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- floattixf.c - Test __floattixf ------------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/floatuntixf_test.c b/test/builtins/Unit/floatuntixf_test.c index 70ad5f36f3f7..2d71f0f88604 100644 --- a/test/builtins/Unit/floatuntixf_test.c +++ b/test/builtins/Unit/floatuntixf_test.c @@ -2,6 +2,8 @@ // XFAIL: aarch64 // test fails for aarch64 (see pr32260) +// UNSUPPORTED: mips + //===-- floatuntixf.c - Test __floatuntixf --------------------------------===// // // The LLVM Compiler Infrastructure diff --git a/test/builtins/Unit/mulxc3_test.c b/test/builtins/Unit/mulxc3_test.c index 3260b7521dec..c48b0da50692 100644 --- a/test/builtins/Unit/mulxc3_test.c +++ b/test/builtins/Unit/mulxc3_test.c @@ -19,6 +19,7 @@ #include <complex.h> #include <stdio.h> +// UNSUPPORTED: mips // REQUIRES: c99-complex // Returns: the product of a + ib and c + id diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc new file mode 100644 index 000000000000..8430539829b0 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_no_prune.cc @@ -0,0 +1,15 @@ +// Tests -fsanitize-coverage=no-prune +// +// REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: i386-darwin +// XFAIL: tsan,powerpc64,s390x,mips +// +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,bb 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 2 +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc,no-prune 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 4 +// RUN: %clangxx -O0 %s -S -o - -emit-llvm -fsanitize-coverage=trace-pc 2>&1 | grep "call void @__sanitizer_cov_trace_pc" | count 3 + +void foo(int *a) { + if (a) + *a = 1; +} diff --git a/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc b/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc new file mode 100644 index 000000000000..341fd7a823b0 --- /dev/null +++ b/test/ubsan/TestCases/Misc/Linux/print_stack_trace.cc @@ -0,0 +1,23 @@ +// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=1 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx -fsanitize=undefined -O0 %s -o %t && UBSAN_OPTIONS=stack_trace_format=DEFAULT:fast_unwind_on_fatal=0 %run %t 2>&1 | FileCheck %s + +// This test is temporarily disabled due to broken unwinding on ARM. +// UNSUPPORTED: -linux- + +// The test doesn't pass on Darwin in UBSan-TSan configuration, because TSan is +// using the slow unwinder which is not supported on Darwin. The test should +// be universal after landing of https://reviews.llvm.org/D32806. + +#include <sanitizer/common_interface_defs.h> + +static inline void FooBarBaz() { + __sanitizer_print_stack_trace(); +} + +int main() { + FooBarBaz(); + return 0; +} + +// CHECK: {{.*}} in FooBarBaz{{.*}}print_stack_trace.cc{{.*}} +// CHECK: {{.*}} in main{{.*}}print_stack_trace.cc{{.*}} diff --git a/test/ubsan/TestCases/Misc/bool.m b/test/ubsan/TestCases/Misc/bool.m new file mode 100644 index 000000000000..0430b452b987 --- /dev/null +++ b/test/ubsan/TestCases/Misc/bool.m @@ -0,0 +1,14 @@ +// RUN: %clang -fsanitize=bool %s -O3 -o %t +// RUN: not %run %t 2>&1 | FileCheck %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 not %run %t 2>&1 | FileCheck %s --check-prefix=SUMMARY + +typedef char BOOL; +unsigned char NotABool = 123; + +int main(int argc, char **argv) { + BOOL *p = (BOOL*)&NotABool; + + // CHECK: bool.m:[[@LINE+1]]:10: runtime error: load of value 123, which is not a valid value for type 'BOOL' + return *p; + // SUMMARY: SUMMARY: {{.*}}Sanitizer: invalid-bool-load {{.*}}bool.m:[[@LINE-1]] +} diff --git a/test/xray/TestCases/Linux/coverage-sample.cc b/test/xray/TestCases/Linux/coverage-sample.cc new file mode 100644 index 000000000000..df23d9f738de --- /dev/null +++ b/test/xray/TestCases/Linux/coverage-sample.cc @@ -0,0 +1,91 @@ +// Check that we can patch and unpatch specific function ids. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s +// FIXME: When run this test case causes a segementation fault on powerpc64le. +// Remove the xfail when the problem is fixed. +// XFAIL: powerpc64le + +#include "xray/xray_interface.h" + +#include <set> +#include <cstdio> + +std::set<int32_t> function_ids; + +[[clang::xray_never_instrument]] void coverage_handler(int32_t fid, + XRayEntryType) { + thread_local bool patching = false; + if (patching) return; + patching = true; + function_ids.insert(fid); + __xray_unpatch_function(fid); + patching = false; +} + +[[clang::xray_always_instrument]] void baz() { + // do nothing! +} + +[[clang::xray_always_instrument]] void bar() { + baz(); +} + +[[clang::xray_always_instrument]] void foo() { + bar(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + __xray_set_handler(coverage_handler); + __xray_patch(); + foo(); + __xray_unpatch(); + + // print out the function_ids. + printf("first pass.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + + // CHECK-LABEL: first pass. + // CHECK-DAG: patched: [[F1:.*]] + // CHECK-DAG: patched: [[F2:.*]] + // CHECK-DAG: patched: [[F3:.*]] + + // make a copy of the function_ids, then patch them later. + auto called_fns = function_ids; + + // clear the function_ids. + function_ids.clear(); + + // patch the functions we've called before. + for (const auto id : called_fns) + __xray_patch_function(id); + + // then call them again. + foo(); + __xray_unpatch(); + + // confirm that we've seen the same functions again. + printf("second pass.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + // CHECK-LABEL: second pass. + // CHECK-DAG: patched: [[F1]] + // CHECK-DAG: patched: [[F2]] + // CHECK-DAG: patched: [[F3]] + + // Now we want to make sure that if we unpatch one, that we're only going to + // see two calls of the coverage_handler. + function_ids.clear(); + __xray_patch(); + __xray_unpatch_function(1); + foo(); + __xray_unpatch(); + + // confirm that we don't see function id one called anymore. + printf("missing 1.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + // CHECK-LABEL: missing 1. + // CHECK-NOT: patched: 1 +} diff --git a/test/xray/TestCases/Linux/func-id-utils.cc b/test/xray/TestCases/Linux/func-id-utils.cc new file mode 100644 index 000000000000..82ba34d30acc --- /dev/null +++ b/test/xray/TestCases/Linux/func-id-utils.cc @@ -0,0 +1,44 @@ +// Check that we can turn a function id to a function address, and also get the +// maximum function id for the current binary. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t +// FIXME: When we know why this fails in ppc, un-xfail it. +// XFAIL: powerpc64le + +#include "xray/xray_interface.h" +#include <algorithm> +#include <cassert> +#include <cstdio> +#include <iterator> +#include <set> + +[[clang::xray_always_instrument]] void bar(){} + +[[clang::xray_always_instrument]] void foo() { + bar(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + assert(__xray_max_function_id() != 0 && "we need xray instrumentation!"); + std::set<void *> must_be_instrumented = {reinterpret_cast<void *>(&foo), + reinterpret_cast<void *>(&bar), + reinterpret_cast<void *>(&main)}; + std::set<void *> all_instrumented; + for (auto i = __xray_max_function_id(); i != 0; --i) { + auto addr = __xray_function_address(i); + all_instrumented.insert(reinterpret_cast<void *>(addr)); + } + assert(all_instrumented.size() == __xray_max_function_id() && + "each function id must be assigned to a unique function"); + + std::set<void *> common; + std::set_intersection(all_instrumented.begin(), all_instrumented.end(), + must_be_instrumented.begin(), + must_be_instrumented.end(), + std::inserter(common, common.begin())); + assert( + common == must_be_instrumented && + "we should see all explicitly instrumented functions with function ids"); + return common == must_be_instrumented ? 0 : 1; +} |