diff options
author | Martin Liska <mliska@suse.cz> | 2023-04-26 09:42:29 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2023-04-26 15:51:56 +0200 |
commit | d53b3d94aaf211ffb2159614f5aaaf03ceb861cc (patch) | |
tree | 4202fe134ccc618029a07e7d1913c608bd7fb77f /libsanitizer/asan | |
parent | a8e1551bdb372aa3cfe754429b5efd6229ae5fdb (diff) | |
download | gcc-d53b3d94aaf211ffb2159614f5aaaf03ceb861cc.zip gcc-d53b3d94aaf211ffb2159614f5aaaf03ceb861cc.tar.gz gcc-d53b3d94aaf211ffb2159614f5aaaf03ceb861cc.tar.bz2 |
libsanitizer: merge from upstream (3185e47b5a8444e9fd).
Diffstat (limited to 'libsanitizer/asan')
-rw-r--r-- | libsanitizer/asan/asan_allocator.cpp | 50 | ||||
-rw-r--r-- | libsanitizer/asan/asan_allocator.h | 8 | ||||
-rw-r--r-- | libsanitizer/asan/asan_errors.cpp | 20 | ||||
-rw-r--r-- | libsanitizer/asan/asan_errors.h | 67 | ||||
-rw-r--r-- | libsanitizer/asan/asan_globals.cpp | 19 | ||||
-rw-r--r-- | libsanitizer/asan/asan_interceptors.cpp | 59 | ||||
-rw-r--r-- | libsanitizer/asan/asan_interceptors.h | 7 | ||||
-rw-r--r-- | libsanitizer/asan/asan_internal.h | 2 | ||||
-rw-r--r-- | libsanitizer/asan/asan_linux.cpp | 164 | ||||
-rw-r--r-- | libsanitizer/asan/asan_mac.cpp | 6 | ||||
-rw-r--r-- | libsanitizer/asan/asan_malloc_win.cpp | 8 | ||||
-rw-r--r-- | libsanitizer/asan/asan_mapping.h | 2 | ||||
-rw-r--r-- | libsanitizer/asan/asan_memory_profile.cpp | 19 | ||||
-rw-r--r-- | libsanitizer/asan/asan_poisoning.cpp | 334 | ||||
-rw-r--r-- | libsanitizer/asan/asan_report.cpp | 12 | ||||
-rw-r--r-- | libsanitizer/asan/asan_report.h | 4 | ||||
-rw-r--r-- | libsanitizer/asan/asan_thread.cpp | 86 | ||||
-rw-r--r-- | libsanitizer/asan/asan_win.cpp | 6 |
18 files changed, 584 insertions, 289 deletions
diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp index 52d7eff..19d7777 100644 --- a/libsanitizer/asan/asan_allocator.cpp +++ b/libsanitizer/asan/asan_allocator.cpp @@ -1094,10 +1094,16 @@ uptr PointsIntoChunk(void *p) { } uptr GetUserBegin(uptr chunk) { + // FIXME: All usecases provide chunk address, GetAsanChunkByAddrFastLocked is + // not needed. __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk); return m ? m->Beg() : 0; } +uptr GetUserAddr(uptr chunk) { + return chunk; +} + LsanMetadata::LsanMetadata(uptr chunk) { metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize) : nullptr; @@ -1138,7 +1144,7 @@ void ForEachChunk(ForEachChunkCallback callback, void *arg) { __asan::get_allocator().ForEachChunk(callback, arg); } -IgnoreObjectResult IgnoreObjectLocked(const void *p) { +IgnoreObjectResult IgnoreObject(const void *p) { uptr addr = reinterpret_cast<uptr>(p); __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr); if (!m || @@ -1153,38 +1159,22 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) { return kIgnoreObjectSuccess; } -void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) { - // Look for the arg pointer of threads that have been created or are running. - // This is necessary to prevent false positive leaks due to the AsanThread - // holding the only live reference to a heap object. This can happen because - // the `pthread_create()` interceptor doesn't wait for the child thread to - // start before returning and thus loosing the the only live reference to the - // heap object on the stack. - - __asan::AsanThreadContext *atctx = - reinterpret_cast<__asan::AsanThreadContext *>(tctx); - __asan::AsanThread *asan_thread = atctx->thread; - - // Note ThreadStatusRunning is required because there is a small window where - // the thread status switches to `ThreadStatusRunning` but the `arg` pointer - // still isn't on the stack yet. - if (atctx->status != ThreadStatusCreated && - atctx->status != ThreadStatusRunning) - return; - - uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg()); - if (!thread_arg) - return; - - auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs); - ptrsVec->push_back(thread_arg); -} - } // namespace __lsan // ---------------------- Interface ---------------- {{{1 using namespace __asan; +static const void *AllocationBegin(const void *p) { + AsanChunk *m = __asan::instance.GetAsanChunkByAddr((uptr)p); + if (!m) + return nullptr; + if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED) + return nullptr; + if (m->UsedSize() == 0) + return nullptr; + return (const void *)(m->Beg()); +} + // ASan allocator doesn't reserve extra bytes, so normally we would // just return "size". We don't want to expose our redzone sizes, etc here. uptr __sanitizer_get_estimated_allocated_size(uptr size) { @@ -1208,6 +1198,10 @@ uptr __sanitizer_get_allocated_size(const void *p) { return allocated_size; } +const void *__sanitizer_get_allocated_begin(const void *p) { + return AllocationBegin(p); +} + void __sanitizer_purge_allocator() { GET_STACK_TRACE_MALLOC; instance.Purge(&stack); diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h index 0b4dbf0..6a12a6c 100644 --- a/libsanitizer/asan/asan_allocator.h +++ b/libsanitizer/asan/asan_allocator.h @@ -143,11 +143,15 @@ typedef DefaultSizeClassMap SizeClassMap; const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x8000000000ULL; // 500G typedef DefaultSizeClassMap SizeClassMap; -# else +# elif SANITIZER_APPLE const uptr kAllocatorSpace = 0x600000000000ULL; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. typedef DefaultSizeClassMap SizeClassMap; -# endif +# else +const uptr kAllocatorSpace = 0x500000000000ULL; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +typedef DefaultSizeClassMap SizeClassMap; +# endif template <typename AddressSpaceViewTy> struct AP64 { // Allocator64 parameters. Deliberately using a short name. static const uptr kSpaceBeg = kAllocatorSpace; diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp index f3befdf..cc8dc26 100644 --- a/libsanitizer/asan/asan_errors.cpp +++ b/libsanitizer/asan/asan_errors.cpp @@ -334,6 +334,26 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() { ReportErrorSummary(scariness.GetDescription(), stack); } +void ErrorBadParamsToAnnotateDoubleEndedContiguousContainer::Print() { + Report( + "ERROR: AddressSanitizer: bad parameters to " + "__sanitizer_annotate_double_ended_contiguous_container:\n" + " storage_beg : %p\n" + " storage_end : %p\n" + " old_container_beg : %p\n" + " old_container_end : %p\n" + " new_container_beg : %p\n" + " new_container_end : %p\n", + (void *)storage_beg, (void *)storage_end, (void *)old_container_beg, + (void *)old_container_end, (void *)new_container_beg, + (void *)new_container_end); + uptr granularity = ASAN_SHADOW_GRANULARITY; + if (!IsAligned(storage_beg, granularity)) + Report("ERROR: storage_beg is not aligned by %zu\n", granularity); + stack->Print(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + void ErrorODRViolation::Print() { Decorator d; Printf("%s", d.Error()); diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h index c6ac88f..634f6da 100644 --- a/libsanitizer/asan/asan_errors.h +++ b/libsanitizer/asan/asan_errors.h @@ -331,6 +331,28 @@ struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase { void Print(); }; +struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase { + const BufferedStackTrace *stack; + uptr storage_beg, storage_end, old_container_beg, old_container_end, + new_container_beg, new_container_end; + + ErrorBadParamsToAnnotateDoubleEndedContiguousContainer() = default; // (*) + ErrorBadParamsToAnnotateDoubleEndedContiguousContainer( + u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_, + uptr old_container_beg_, uptr old_container_end_, uptr new_container_beg_, + uptr new_container_end_) + : ErrorBase(tid, 10, + "bad-__sanitizer_annotate_double_ended_contiguous_container"), + stack(stack_), + storage_beg(storage_beg_), + storage_end(storage_end_), + old_container_beg(old_container_beg_), + old_container_end(old_container_end_), + new_container_beg(new_container_beg_), + new_container_end(new_container_end_) {} + void Print(); +}; + struct ErrorODRViolation : ErrorBase { __asan_global global1, global2; u32 stack_id1, stack_id2; @@ -378,28 +400,29 @@ struct ErrorGeneric : ErrorBase { }; // clang-format off -#define ASAN_FOR_EACH_ERROR_KIND(macro) \ - macro(DeadlySignal) \ - macro(DoubleFree) \ - macro(NewDeleteTypeMismatch) \ - macro(FreeNotMalloced) \ - macro(AllocTypeMismatch) \ - macro(MallocUsableSizeNotOwned) \ - macro(SanitizerGetAllocatedSizeNotOwned) \ - macro(CallocOverflow) \ - macro(ReallocArrayOverflow) \ - macro(PvallocOverflow) \ - macro(InvalidAllocationAlignment) \ - macro(InvalidAlignedAllocAlignment) \ - macro(InvalidPosixMemalignAlignment) \ - macro(AllocationSizeTooBig) \ - macro(RssLimitExceeded) \ - macro(OutOfMemory) \ - macro(StringFunctionMemoryRangesOverlap) \ - macro(StringFunctionSizeOverflow) \ - macro(BadParamsToAnnotateContiguousContainer) \ - macro(ODRViolation) \ - macro(InvalidPointerPair) \ +#define ASAN_FOR_EACH_ERROR_KIND(macro) \ + macro(DeadlySignal) \ + macro(DoubleFree) \ + macro(NewDeleteTypeMismatch) \ + macro(FreeNotMalloced) \ + macro(AllocTypeMismatch) \ + macro(MallocUsableSizeNotOwned) \ + macro(SanitizerGetAllocatedSizeNotOwned) \ + macro(CallocOverflow) \ + macro(ReallocArrayOverflow) \ + macro(PvallocOverflow) \ + macro(InvalidAllocationAlignment) \ + macro(InvalidAlignedAllocAlignment) \ + macro(InvalidPosixMemalignAlignment) \ + macro(AllocationSizeTooBig) \ + macro(RssLimitExceeded) \ + macro(OutOfMemory) \ + macro(StringFunctionMemoryRangesOverlap) \ + macro(StringFunctionSizeOverflow) \ + macro(BadParamsToAnnotateContiguousContainer) \ + macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \ + macro(ODRViolation) \ + macro(InvalidPointerPair) \ macro(Generic) // clang-format on diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp index 01a2439..4d391cb 100644 --- a/libsanitizer/asan/asan_globals.cpp +++ b/libsanitizer/asan/asan_globals.cpp @@ -158,6 +158,23 @@ static void CheckODRViolationViaIndicator(const Global *g) { } } +// Check ODR violation for given global G by checking if it's already poisoned. +// We use this method in case compiler doesn't use private aliases for global +// variables. +static void CheckODRViolationViaPoisoning(const Global *g) { + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { + // This check may not be enough: if the first global is much larger + // the entire redzone of the second global may be within the first global. + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { + if (g->beg == l->g->beg && + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && + !IsODRViolationSuppressed(g->name)) + ReportODRViolation(g, FindRegistrationSite(g), + l->g, FindRegistrationSite(l->g)); + } + } +} + // Clang provides two different ways for global variables protection: // it can poison the global itself or its private alias. In former // case we may poison same symbol multiple times, that can help us to @@ -203,6 +220,8 @@ static void RegisterGlobal(const Global *g) { // where two globals with the same name are defined in different modules. if (UseODRIndicator(g)) CheckODRViolationViaIndicator(g); + else + CheckODRViolationViaPoisoning(g); } if (CanPoisonMemory()) PoisonRedZones(*g); diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp index 8170082..0f16005 100644 --- a/libsanitizer/asan/asan_interceptors.cpp +++ b/libsanitizer/asan/asan_interceptors.cpp @@ -257,12 +257,36 @@ static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) { PoisonShadow(bottom, ssize, 0); } -INTERCEPTOR(int, getcontext, struct ucontext_t *ucp) { - // API does not requires to have ucp clean, and sets only part of fields. We - // use ucp->uc_stack to unpoison new stack. We prefer to have zeroes then - // uninitialized bytes. - ResetContextStack(ucp); - return REAL(getcontext)(ucp); +INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc, + ...) { + va_list ap; + uptr args[64]; + // We don't know a better way to forward ... into REAL function. We can + // increase args size if neccecary. + CHECK_LE(argc, ARRAY_SIZE(args)); + internal_memset(args, 0, sizeof(args)); + va_start(ap, argc); + for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr); + va_end(ap); + +# define ENUMERATE_ARRAY_4(start) \ + args[start], args[start + 1], args[start + 2], args[start + 3] +# define ENUMERATE_ARRAY_16(start) \ + ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \ + ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12) +# define ENUMERATE_ARRAY_64() \ + ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \ + ENUMERATE_ARRAY_16(48) + + REAL(makecontext) + ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64()); + +# undef ENUMERATE_ARRAY_4 +# undef ENUMERATE_ARRAY_16 +# undef ENUMERATE_ARRAY_64 + + // Sign the stack so we can identify it for unpoisoning. + SignContextStack(ucp); } INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, @@ -279,9 +303,6 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, ReadContextStack(ucp, &stack, &ssize); ClearShadowMemoryForContextStack(stack, ssize); - // See getcontext interceptor. - ResetContextStack(oucp); - # if __has_attribute(__indirect_return__) && \ (defined(__x86_64__) || defined(__i386__)) int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *) @@ -453,7 +474,9 @@ INTERCEPTOR(char*, strdup, const char *s) { } GET_STACK_TRACE_MALLOC; void *new_mem = asan_malloc(length + 1, &stack); - REAL(memcpy)(new_mem, s, length + 1); + if (new_mem) { + REAL(memcpy)(new_mem, s, length + 1); + } return reinterpret_cast<char*>(new_mem); } @@ -469,7 +492,9 @@ INTERCEPTOR(char*, __strdup, const char *s) { } GET_STACK_TRACE_MALLOC; void *new_mem = asan_malloc(length + 1, &stack); - REAL(memcpy)(new_mem, s, length + 1); + if (new_mem) { + REAL(memcpy)(new_mem, s, length + 1); + } return reinterpret_cast<char*>(new_mem); } #endif // ASAN_INTERCEPT___STRDUP @@ -658,11 +683,11 @@ void InitializeAsanInterceptors() { // Intecept jump-related functions. ASAN_INTERCEPT_FUNC(longjmp); -#if ASAN_INTERCEPT_SWAPCONTEXT - ASAN_INTERCEPT_FUNC(getcontext); +# if ASAN_INTERCEPT_SWAPCONTEXT ASAN_INTERCEPT_FUNC(swapcontext); -#endif -#if ASAN_INTERCEPT__LONGJMP + ASAN_INTERCEPT_FUNC(makecontext); +# endif +# if ASAN_INTERCEPT__LONGJMP ASAN_INTERCEPT_FUNC(_longjmp); #endif #if ASAN_INTERCEPT___LONGJMP_CHK @@ -681,11 +706,11 @@ void InitializeAsanInterceptors() { #endif // Indirectly intercept std::rethrow_exception. #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION - INTERCEPT_FUNCTION(_Unwind_RaiseException); + ASAN_INTERCEPT_FUNC(_Unwind_RaiseException); #endif // Indirectly intercept std::rethrow_exception. #if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION - INTERCEPT_FUNCTION(_Unwind_SjLj_RaiseException); + ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException); #endif // Intercept threading-related functions diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h index 9a6c22c..c4bf087 100644 --- a/libsanitizer/asan/asan_interceptors.h +++ b/libsanitizer/asan/asan_interceptors.h @@ -81,12 +81,7 @@ void InitializePlatformInterceptors(); #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \ !SANITIZER_NETBSD # define ASAN_INTERCEPT___CXA_THROW 1 -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \ - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 -# else -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 -# endif +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 # else diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h index 959fdec..a5348e3 100644 --- a/libsanitizer/asan/asan_internal.h +++ b/libsanitizer/asan/asan_internal.h @@ -105,8 +105,8 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle); void AsanOnDeadlySignal(int, void *siginfo, void *context); +void SignContextStack(void *context); void ReadContextStack(void *context, uptr *stack, uptr *ssize); -void ResetContextStack(void *context); void StopInitOrderChecking(); // Wrapper for TLS/TSD. diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp index 89450fc..e19b447 100644 --- a/libsanitizer/asan/asan_linux.cpp +++ b/libsanitizer/asan/asan_linux.cpp @@ -15,55 +15,56 @@ #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ SANITIZER_SOLARIS -#include "asan_interceptors.h" -#include "asan_internal.h" -#include "asan_premap_shadow.h" -#include "asan_thread.h" -#include "sanitizer_common/sanitizer_flags.h" -#include "sanitizer_common/sanitizer_freebsd.h" -#include "sanitizer_common/sanitizer_libc.h" -#include "sanitizer_common/sanitizer_procmaps.h" - -#include <sys/time.h> -#include <sys/resource.h> -#include <sys/mman.h> -#include <sys/syscall.h> -#include <sys/types.h> -#include <dlfcn.h> -#include <fcntl.h> -#include <limits.h> -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> -#include <unwind.h> - -#if SANITIZER_FREEBSD -#include <sys/link_elf.h> -#endif - -#if SANITIZER_SOLARIS -#include <link.h> -#endif - -#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS -#include <ucontext.h> -extern "C" void* _DYNAMIC; -#elif SANITIZER_NETBSD -#include <link_elf.h> -#include <ucontext.h> +# include <dlfcn.h> +# include <fcntl.h> +# include <limits.h> +# include <pthread.h> +# include <stdio.h> +# include <sys/mman.h> +# include <sys/resource.h> +# include <sys/syscall.h> +# include <sys/time.h> +# include <sys/types.h> +# include <unistd.h> +# include <unwind.h> + +# include "asan_interceptors.h" +# include "asan_internal.h" +# include "asan_premap_shadow.h" +# include "asan_thread.h" +# include "sanitizer_common/sanitizer_flags.h" +# include "sanitizer_common/sanitizer_freebsd.h" +# include "sanitizer_common/sanitizer_hash.h" +# include "sanitizer_common/sanitizer_libc.h" +# include "sanitizer_common/sanitizer_procmaps.h" + +# if SANITIZER_FREEBSD +# include <sys/link_elf.h> +# endif + +# if SANITIZER_SOLARIS +# include <link.h> +# endif + +# if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS +# include <ucontext.h> +extern "C" void *_DYNAMIC; +# elif SANITIZER_NETBSD +# include <link_elf.h> +# include <ucontext.h> extern Elf_Dyn _DYNAMIC; -#else -#include <sys/ucontext.h> -#include <link.h> +# else +# include <link.h> +# include <sys/ucontext.h> extern ElfW(Dyn) _DYNAMIC[]; -#endif +# endif // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in // 32-bit mode. -#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ - __FreeBSD_version <= 902001 // v9.2 -#define ucontext_t xucontext_t -#endif +# if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \ + __FreeBSD_version <= 902001 // v9.2 +# define ucontext_t xucontext_t +# endif typedef enum { ASAN_RT_VERSION_UNDEFINED = 0, @@ -74,21 +75,21 @@ typedef enum { // FIXME: perhaps also store abi version here? extern "C" { SANITIZER_INTERFACE_ATTRIBUTE -asan_rt_version_t __asan_rt_version; +asan_rt_version_t __asan_rt_version; } namespace __asan { void InitializePlatformInterceptors() {} void InitializePlatformExceptionHandlers() {} -bool IsSystemHeapAddress (uptr addr) { return false; } +bool IsSystemHeapAddress(uptr addr) { return false; } void *AsanDoesNotSupportStaticLinkage() { // This will fail to link with -static. return &_DYNAMIC; } -#if ASAN_PREMAP_SHADOW +# if ASAN_PREMAP_SHADOW uptr FindPremappedShadowStart(uptr shadow_size_bytes) { uptr granularity = GetMmapGranularity(); uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow); @@ -98,14 +99,14 @@ uptr FindPremappedShadowStart(uptr shadow_size_bytes) { UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size); return shadow_start; } -#endif +# endif uptr FindDynamicShadowStart() { uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd); -#if ASAN_PREMAP_SHADOW +# if ASAN_PREMAP_SHADOW if (!PremapShadowFailed()) return FindPremappedShadowStart(shadow_size_bytes); -#endif +# endif return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE, /*min_shadow_base_alignment*/ 0, kHighMemEnd); @@ -121,11 +122,11 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); } -#if SANITIZER_ANDROID +# if SANITIZER_ANDROID // FIXME: should we do anything for Android? void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} -#else +# else static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, void *data) { VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, @@ -154,7 +155,7 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, static bool IsDynamicRTName(const char *libname) { return internal_strstr(libname, "libclang_rt.asan") || - internal_strstr(libname, "libasan.so"); + internal_strstr(libname, "libasan.so"); } static void ReportIncompatibleRT() { @@ -170,9 +171,10 @@ void AsanCheckDynamicRTPrereqs() { const char *first_dso_name = nullptr; dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) { - Report("ASan runtime does not come first in initial library list; " - "you should either link runtime to your application or " - "manually preload it with LD_PRELOAD.\n"); + Report( + "ASan runtime does not come first in initial library list; " + "you should either link runtime to your application or " + "manually preload it with LD_PRELOAD.\n"); Die(); } } @@ -190,13 +192,14 @@ void AsanCheckIncompatibleRT() { // as early as possible, otherwise ASan interceptors could bind to // the functions in dynamic ASan runtime instead of the functions in // system libraries, causing crashes later in ASan initialization. - MemoryMappingLayout proc_maps(/*cache_enabled*/true); + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); char filename[PATH_MAX]; MemoryMappedSegment segment(filename, sizeof(filename)); while (proc_maps.Next(&segment)) { if (IsDynamicRTName(segment.filename)) { - Report("Your application is linked against " - "incompatible ASan runtimes.\n"); + Report( + "Your application is linked against " + "incompatible ASan runtimes.\n"); Die(); } } @@ -206,31 +209,36 @@ void AsanCheckIncompatibleRT() { } } } -#endif // SANITIZER_ANDROID +# endif // SANITIZER_ANDROID -#if !SANITIZER_ANDROID -void ReadContextStack(void *context, uptr *stack, uptr *ssize) { - ucontext_t *ucp = (ucontext_t*)context; - *stack = (uptr)ucp->uc_stack.ss_sp; - *ssize = ucp->uc_stack.ss_size; +# if ASAN_INTERCEPT_SWAPCONTEXT +constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea; + +static int HashContextStack(const ucontext_t &ucp) { + MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic); + hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp)); + hash.add(ucp.uc_stack.ss_size); + return static_cast<int>(hash.get()); } -void ResetContextStack(void *context) { - ucontext_t *ucp = (ucontext_t *)context; - ucp->uc_stack.ss_sp = nullptr; - ucp->uc_stack.ss_size = 0; +void SignContextStack(void *context) { + ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context); + ucp->uc_stack.ss_flags = HashContextStack(*ucp); } -# else + void ReadContextStack(void *context, uptr *stack, uptr *ssize) { - UNIMPLEMENTED(); + const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context); + if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) { + *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp); + *ssize = ucp->uc_stack.ss_size; + return; + } + *stack = 0; + *ssize = 0; } +# endif // ASAN_INTERCEPT_SWAPCONTEXT -void ResetContextStack(void *context) { UNIMPLEMENTED(); } -# endif - -void *AsanDlSymNext(const char *sym) { - return dlsym(RTLD_NEXT, sym); -} +void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); } bool HandleDlopenInit() { // Not supported on this platform. @@ -239,7 +247,7 @@ bool HandleDlopenInit() { return false; } -} // namespace __asan +} // namespace __asan #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || // SANITIZER_SOLARIS diff --git a/libsanitizer/asan/asan_mac.cpp b/libsanitizer/asan/asan_mac.cpp index a2d5c31..c9bd5fb 100644 --- a/libsanitizer/asan/asan_mac.cpp +++ b/libsanitizer/asan/asan_mac.cpp @@ -95,12 +95,6 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) { ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); } -void ReadContextStack(void *context, uptr *stack, uptr *ssize) { - UNIMPLEMENTED(); -} - -void ResetContextStack(void *context) { UNIMPLEMENTED(); } - // Support for the following functions from libdispatch on Mac OS: // dispatch_async_f() // dispatch_async() diff --git a/libsanitizer/asan/asan_malloc_win.cpp b/libsanitizer/asan/asan_malloc_win.cpp index 4b76d4e..ff78d76 100644 --- a/libsanitizer/asan/asan_malloc_win.cpp +++ b/libsanitizer/asan/asan_malloc_win.cpp @@ -508,10 +508,10 @@ void ReplaceSystemMalloc() { TryToOverrideFunction("_expand_base", (uptr)_expand); if (flags()->windows_hook_rtl_allocators) { - INTERCEPT_FUNCTION(HeapSize); - INTERCEPT_FUNCTION(HeapFree); - INTERCEPT_FUNCTION(HeapReAlloc); - INTERCEPT_FUNCTION(HeapAlloc); + ASAN_INTERCEPT_FUNC(HeapSize); + ASAN_INTERCEPT_FUNC(HeapFree); + ASAN_INTERCEPT_FUNC(HeapReAlloc); + ASAN_INTERCEPT_FUNC(HeapAlloc); // Undocumented functions must be intercepted by name, not by symbol. __interception::OverrideFunction("RtlSizeHeap", (uptr)WRAP(RtlSizeHeap), diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h index 47ccf84..c5f95c0 100644 --- a/libsanitizer/asan/asan_mapping.h +++ b/libsanitizer/asan/asan_mapping.h @@ -190,7 +190,7 @@ # elif defined(__aarch64__) # define ASAN_SHADOW_OFFSET_CONST 0x0000001000000000 # elif defined(__powerpc64__) -# define ASAN_SHADOW_OFFSET_CONST 0x0000020000000000 +# define ASAN_SHADOW_OFFSET_CONST 0x0000100000000000 # elif defined(__s390x__) # define ASAN_SHADOW_OFFSET_CONST 0x0010000000000000 # elif SANITIZER_FREEBSD diff --git a/libsanitizer/asan/asan_memory_profile.cpp b/libsanitizer/asan/asan_memory_profile.cpp index 4fcd560..3396fc2 100644 --- a/libsanitizer/asan/asan_memory_profile.cpp +++ b/libsanitizer/asan/asan_memory_profile.cpp @@ -11,12 +11,11 @@ // This file implements __sanitizer_print_memory_profile. //===----------------------------------------------------------------------===// +#include "asan/asan_allocator.h" +#include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_stacktrace.h" -#include "sanitizer_common/sanitizer_stoptheworld.h" -#include "lsan/lsan_common.h" -#include "asan/asan_allocator.h" #if CAN_SANITIZE_LEAKS @@ -100,17 +99,16 @@ static void ChunkCallback(uptr chunk, void *arg) { FindHeapChunkByAllocBeg(chunk)); } -static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list, - void *argument) { +static void MemoryProfileCB(uptr top_percent, uptr max_number_of_contexts) { HeapProfile hp; + __lsan::LockAllocator(); __lsan::ForEachChunk(ChunkCallback, &hp); - uptr *Arg = reinterpret_cast<uptr*>(argument); - hp.Print(Arg[0], Arg[1]); + __lsan::UnlockAllocator(); + hp.Print(top_percent, max_number_of_contexts); if (Verbosity()) __asan_print_accumulated_stats(); } - } // namespace __asan #endif // CAN_SANITIZE_LEAKS @@ -120,10 +118,7 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts) { #if CAN_SANITIZE_LEAKS - uptr Arg[2]; - Arg[0] = top_percent; - Arg[1] = max_number_of_contexts; - __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg); + __asan::MemoryProfileCB(top_percent, max_number_of_contexts); #endif // CAN_SANITIZE_LEAKS } } // extern "C" diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp index e470256..5164b7d 100644 --- a/libsanitizer/asan/asan_poisoning.cpp +++ b/libsanitizer/asan/asan_poisoning.cpp @@ -370,79 +370,77 @@ void __asan_unpoison_stack_memory(uptr addr, uptr size) { PoisonAlignedStackMemory(addr, size, false); } +static void FixUnalignedStorage(uptr storage_beg, uptr storage_end, + uptr &old_beg, uptr &old_end, uptr &new_beg, + uptr &new_end) { + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + if (UNLIKELY(!AddrIsAlignedByGranularity(storage_end))) { + uptr end_down = RoundDownTo(storage_end, granularity); + // Ignore the last unaligned granule if the storage is followed by + // unpoisoned byte, because we can't poison the prefix anyway. Don't call + // AddressIsPoisoned at all if container changes does not affect the last + // granule at all. + if ((((old_end != new_end) && Max(old_end, new_end) > end_down) || + ((old_beg != new_beg) && Max(old_beg, new_beg) > end_down)) && + !AddressIsPoisoned(storage_end)) { + old_beg = Min(end_down, old_beg); + old_end = Min(end_down, old_end); + new_beg = Min(end_down, new_beg); + new_end = Min(end_down, new_end); + } + } + + // Handle misaligned begin and cut it off. + if (UNLIKELY(!AddrIsAlignedByGranularity(storage_beg))) { + uptr beg_up = RoundUpTo(storage_beg, granularity); + // The first unaligned granule needs special handling only if we had bytes + // there before and will have none after. + if ((new_beg == new_end || new_beg >= beg_up) && old_beg != old_end && + old_beg < beg_up) { + // Keep granule prefix outside of the storage unpoisoned. + uptr beg_down = RoundDownTo(storage_beg, granularity); + *(u8 *)MemToShadow(beg_down) = storage_beg - beg_down; + old_beg = Max(beg_up, old_beg); + old_end = Max(beg_up, old_end); + new_beg = Max(beg_up, new_beg); + new_end = Max(beg_up, new_end); + } + } +} + void __sanitizer_annotate_contiguous_container(const void *beg_p, const void *end_p, const void *old_mid_p, const void *new_mid_p) { - if (!flags()->detect_container_overflow) return; + if (!flags()->detect_container_overflow) + return; VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, new_mid_p); - uptr beg = reinterpret_cast<uptr>(beg_p); - uptr end = reinterpret_cast<uptr>(end_p); - uptr old_mid = reinterpret_cast<uptr>(old_mid_p); - uptr new_mid = reinterpret_cast<uptr>(new_mid_p); + uptr storage_beg = reinterpret_cast<uptr>(beg_p); + uptr storage_end = reinterpret_cast<uptr>(end_p); + uptr old_end = reinterpret_cast<uptr>(old_mid_p); + uptr new_end = reinterpret_cast<uptr>(new_mid_p); + uptr old_beg = storage_beg; + uptr new_beg = storage_beg; uptr granularity = ASAN_SHADOW_GRANULARITY; - if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end)) { + if (!(storage_beg <= old_end && storage_beg <= new_end && + old_end <= storage_end && new_end <= storage_end)) { GET_STACK_TRACE_FATAL_HERE; - ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid, - &stack); + ReportBadParamsToAnnotateContiguousContainer(storage_beg, storage_end, + old_end, new_end, &stack); } - CHECK_LE(end - beg, - FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check. + CHECK_LE(storage_end - storage_beg, + FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check. - if (old_mid == new_mid) + if (old_end == new_end) return; // Nothing to do here. - // Handle misaligned end and cut it off. - if (UNLIKELY(!AddrIsAlignedByGranularity(end))) { - uptr end_down = RoundDownTo(end, granularity); - // Either new or old mid must be in the granule to affect it. - if (new_mid > end_down) { - if (AddressIsPoisoned(end)) { - *(u8 *)MemToShadow(end_down) = static_cast<u8>(new_mid - end_down); - } else { - // Something after the container - don't touch. - } - } else if (old_mid > end_down) { - if (AddressIsPoisoned(end)) { - *(u8 *)MemToShadow(end_down) = kAsanContiguousContainerOOBMagic; - } else { - // Something after the container - don't touch. - } - } + FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg, + new_end); - if (beg >= end_down) - return; // Same granule. - - old_mid = Min(end_down, old_mid); - new_mid = Min(end_down, new_mid); - } - - // Handle misaligned begin and cut it off. - if (UNLIKELY(!AddrIsAlignedByGranularity(beg))) { - uptr beg_up = RoundUpTo(beg, granularity); - uptr beg_down = RoundDownTo(beg, granularity); - // As soon as we add first byte into container we will not be able to - // determine the state of the byte before the container. So we assume it's - // always unpoison. - - // Either new or old mid must be in the granule to affect it. - if (new_mid < beg_up) { - *(u8 *)MemToShadow(beg_down) = static_cast<u8>(new_mid - beg_down); - } else if (old_mid < beg_up) { - *(u8 *)MemToShadow(beg_down) = 0; - } - - old_mid = Max(beg_up, old_mid); - new_mid = Max(beg_up, new_mid); - } - - if (old_mid == new_mid) - return; - - uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); - uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); - uptr d1 = RoundDownTo(old_mid, granularity); + uptr a = RoundDownTo(Min(old_end, new_end), granularity); + uptr c = RoundUpTo(Max(old_end, new_end), granularity); + uptr d1 = RoundDownTo(old_end, granularity); // uptr d2 = RoundUpTo(old_mid, granularity); // Currently we should be in this state: // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good. @@ -453,23 +451,148 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p, // if (d1 != d2) // CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1); if (a + granularity <= d1) - CHECK_EQ(*(u8*)MemToShadow(a), 0); + CHECK_EQ(*(u8 *)MemToShadow(a), 0); // if (d2 + granularity <= c && c <= end) // CHECK_EQ(*(u8 *)MemToShadow(c - granularity), // kAsanContiguousContainerOOBMagic); - uptr b1 = RoundDownTo(new_mid, granularity); - uptr b2 = RoundUpTo(new_mid, granularity); + uptr b1 = RoundDownTo(new_end, granularity); + uptr b2 = RoundUpTo(new_end, granularity); // New state: // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good. - PoisonShadow(a, b1 - a, 0); - PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic); + if (b1 > a) + PoisonShadow(a, b1 - a, 0); + else if (c > b2) + PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic); if (b1 != b2) { CHECK_EQ(b2 - b1, granularity); - *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1); + *(u8 *)MemToShadow(b1) = static_cast<u8>(new_end - b1); } } +// Annotates a double ended contiguous memory area like std::deque's chunk. +// It allows detecting buggy accesses to allocated but not used begining +// or end items of such a container. +void __sanitizer_annotate_double_ended_contiguous_container( + const void *storage_beg_p, const void *storage_end_p, + const void *old_container_beg_p, const void *old_container_end_p, + const void *new_container_beg_p, const void *new_container_end_p) { + if (!flags()->detect_container_overflow) + return; + + VPrintf(2, "contiguous_container: %p %p %p %p %p %p\n", storage_beg_p, + storage_end_p, old_container_beg_p, old_container_end_p, + new_container_beg_p, new_container_end_p); + + uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p); + uptr storage_end = reinterpret_cast<uptr>(storage_end_p); + uptr old_beg = reinterpret_cast<uptr>(old_container_beg_p); + uptr old_end = reinterpret_cast<uptr>(old_container_end_p); + uptr new_beg = reinterpret_cast<uptr>(new_container_beg_p); + uptr new_end = reinterpret_cast<uptr>(new_container_end_p); + + constexpr uptr granularity = ASAN_SHADOW_GRANULARITY; + + if (!(old_beg <= old_end && new_beg <= new_end) || + !(storage_beg <= new_beg && new_end <= storage_end) || + !(storage_beg <= old_beg && old_end <= storage_end)) { + GET_STACK_TRACE_FATAL_HERE; + ReportBadParamsToAnnotateDoubleEndedContiguousContainer( + storage_beg, storage_end, old_beg, old_end, new_beg, new_end, &stack); + } + CHECK_LE(storage_end - storage_beg, + FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check. + + if ((old_beg == old_end && new_beg == new_end) || + (old_beg == new_beg && old_end == new_end)) + return; // Nothing to do here. + + FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg, + new_end); + + // Handle non-intersecting new/old containers separately have simpler + // intersecting case. + if (old_beg == old_end || new_beg == new_end || new_end <= old_beg || + old_end <= new_beg) { + if (old_beg != old_end) { + // Poisoning the old container. + uptr a = RoundDownTo(old_beg, granularity); + uptr b = RoundUpTo(old_end, granularity); + PoisonShadow(a, b - a, kAsanContiguousContainerOOBMagic); + } + + if (new_beg != new_end) { + // Unpoisoning the new container. + uptr a = RoundDownTo(new_beg, granularity); + uptr b = RoundDownTo(new_end, granularity); + PoisonShadow(a, b - a, 0); + if (!AddrIsAlignedByGranularity(new_end)) + *(u8 *)MemToShadow(b) = static_cast<u8>(new_end - b); + } + + return; + } + + // Intersection of old and new containers is not empty. + CHECK_LT(new_beg, old_end); + CHECK_GT(new_end, old_beg); + + if (new_beg < old_beg) { + // Round down because we can't poison prefixes. + uptr a = RoundDownTo(new_beg, granularity); + // Round down and ignore the [c, old_beg) as its state defined by unchanged + // [old_beg, old_end). + uptr c = RoundDownTo(old_beg, granularity); + PoisonShadow(a, c - a, 0); + } else if (new_beg > old_beg) { + // Round down and poison [a, old_beg) because it was unpoisoned only as a + // prefix. + uptr a = RoundDownTo(old_beg, granularity); + // Round down and ignore the [c, new_beg) as its state defined by unchanged + // [new_beg, old_end). + uptr c = RoundDownTo(new_beg, granularity); + + PoisonShadow(a, c - a, kAsanContiguousContainerOOBMagic); + } + + if (new_end > old_end) { + // Round down to poison the prefix. + uptr a = RoundDownTo(old_end, granularity); + // Round down and handle remainder below. + uptr c = RoundDownTo(new_end, granularity); + PoisonShadow(a, c - a, 0); + if (!AddrIsAlignedByGranularity(new_end)) + *(u8 *)MemToShadow(c) = static_cast<u8>(new_end - c); + } else if (new_end < old_end) { + // Round up and handle remained below. + uptr a2 = RoundUpTo(new_end, granularity); + // Round up to poison entire granule as we had nothing in [old_end, c2). + uptr c2 = RoundUpTo(old_end, granularity); + PoisonShadow(a2, c2 - a2, kAsanContiguousContainerOOBMagic); + + if (!AddrIsAlignedByGranularity(new_end)) { + uptr a = RoundDownTo(new_end, granularity); + *(u8 *)MemToShadow(a) = static_cast<u8>(new_end - a); + } + } +} + +static const void *FindBadAddress(uptr begin, uptr end, bool poisoned) { + CHECK_LE(begin, end); + constexpr uptr kMaxRangeToCheck = 32; + if (end - begin > kMaxRangeToCheck * 2) { + if (auto *bad = FindBadAddress(begin, begin + kMaxRangeToCheck, poisoned)) + return bad; + if (auto *bad = FindBadAddress(end - kMaxRangeToCheck, end, poisoned)) + return bad; + } + + for (uptr i = begin; i < end; ++i) + if (AddressIsPoisoned(i) != poisoned) + return reinterpret_cast<const void *>(i); + return nullptr; +} + const void *__sanitizer_contiguous_container_find_bad_address( const void *beg_p, const void *mid_p, const void *end_p) { if (!flags()->detect_container_overflow) @@ -477,35 +600,22 @@ const void *__sanitizer_contiguous_container_find_bad_address( uptr granularity = ASAN_SHADOW_GRANULARITY; uptr beg = reinterpret_cast<uptr>(beg_p); uptr end = reinterpret_cast<uptr>(end_p); + uptr mid = reinterpret_cast<uptr>(mid_p); + CHECK_LE(beg, mid); + CHECK_LE(mid, end); + // If the byte after the storage is unpoisoned, everything in the granule + // before must stay unpoisoned. uptr annotations_end = (!AddrIsAlignedByGranularity(end) && !AddressIsPoisoned(end)) ? RoundDownTo(end, granularity) : end; - uptr mid = reinterpret_cast<uptr>(mid_p); - CHECK_LE(beg, mid); - CHECK_LE(mid, end); - // Check some bytes starting from beg, some bytes around mid, and some bytes - // ending with end. - uptr kMaxRangeToCheck = 32; - uptr r1_beg = beg; - uptr r1_end = Min(beg + kMaxRangeToCheck, mid); - uptr r2_beg = Max(beg, mid - kMaxRangeToCheck); - uptr r2_end = Min(annotations_end, mid + kMaxRangeToCheck); - uptr r3_beg = Max(annotations_end - kMaxRangeToCheck, mid); - uptr r3_end = annotations_end; - for (uptr i = r1_beg; i < r1_end; i++) - if (AddressIsPoisoned(i)) - return reinterpret_cast<const void *>(i); - for (uptr i = r2_beg; i < mid; i++) - if (AddressIsPoisoned(i)) - return reinterpret_cast<const void *>(i); - for (uptr i = mid; i < r2_end; i++) - if (!AddressIsPoisoned(i)) - return reinterpret_cast<const void *>(i); - for (uptr i = r3_beg; i < r3_end; i++) - if (!AddressIsPoisoned(i)) - return reinterpret_cast<const void *>(i); - return nullptr; + beg = Min(beg, annotations_end); + mid = Min(mid, annotations_end); + if (auto *bad = FindBadAddress(beg, mid, false)) + return bad; + if (auto *bad = FindBadAddress(mid, annotations_end, true)) + return bad; + return FindBadAddress(annotations_end, end, false); } int __sanitizer_verify_contiguous_container(const void *beg_p, @@ -515,6 +625,48 @@ int __sanitizer_verify_contiguous_container(const void *beg_p, end_p) == nullptr; } +const void *__sanitizer_double_ended_contiguous_container_find_bad_address( + const void *storage_beg_p, const void *container_beg_p, + const void *container_end_p, const void *storage_end_p) { + if (!flags()->detect_container_overflow) + return nullptr; + uptr granularity = ASAN_SHADOW_GRANULARITY; + uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p); + uptr storage_end = reinterpret_cast<uptr>(storage_end_p); + uptr beg = reinterpret_cast<uptr>(container_beg_p); + uptr end = reinterpret_cast<uptr>(container_end_p); + + // The prefix of the firs granule of the container is unpoisoned. + if (beg != end) + beg = Max(storage_beg, RoundDownTo(beg, granularity)); + + // If the byte after the storage is unpoisoned, the prefix of the last granule + // is unpoisoned. + uptr annotations_end = (!AddrIsAlignedByGranularity(storage_end) && + !AddressIsPoisoned(storage_end)) + ? RoundDownTo(storage_end, granularity) + : storage_end; + storage_beg = Min(storage_beg, annotations_end); + beg = Min(beg, annotations_end); + end = Min(end, annotations_end); + + if (auto *bad = FindBadAddress(storage_beg, beg, true)) + return bad; + if (auto *bad = FindBadAddress(beg, end, false)) + return bad; + if (auto *bad = FindBadAddress(end, annotations_end, true)) + return bad; + return FindBadAddress(annotations_end, storage_end, false); +} + +int __sanitizer_verify_double_ended_contiguous_container( + const void *storage_beg_p, const void *container_beg_p, + const void *container_end_p, const void *storage_end_p) { + return __sanitizer_double_ended_contiguous_container_find_bad_address( + storage_beg_p, container_beg_p, container_end_p, storage_end_p) == + nullptr; +} + extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_poison_intra_object_redzone(uptr ptr, uptr size) { AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true); diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp index 2a55d6c..f2c0434 100644 --- a/libsanitizer/asan/asan_report.cpp +++ b/libsanitizer/asan/asan_report.cpp @@ -354,6 +354,18 @@ void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, in_report.ReportError(error); } +void ReportBadParamsToAnnotateDoubleEndedContiguousContainer( + uptr storage_beg, uptr storage_end, uptr old_container_beg, + uptr old_container_end, uptr new_container_beg, uptr new_container_end, + BufferedStackTrace *stack) { + ScopedInErrorReport in_report; + ErrorBadParamsToAnnotateDoubleEndedContiguousContainer error( + GetCurrentTidOrInvalid(), stack, storage_beg, storage_end, + old_container_beg, old_container_end, new_container_beg, + new_container_end); + in_report.ReportError(error); +} + void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2) { ScopedInErrorReport in_report; diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h index dcf6089..248e30d 100644 --- a/libsanitizer/asan/asan_report.h +++ b/libsanitizer/asan/asan_report.h @@ -83,6 +83,10 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size, void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid, uptr new_mid, BufferedStackTrace *stack); +void ReportBadParamsToAnnotateDoubleEndedContiguousContainer( + uptr storage_beg, uptr storage_end, uptr old_container_beg, + uptr old_container_end, uptr new_container_beg, uptr new_container_end, + BufferedStackTrace *stack); void ReportODRViolation(const __asan_global *g1, u32 stack_id1, const __asan_global *g2, u32 stack_id2); diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp index c15963e1..3f6e58e 100644 --- a/libsanitizer/asan/asan_thread.cpp +++ b/libsanitizer/asan/asan_thread.cpp @@ -10,17 +10,18 @@ // // Thread-related code. //===----------------------------------------------------------------------===// +#include "asan_thread.h" + #include "asan_allocator.h" #include "asan_interceptors.h" +#include "asan_mapping.h" #include "asan_poisoning.h" #include "asan_stack.h" -#include "asan_thread.h" -#include "asan_mapping.h" +#include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" -#include "lsan/lsan_common.h" namespace __asan { @@ -306,6 +307,7 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) { GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size, &tls_begin_, &tls_size); stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY); + stack_bottom_ = RoundDownTo(stack_bottom_, ASAN_SHADOW_GRANULARITY); tls_end_ = tls_begin_ + tls_size; dtls_ = DTLS_Get(); @@ -478,6 +480,17 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) { // --- Implementation of LSan-specific functions --- {{{1 namespace __lsan { +void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); } + +void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); } + +static ThreadRegistry *GetAsanThreadRegistryLocked() { + __asan::asanThreadRegistry().CheckLocked(); + return &__asan::asanThreadRegistry(); +} + +void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } + bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls) { @@ -496,33 +509,76 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {} -void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, - void *arg) { +void GetThreadExtraStackRangesLocked(tid_t os_id, + InternalMmapVector<Range> *ranges) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (!t) return; __asan::FakeStack *fake_stack = t->get_fake_stack(); if (!fake_stack) return; - fake_stack->ForEachFakeFrame(callback, arg); + + fake_stack->ForEachFakeFrame( + [](uptr begin, uptr end, void *arg) { + reinterpret_cast<InternalMmapVector<Range> *>(arg)->push_back( + {begin, end}); + }, + ranges); } -void LockThreadRegistry() { - __asan::asanThreadRegistry().Lock(); +void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) { + GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *arg) { + GetThreadExtraStackRangesLocked( + tctx->os_id, reinterpret_cast<InternalMmapVector<Range> *>(arg)); + }, + ranges); } -void UnlockThreadRegistry() { - __asan::asanThreadRegistry().Unlock(); +void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) { + GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *ptrs) { + // Look for the arg pointer of threads that have been created or are + // running. This is necessary to prevent false positive leaks due to the + // AsanThread holding the only live reference to a heap object. This + // can happen because the `pthread_create()` interceptor doesn't wait + // for the child thread to start before returning and thus loosing the + // the only live reference to the heap object on the stack. + + __asan::AsanThreadContext *atctx = + static_cast<__asan::AsanThreadContext *>(tctx); + + // Note ThreadStatusRunning is required because there is a small window + // where the thread status switches to `ThreadStatusRunning` but the + // `arg` pointer still isn't on the stack yet. + if (atctx->status != ThreadStatusCreated && + atctx->status != ThreadStatusRunning) + return; + + uptr thread_arg = reinterpret_cast<uptr>(atctx->thread->get_arg()); + if (!thread_arg) + return; + + auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs); + ptrsVec->push_back(thread_arg); + }, + ptrs); } -ThreadRegistry *GetThreadRegistryLocked() { - __asan::asanThreadRegistry().CheckLocked(); - return &__asan::asanThreadRegistry(); +void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) { + GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *threads) { + if (tctx->status == ThreadStatusRunning) + reinterpret_cast<InternalMmapVector<tid_t> *>(threads)->push_back( + tctx->os_id); + }, + threads); } -void EnsureMainThreadIDIsCorrect() { - __asan::EnsureMainThreadIDIsCorrect(); +void FinishThreadLocked(u32 tid) { + GetAsanThreadRegistryLocked()->FinishThread(tid); } + } // namespace __lsan // ---------------------- Interface ---------------- {{{1 diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp index f11df06..7dbd7ab 100644 --- a/libsanitizer/asan/asan_win.cpp +++ b/libsanitizer/asan/asan_win.cpp @@ -263,12 +263,6 @@ void AsanCheckDynamicRTPrereqs() {} void AsanCheckIncompatibleRT() {} -void ReadContextStack(void *context, uptr *stack, uptr *ssize) { - UNIMPLEMENTED(); -} - -void ResetContextStack(void *context) { UNIMPLEMENTED(); } - void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } bool PlatformUnpoisonStacks() { return false; } |