diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:48 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:06:48 +0000 |
commit | 93c1b73a09a52d4a265f683bf1954b08bb430049 (patch) | |
tree | 5543464d74945196cc890e9d9099e5d0660df7eb /lib/asan | |
parent | 0d8e7490d6e8a13a8f0977d9b7771803b9f64ea0 (diff) | |
download | src-93c1b73a09a52d4a265f683bf1954b08bb430049.tar.gz src-93c1b73a09a52d4a265f683bf1954b08bb430049.zip |
Vendor import of compiler-rt trunk r338150:vendor/compiler-rt/compiler-rt-trunk-r338150
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=336817
svn path=/vendor/compiler-rt/compiler-rt-trunk-r338150/; revision=336818; tag=vendor/compiler-rt/compiler-rt-trunk-r338150
Diffstat (limited to 'lib/asan')
40 files changed, 1356 insertions, 374 deletions
diff --git a/lib/asan/.clang-format b/lib/asan/.clang-format index f6cb8ad931f5..560308c91dee 100644 --- a/lib/asan/.clang-format +++ b/lib/asan/.clang-format @@ -1 +1,2 @@ BasedOnStyle: Google +AllowShortIfStatementsOnASingleLine: false diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index fbd72f69298f..2ae5c85ecefb 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -23,6 +23,7 @@ set(ASAN_SOURCES asan_posix.cc asan_premap_shadow.cc asan_report.cc + asan_rtems.cc asan_rtl.cc asan_shadow_setup.cc asan_stack.cc @@ -37,6 +38,34 @@ set(ASAN_CXX_SOURCES set(ASAN_PREINIT_SOURCES asan_preinit.cc) +SET(ASAN_HEADERS + asan_activation.h + asan_activation_flags.inc + asan_allocator.h + asan_descriptions.h + asan_errors.h + asan_fake_stack.h + asan_flags.h + asan_flags.inc + asan_init_version.h + asan_interceptors.h + asan_interceptors_memintrinsics.h + asan_interface.inc + asan_interface_internal.h + asan_internal.h + asan_lock.h + asan_malloc_local.h + asan_mapping.h + asan_mapping_myriad.h + asan_poisoning.h + asan_premap_shadow.h + asan_report.h + asan_scariness_score.h + asan_stack.h + asan_stats.h + asan_suppressions.h + asan_thread.h) + include_directories(..) set(ASAN_CFLAGS ${SANITIZER_COMMON_CFLAGS}) @@ -46,20 +75,6 @@ append_rtti_flag(OFF ASAN_CFLAGS) set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) -if(ANDROID) -# On Android, -z global does not do what it is documented to do. -# On Android, -z global moves the library ahead in the lookup order, -# placing it right after the LD_PRELOADs. This is used to compensate for the fact -# that Android linker does not look at the dependencies of the main executable -# that aren't dependencies of the current DSO when resolving symbols from said DSO. -# As a net result, this allows running ASan executables without LD_PRELOAD-ing the -# ASan runtime library. -# The above is applicable to L MR1 or newer. - if (COMPILER_RT_HAS_Z_GLOBAL) - list(APPEND ASAN_DYNAMIC_LINK_FLAGS -Wl,-z,global) - endif() -endif() - set(ASAN_DYNAMIC_DEFINITIONS ${ASAN_COMMON_DEFINITIONS} ASAN_DYNAMIC=1) append_list_if(WIN32 INTERCEPTION_DYNAMIC_CRT ASAN_DYNAMIC_DEFINITIONS) @@ -83,21 +98,28 @@ add_compiler_rt_object_libraries(RTAsan_dynamic OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${ASAN_SUPPORTED_ARCH} SOURCES ${ASAN_SOURCES} ${ASAN_CXX_SOURCES} + ADDITIONAL_HEADERS ${ASAN_HEADERS} CFLAGS ${ASAN_DYNAMIC_CFLAGS} DEFS ${ASAN_DYNAMIC_DEFINITIONS}) if(NOT APPLE) add_compiler_rt_object_libraries(RTAsan ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS} + SOURCES ${ASAN_SOURCES} + ADDITIONAL_HEADERS ${ASAN_HEADERS} + CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) add_compiler_rt_object_libraries(RTAsan_cxx ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_CXX_SOURCES} CFLAGS ${ASAN_CFLAGS} + SOURCES ${ASAN_CXX_SOURCES} + ADDITIONAL_HEADERS ${ASAN_HEADERS} + CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) add_compiler_rt_object_libraries(RTAsan_preinit ARCHS ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_PREINIT_SOURCES} CFLAGS ${ASAN_CFLAGS} + SOURCES ${ASAN_PREINIT_SOURCES} + ADDITIONAL_HEADERS ${ASAN_HEADERS} + CFLAGS ${ASAN_CFLAGS} DEFS ${ASAN_COMMON_DEFINITIONS}) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cc "") @@ -125,6 +147,8 @@ if(APPLE) RTInterception RTSanitizerCommon RTSanitizerCommonLibc + RTSanitizerCommonCoverage + RTSanitizerCommonSymbolizer RTLSanCommon RTUbsan CFLAGS ${ASAN_DYNAMIC_CFLAGS} @@ -138,6 +162,8 @@ else() RTInterception RTSanitizerCommon RTSanitizerCommonLibc + RTSanitizerCommonCoverage + RTSanitizerCommonSymbolizer RTLSanCommon RTUbsan) @@ -223,7 +249,7 @@ else() DEFS ${ASAN_DYNAMIC_DEFINITIONS} PARENT_TARGET asan) - if (UNIX AND NOT ${arch} STREQUAL "i386") + if (SANITIZER_USE_SYMBOLS AND NOT ${arch} STREQUAL "i386") add_sanitizer_rt_symbols(clang_rt.asan_cxx ARCHS ${arch}) add_dependencies(asan clang_rt.asan_cxx-${arch}-symbols) diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index a437ae1cd3b1..c0fad4fa042b 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -134,8 +134,9 @@ struct AsanChunk: ChunkBase { }; struct QuarantineCallback { - explicit QuarantineCallback(AllocatorCache *cache) - : cache_(cache) { + QuarantineCallback(AllocatorCache *cache, BufferedStackTrace *stack) + : cache_(cache), + stack_(stack) { } void Recycle(AsanChunk *m) { @@ -168,7 +169,7 @@ struct QuarantineCallback { void *res = get_allocator().Allocate(cache_, size, 1); // TODO(alekseys): Consider making quarantine OOM-friendly. if (UNLIKELY(!res)) - return DieOnFailure::OnOOM(); + ReportOutOfMemory(size, stack_); return res; } @@ -176,7 +177,9 @@ struct QuarantineCallback { get_allocator().Deallocate(cache_, p); } - AllocatorCache *cache_; + private: + AllocatorCache* const cache_; + BufferedStackTrace* const stack_; }; typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine; @@ -397,8 +400,11 @@ struct Allocator { AllocType alloc_type, bool can_fill) { if (UNLIKELY(!asan_inited)) AsanInitFromRtl(); - if (RssLimitExceeded()) - return AsanAllocator::FailureHandler::OnOOM(); + if (RssLimitExceeded()) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportRssLimitExceeded(stack); + } Flags &fl = *flags(); CHECK(stack); const uptr min_alignment = SHADOW_GRANULARITY; @@ -431,9 +437,13 @@ struct Allocator { } CHECK(IsAligned(needed_size, min_alignment)); if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { - Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", - (void*)size); - return AsanAllocator::FailureHandler::OnBadRequest(); + if (AllocatorMayReturnNull()) { + Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", + (void*)size); + return nullptr; + } + ReportAllocationSizeTooBig(size, needed_size, kMaxAllowedMallocSize, + stack); } AsanThread *t = GetCurrentThread(); @@ -446,8 +456,12 @@ struct Allocator { AllocatorCache *cache = &fallback_allocator_cache; allocated = allocator.Allocate(cache, needed_size, 8); } - if (!allocated) - return nullptr; + if (UNLIKELY(!allocated)) { + SetAllocatorOutOfMemory(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportOutOfMemory(size, stack); + } if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) { // Heap poisoning is enabled, but the allocator provides an unpoisoned @@ -583,13 +597,13 @@ struct Allocator { if (t) { AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); AllocatorCache *ac = GetAllocatorCache(ms); - quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), m, - m->UsedSize()); + quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac, stack), m, + m->UsedSize()); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *ac = &fallback_allocator_cache; - quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), m, - m->UsedSize()); + quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac, stack), + m, m->UsedSize()); } } @@ -660,8 +674,11 @@ struct Allocator { } void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { - if (CheckForCallocOverflow(size, nmemb)) - return AsanAllocator::FailureHandler::OnBadRequest(); + if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { + if (AllocatorMayReturnNull()) + return nullptr; + ReportCallocOverflow(nmemb, size, stack); + } void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); // If the memory comes from the secondary allocator no need to clear it // as it comes directly from mmap. @@ -677,9 +694,9 @@ struct Allocator { ReportFreeNotMalloced((uptr)ptr, stack); } - void CommitBack(AsanThreadLocalMallocStorage *ms) { + void CommitBack(AsanThreadLocalMallocStorage *ms, BufferedStackTrace *stack) { AllocatorCache *ac = GetAllocatorCache(ms); - quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac)); + quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac, stack)); allocator.SwallowCache(ac); } @@ -739,17 +756,19 @@ struct Allocator { return AsanChunkView(m1); } - void Purge() { + void Purge(BufferedStackTrace *stack) { AsanThread *t = GetCurrentThread(); if (t) { AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); quarantine.DrainAndRecycle(GetQuarantineCache(ms), - QuarantineCallback(GetAllocatorCache(ms))); + QuarantineCallback(GetAllocatorCache(ms), + stack)); } { SpinMutexLock l(&fallback_mutex); quarantine.DrainAndRecycle(&fallback_quarantine_cache, - QuarantineCallback(&fallback_allocator_cache)); + QuarantineCallback(&fallback_allocator_cache, + stack)); } allocator.ForceReleaseToOS(); @@ -836,7 +855,8 @@ AsanChunkView FindHeapChunkByAllocBeg(uptr addr) { } void AsanThreadLocalMallocStorage::CommitBack() { - instance.CommitBack(this); + GET_STACK_TRACE_MALLOC; + instance.CommitBack(this, &stack); } void PrintInternalAllocatorStats() { @@ -883,7 +903,9 @@ void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { uptr PageSize = GetPageSizeCached(); if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { errno = errno_ENOMEM; - return AsanAllocator::FailureHandler::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportPvallocOverflow(size, stack); } // pvalloc(0) should allocate one page. size = size ? RoundUpTo(size, PageSize) : PageSize; @@ -895,20 +917,35 @@ void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, AllocType alloc_type) { if (UNLIKELY(!IsPowerOfTwo(alignment))) { errno = errno_EINVAL; - return AsanAllocator::FailureHandler::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAllocationAlignment(alignment, stack); } return SetErrnoOnNull( instance.Allocate(size, alignment, stack, alloc_type, true)); } +void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { + if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { + errno = errno_EINVAL; + if (AllocatorMayReturnNull()) + return nullptr; + ReportInvalidAlignedAllocAlignment(size, alignment, stack); + } + return SetErrnoOnNull( + instance.Allocate(size, alignment, stack, FROM_MALLOC, true)); +} + int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack) { if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { - AsanAllocator::FailureHandler::OnBadRequest(); - return errno_EINVAL; + if (AllocatorMayReturnNull()) + return errno_EINVAL; + ReportInvalidPosixMemalignAlignment(alignment, stack); } void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true); if (UNLIKELY(!ptr)) + // OOM error is already taken care of by Allocate. return errno_ENOMEM; CHECK(IsAligned((uptr)ptr, alignment)); *memptr = ptr; @@ -1054,7 +1091,8 @@ uptr __sanitizer_get_allocated_size(const void *p) { } void __sanitizer_purge_allocator() { - instance.Purge(); + GET_STACK_TRACE_MALLOC; + instance.Purge(&stack); } #if !SANITIZER_SUPPORTS_WEAK_HOOKS diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index 26483db4c60e..93d6f29c5bf5 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -125,11 +125,12 @@ const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x40000000000ULL; // 4T. typedef DefaultSizeClassMap SizeClassMap; # elif defined(__powerpc64__) -const uptr kAllocatorSpace = 0xa0000000000ULL; +const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. typedef DefaultSizeClassMap SizeClassMap; # elif defined(__aarch64__) && SANITIZER_ANDROID -const uptr kAllocatorSpace = 0x3000000000ULL; +// Android needs to support 39, 42 and 48 bit VMA. +const uptr kAllocatorSpace = ~(uptr)0; const uptr kAllocatorSize = 0x2000000000ULL; // 128G. typedef VeryCompactSizeClassMap SizeClassMap; # elif defined(__aarch64__) @@ -207,6 +208,7 @@ void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack); void *asan_valloc(uptr size, BufferedStackTrace *stack); void *asan_pvalloc(uptr size, BufferedStackTrace *stack); +void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, BufferedStackTrace *stack); uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp); diff --git a/lib/asan/asan_debugging.cc b/lib/asan/asan_debugging.cc index 37c5922dc0fc..7c877ded30cf 100644 --- a/lib/asan/asan_debugging.cc +++ b/lib/asan/asan_debugging.cc @@ -27,7 +27,8 @@ using namespace __asan; static void FindInfoForStackVar(uptr addr, const char *frame_descr, uptr offset, char *name, uptr name_size, uptr ®ion_address, uptr ®ion_size) { - InternalMmapVector<StackVarDescr> vars(16); + InternalMmapVector<StackVarDescr> vars; + vars.reserve(16); if (!ParseFrameDescription(frame_descr, &vars)) { return; } diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc index 86c6af7d9f75..cdb562d975ff 100644 --- a/lib/asan/asan_descriptions.cc +++ b/lib/asan/asan_descriptions.cc @@ -20,23 +20,25 @@ namespace __asan { -// Return " (thread_name) " or an empty string if the name is empty. -const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], - uptr buff_len) { - const char *name = t->name; - if (name[0] == '\0') return ""; - buff[0] = 0; - internal_strncat(buff, " (", 3); - internal_strncat(buff, name, buff_len - 4); - internal_strncat(buff, ")", 2); - return buff; +AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) { + Init(t->tid, t->name); } -const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len) { - if (tid == kInvalidTid) return ""; - asanThreadRegistry().CheckLocked(); - AsanThreadContext *t = GetThreadContextByTidLocked(tid); - return ThreadNameWithParenthesis(t, buff, buff_len); +AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) { + if (tid == kInvalidTid) { + Init(tid, ""); + } else { + asanThreadRegistry().CheckLocked(); + AsanThreadContext *t = GetThreadContextByTidLocked(tid); + Init(tid, t->name); + } +} + +void AsanThreadIdAndName::Init(u32 tid, const char *tname) { + int len = internal_snprintf(name, sizeof(name), "T%d", tid); + CHECK(((unsigned int)len) < sizeof(name)); + if (tname[0] != '\0') + internal_snprintf(&name[len], sizeof(name) - len, " (%s)", tname); } void DescribeThread(AsanThreadContext *context) { @@ -47,18 +49,15 @@ void DescribeThread(AsanThreadContext *context) { return; } context->announced = true; - char tname[128]; InternalScopedString str(1024); - str.append("Thread T%d%s", context->tid, - ThreadNameWithParenthesis(context->tid, tname, sizeof(tname))); + str.append("Thread %s", AsanThreadIdAndName(context).c_str()); if (context->parent_tid == kInvalidTid) { str.append(" created by unknown thread\n"); Printf("%s", str.data()); return; } - str.append( - " created by T%d%s here:\n", context->parent_tid, - ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); + str.append(" created by %s here:\n", + AsanThreadIdAndName(context->parent_tid).c_str()); Printf("%s", str.data()); StackDepotGet(context->stack_id).Print(); // Recursively described parent thread if needed. @@ -358,10 +357,9 @@ bool GlobalAddressDescription::PointsInsideTheSameVariable( void StackAddressDescription::Print() const { Decorator d; - char tname[128]; Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread T%d%s", addr, tid, - ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + Printf("Address %p is located in stack of thread %s", addr, + AsanThreadIdAndName(tid).c_str()); if (!frame_descr) { Printf("%s\n", d.Default()); @@ -380,7 +378,8 @@ void StackAddressDescription::Print() const { StackTrace alloca_stack(&frame_pc, 1); alloca_stack.Print(); - InternalMmapVector<StackVarDescr> vars(16); + InternalMmapVector<StackVarDescr> vars; + vars.reserve(16); if (!ParseFrameDescription(frame_descr, &vars)) { Printf( "AddressSanitizer can't parse the stack frame " @@ -402,7 +401,7 @@ void StackAddressDescription::Print() const { } Printf( "HINT: this may be a false positive if your program uses " - "some custom stack unwind mechanism or swapcontext\n"); + "some custom stack unwind mechanism, swapcontext or vfork\n"); if (SANITIZER_WINDOWS) Printf(" (longjmp, SEH and C++ exceptions *are* supported)\n"); else @@ -418,26 +417,19 @@ void HeapAddressDescription::Print() const { AsanThreadContext *alloc_thread = GetThreadContextByTidLocked(alloc_tid); StackTrace alloc_stack = GetStackTraceFromId(alloc_stack_id); - char tname[128]; Decorator d; AsanThreadContext *free_thread = nullptr; if (free_tid != kInvalidTid) { free_thread = GetThreadContextByTidLocked(free_tid); - Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), - free_thread->tid, - ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), - d.Default()); + Printf("%sfreed by thread %s here:%s\n", d.Allocation(), + AsanThreadIdAndName(free_thread).c_str(), d.Default()); StackTrace free_stack = GetStackTraceFromId(free_stack_id); free_stack.Print(); - Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(), - alloc_thread->tid, - ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.Default()); + Printf("%spreviously allocated by thread %s here:%s\n", d.Allocation(), + AsanThreadIdAndName(alloc_thread).c_str(), d.Default()); } else { - Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), - alloc_thread->tid, - ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), - d.Default()); + Printf("%sallocated by thread %s here:%s\n", d.Allocation(), + AsanThreadIdAndName(alloc_thread).c_str(), d.Default()); } alloc_stack.Print(); DescribeThread(GetCurrentThread()); diff --git a/lib/asan/asan_descriptions.h b/lib/asan/asan_descriptions.h index 1a1b01cf20cd..5c2d7662a35a 100644 --- a/lib/asan/asan_descriptions.h +++ b/lib/asan/asan_descriptions.h @@ -26,9 +26,20 @@ void DescribeThread(AsanThreadContext *context); static inline void DescribeThread(AsanThread *t) { if (t) DescribeThread(t->context()); } -const char *ThreadNameWithParenthesis(AsanThreadContext *t, char buff[], - uptr buff_len); -const char *ThreadNameWithParenthesis(u32 tid, char buff[], uptr buff_len); + +class AsanThreadIdAndName { + public: + explicit AsanThreadIdAndName(AsanThreadContext *t); + explicit AsanThreadIdAndName(u32 tid); + + // Contains "T%tid (%name)" or "T%tid" if the name is empty. + const char *c_str() const { return &name[0]; } + + private: + void Init(u32 tid, const char *tname); + + char name[128]; +}; class Decorator : public __sanitizer::SanitizerCommonDecorator { public: diff --git a/lib/asan/asan_errors.cc b/lib/asan/asan_errors.cc index 0f4a3abff9a7..33d0613f79f4 100644 --- a/lib/asan/asan_errors.cc +++ b/lib/asan/asan_errors.cc @@ -45,13 +45,11 @@ void ErrorDeadlySignal::Print() { void ErrorDoubleFree::Print() { Decorator d; - Printf("%s", d.Warning()); - char tname[128]; + Printf("%s", d.Error()); Report( - "ERROR: AddressSanitizer: attempting %s on %p in " - "thread T%d%s:\n", - scariness.GetDescription(), addr_description.addr, tid, - ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + "ERROR: AddressSanitizer: attempting %s on %p in thread %s:\n", + scariness.GetDescription(), addr_description.addr, + AsanThreadIdAndName(tid).c_str()); Printf("%s", d.Default()); scariness.Print(); GET_STACK_TRACE_FATAL(second_free_stack->trace[0], @@ -63,13 +61,11 @@ void ErrorDoubleFree::Print() { void ErrorNewDeleteTypeMismatch::Print() { Decorator d; - Printf("%s", d.Warning()); - char tname[128]; + Printf("%s", d.Error()); Report( - "ERROR: AddressSanitizer: %s on %p in thread " - "T%d%s:\n", - scariness.GetDescription(), addr_description.addr, tid, - ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + "ERROR: AddressSanitizer: %s on %p in thread %s:\n", + scariness.GetDescription(), addr_description.addr, + AsanThreadIdAndName(tid).c_str()); Printf("%s object passed to delete has wrong type:\n", d.Default()); if (delete_size != 0) { Printf( @@ -106,13 +102,11 @@ void ErrorNewDeleteTypeMismatch::Print() { void ErrorFreeNotMalloced::Print() { Decorator d; - Printf("%s", d.Warning()); - char tname[128]; + Printf("%s", d.Error()); Report( "ERROR: AddressSanitizer: attempting free on address " - "which was not malloc()-ed: %p in thread T%d%s\n", - addr_description.Address(), tid, - ThreadNameWithParenthesis(tid, tname, sizeof(tname))); + "which was not malloc()-ed: %p in thread %s\n", + addr_description.Address(), AsanThreadIdAndName(tid).c_str()); Printf("%s", d.Default()); CHECK_GT(free_stack->size, 0); scariness.Print(); @@ -129,7 +123,7 @@ void ErrorAllocTypeMismatch::Print() { "operator delete []"}; CHECK_NE(alloc_type, dealloc_type); Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n", scariness.GetDescription(), alloc_names[alloc_type], dealloc_names[dealloc_type], @@ -148,7 +142,7 @@ void ErrorAllocTypeMismatch::Print() { void ErrorMallocUsableSizeNotOwned::Print() { Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report( "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for " "pointer which is not owned: %p\n", @@ -161,7 +155,7 @@ void ErrorMallocUsableSizeNotOwned::Print() { void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report( "ERROR: AddressSanitizer: attempting to call " "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n", @@ -172,11 +166,123 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { ReportErrorSummary(scariness.GetDescription(), stack); } +void ErrorCallocOverflow::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: calloc parameters overflow: count * size " + "(%zd * %zd) cannot be represented in type size_t (thread %s)\n", + count, size, AsanThreadIdAndName(tid).c_str()); + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorPvallocOverflow::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: pvalloc parameters overflow: size 0x%zx " + "rounded up to system page size 0x%zx cannot be represented in type " + "size_t (thread %s)\n", + size, GetPageSizeCached(), AsanThreadIdAndName(tid).c_str()); + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorInvalidAllocationAlignment::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: invalid allocation alignment: %zd, " + "alignment must be a power of two (thread %s)\n", + alignment, AsanThreadIdAndName(tid).c_str()); + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorInvalidAlignedAllocAlignment::Print() { + Decorator d; + Printf("%s", d.Error()); +#if SANITIZER_POSIX + Report("ERROR: AddressSanitizer: invalid alignment requested in " + "aligned_alloc: %zd, alignment must be a power of two and the " + "requested size 0x%zx must be a multiple of alignment " + "(thread %s)\n", alignment, size, AsanThreadIdAndName(tid).c_str()); +#else + Report("ERROR: AddressSanitizer: invalid alignment requested in " + "aligned_alloc: %zd, the requested size 0x%zx must be a multiple of " + "alignment (thread %s)\n", alignment, size, + AsanThreadIdAndName(tid).c_str()); +#endif + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorInvalidPosixMemalignAlignment::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: invalid alignment requested in posix_memalign: " + "%zd, alignment must be a power of two and a multiple of sizeof(void*) " + "== %zd (thread %s)\n", + alignment, sizeof(void*), AsanThreadIdAndName(tid).c_str()); // NOLINT + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorAllocationSizeTooBig::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: requested allocation size 0x%zx (0x%zx after " + "adjustments for alignment, red zones etc.) exceeds maximum supported " + "size of 0x%zx (thread %s)\n", + user_size, total_size, max_size, AsanThreadIdAndName(tid).c_str()); + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorRssLimitExceeded::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: specified RSS limit exceeded, currently set to " + "soft_rss_limit_mb=%zd\n", common_flags()->soft_rss_limit_mb); + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + +void ErrorOutOfMemory::Print() { + Decorator d; + Printf("%s", d.Error()); + Report( + "ERROR: AddressSanitizer: allocator is out of memory trying to allocate " + "0x%zx bytes\n", requested_size); + Printf("%s", d.Default()); + stack->Print(); + PrintHintAllocatorCannotReturnNull(); + ReportErrorSummary(scariness.GetDescription(), stack); +} + void ErrorStringFunctionMemoryRangesOverlap::Print() { Decorator d; char bug_type[100]; internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function); - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report( "ERROR: AddressSanitizer: %s: memory ranges [%p,%p) and [%p, %p) " "overlap\n", @@ -193,7 +299,7 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() { void ErrorStringFunctionSizeOverflow::Print() { Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", scariness.GetDescription(), size); Printf("%s", d.Default()); @@ -221,7 +327,7 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() { void ErrorODRViolation::Print() { Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(), global1.beg); Printf("%s", d.Default()); @@ -250,7 +356,7 @@ void ErrorODRViolation::Print() { void ErrorInvalidPointerPair::Print() { Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(), addr1_description.Address(), addr2_description.Address()); Printf("%s", d.Default()); @@ -414,6 +520,7 @@ static void PrintLegend(InternalScopedString *str) { PrintShadowByte(str, " ASan internal: ", kAsanInternalHeapMagic); PrintShadowByte(str, " Left alloca redzone: ", kAsanAllocaLeftMagic); PrintShadowByte(str, " Right alloca redzone: ", kAsanAllocaRightMagic); + PrintShadowByte(str, " Shadow gap: ", kAsanShadowGap); } static void PrintShadowBytes(InternalScopedString *str, const char *before, @@ -453,17 +560,15 @@ static void PrintShadowMemoryForAddress(uptr addr) { void ErrorGeneric::Print() { Decorator d; - Printf("%s", d.Warning()); + Printf("%s", d.Error()); uptr addr = addr_description.Address(); Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n", bug_descr, (void *)addr, pc, bp, sp); Printf("%s", d.Default()); - char tname[128]; - Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(), + Printf("%s%s of size %zu at %p thread %s%s\n", d.Access(), access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size, - (void *)addr, tid, - ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.Default()); + (void *)addr, AsanThreadIdAndName(tid).c_str(), d.Default()); scariness.Print(); GET_STACK_TRACE_FATAL(pc, bp); diff --git a/lib/asan/asan_errors.h b/lib/asan/asan_errors.h index 518ba0c6945e..574197ebff86 100644 --- a/lib/asan/asan_errors.h +++ b/lib/asan/asan_errors.h @@ -20,20 +20,30 @@ namespace __asan { +// (*) VS2013 does not implement unrestricted unions, so we need a trivial +// default constructor explicitly defined for each particular error. + +// None of the error classes own the stack traces mentioned in them. + struct ErrorBase { - ErrorBase() = default; - explicit ErrorBase(u32 tid_) : tid(tid_) {} ScarinessScoreBase scariness; u32 tid; + + ErrorBase() = default; // (*) + explicit ErrorBase(u32 tid_) : tid(tid_) {} + ErrorBase(u32 tid_, int initial_score, const char *reason) : tid(tid_) { + scariness.Clear(); + scariness.Scare(initial_score, reason); + } }; struct ErrorDeadlySignal : ErrorBase { SignalContext signal; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorDeadlySignal() = default; + + ErrorDeadlySignal() = default; // (*) ErrorDeadlySignal(u32 tid, const SignalContext &sig) - : ErrorBase(tid), signal(sig) { + : ErrorBase(tid), + signal(sig) { scariness.Clear(); if (signal.IsStackOverflow()) { scariness.Scare(10, "stack-overflow"); @@ -55,125 +65,206 @@ struct ErrorDeadlySignal : ErrorBase { }; struct ErrorDoubleFree : ErrorBase { - // ErrorDoubleFree doesn't own the stack trace. const BufferedStackTrace *second_free_stack; HeapAddressDescription addr_description; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorDoubleFree() = default; + + ErrorDoubleFree() = default; // (*) ErrorDoubleFree(u32 tid, BufferedStackTrace *stack, uptr addr) - : ErrorBase(tid), second_free_stack(stack) { + : ErrorBase(tid, 42, "double-free"), + second_free_stack(stack) { CHECK_GT(second_free_stack->size, 0); GetHeapAddressInformation(addr, 1, &addr_description); - scariness.Clear(); - scariness.Scare(42, "double-free"); } void Print(); }; struct ErrorNewDeleteTypeMismatch : ErrorBase { - // ErrorNewDeleteTypeMismatch doesn't own the stack trace. const BufferedStackTrace *free_stack; HeapAddressDescription addr_description; uptr delete_size; uptr delete_alignment; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorNewDeleteTypeMismatch() = default; + + ErrorNewDeleteTypeMismatch() = default; // (*) ErrorNewDeleteTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, uptr delete_size_, uptr delete_alignment_) - : ErrorBase(tid), free_stack(stack), delete_size(delete_size_), + : ErrorBase(tid, 10, "new-delete-type-mismatch"), + free_stack(stack), + delete_size(delete_size_), delete_alignment(delete_alignment_) { GetHeapAddressInformation(addr, 1, &addr_description); - scariness.Clear(); - scariness.Scare(10, "new-delete-type-mismatch"); } void Print(); }; struct ErrorFreeNotMalloced : ErrorBase { - // ErrorFreeNotMalloced doesn't own the stack trace. const BufferedStackTrace *free_stack; AddressDescription addr_description; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorFreeNotMalloced() = default; + + ErrorFreeNotMalloced() = default; // (*) ErrorFreeNotMalloced(u32 tid, BufferedStackTrace *stack, uptr addr) - : ErrorBase(tid), + : ErrorBase(tid, 40, "bad-free"), free_stack(stack), - addr_description(addr, /*shouldLockThreadRegistry=*/false) { - scariness.Clear(); - scariness.Scare(40, "bad-free"); - } + addr_description(addr, /*shouldLockThreadRegistry=*/false) {} void Print(); }; struct ErrorAllocTypeMismatch : ErrorBase { - // ErrorAllocTypeMismatch doesn't own the stack trace. const BufferedStackTrace *dealloc_stack; HeapAddressDescription addr_description; AllocType alloc_type, dealloc_type; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorAllocTypeMismatch() = default; + + ErrorAllocTypeMismatch() = default; // (*) ErrorAllocTypeMismatch(u32 tid, BufferedStackTrace *stack, uptr addr, AllocType alloc_type_, AllocType dealloc_type_) - : ErrorBase(tid), + : ErrorBase(tid, 10, "alloc-dealloc-mismatch"), dealloc_stack(stack), alloc_type(alloc_type_), dealloc_type(dealloc_type_) { GetHeapAddressInformation(addr, 1, &addr_description); - scariness.Clear(); - scariness.Scare(10, "alloc-dealloc-mismatch"); }; void Print(); }; struct ErrorMallocUsableSizeNotOwned : ErrorBase { - // ErrorMallocUsableSizeNotOwned doesn't own the stack trace. const BufferedStackTrace *stack; AddressDescription addr_description; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorMallocUsableSizeNotOwned() = default; + + ErrorMallocUsableSizeNotOwned() = default; // (*) ErrorMallocUsableSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) - : ErrorBase(tid), + : ErrorBase(tid, 10, "bad-malloc_usable_size"), stack(stack_), - addr_description(addr, /*shouldLockThreadRegistry=*/false) { - scariness.Clear(); - scariness.Scare(10, "bad-malloc_usable_size"); - } + addr_description(addr, /*shouldLockThreadRegistry=*/false) {} void Print(); }; struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase { - // ErrorSanitizerGetAllocatedSizeNotOwned doesn't own the stack trace. const BufferedStackTrace *stack; AddressDescription addr_description; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorSanitizerGetAllocatedSizeNotOwned() = default; + + ErrorSanitizerGetAllocatedSizeNotOwned() = default; // (*) ErrorSanitizerGetAllocatedSizeNotOwned(u32 tid, BufferedStackTrace *stack_, uptr addr) - : ErrorBase(tid), + : ErrorBase(tid, 10, "bad-__sanitizer_get_allocated_size"), stack(stack_), - addr_description(addr, /*shouldLockThreadRegistry=*/false) { - scariness.Clear(); - scariness.Scare(10, "bad-__sanitizer_get_allocated_size"); - } + addr_description(addr, /*shouldLockThreadRegistry=*/false) {} + void Print(); +}; + +struct ErrorCallocOverflow : ErrorBase { + const BufferedStackTrace *stack; + uptr count; + uptr size; + + ErrorCallocOverflow() = default; // (*) + ErrorCallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr count_, + uptr size_) + : ErrorBase(tid, 10, "calloc-overflow"), + stack(stack_), + count(count_), + size(size_) {} + void Print(); +}; + +struct ErrorPvallocOverflow : ErrorBase { + const BufferedStackTrace *stack; + uptr size; + + ErrorPvallocOverflow() = default; // (*) + ErrorPvallocOverflow(u32 tid, BufferedStackTrace *stack_, uptr size_) + : ErrorBase(tid, 10, "pvalloc-overflow"), + stack(stack_), + size(size_) {} + void Print(); +}; + +struct ErrorInvalidAllocationAlignment : ErrorBase { + const BufferedStackTrace *stack; + uptr alignment; + + ErrorInvalidAllocationAlignment() = default; // (*) + ErrorInvalidAllocationAlignment(u32 tid, BufferedStackTrace *stack_, + uptr alignment_) + : ErrorBase(tid, 10, "invalid-allocation-alignment"), + stack(stack_), + alignment(alignment_) {} + void Print(); +}; + +struct ErrorInvalidAlignedAllocAlignment : ErrorBase { + const BufferedStackTrace *stack; + uptr size; + uptr alignment; + + ErrorInvalidAlignedAllocAlignment() = default; // (*) + ErrorInvalidAlignedAllocAlignment(u32 tid, BufferedStackTrace *stack_, + uptr size_, uptr alignment_) + : ErrorBase(tid, 10, "invalid-aligned-alloc-alignment"), + stack(stack_), + size(size_), + alignment(alignment_) {} + void Print(); +}; + +struct ErrorInvalidPosixMemalignAlignment : ErrorBase { + const BufferedStackTrace *stack; + uptr alignment; + + ErrorInvalidPosixMemalignAlignment() = default; // (*) + ErrorInvalidPosixMemalignAlignment(u32 tid, BufferedStackTrace *stack_, + uptr alignment_) + : ErrorBase(tid, 10, "invalid-posix-memalign-alignment"), + stack(stack_), + alignment(alignment_) {} + void Print(); +}; + +struct ErrorAllocationSizeTooBig : ErrorBase { + const BufferedStackTrace *stack; + uptr user_size; + uptr total_size; + uptr max_size; + + ErrorAllocationSizeTooBig() = default; // (*) + ErrorAllocationSizeTooBig(u32 tid, BufferedStackTrace *stack_, + uptr user_size_, uptr total_size_, uptr max_size_) + : ErrorBase(tid, 10, "allocation-size-too-big"), + stack(stack_), + user_size(user_size_), + total_size(total_size_), + max_size(max_size_) {} + void Print(); +}; + +struct ErrorRssLimitExceeded : ErrorBase { + const BufferedStackTrace *stack; + + ErrorRssLimitExceeded() = default; // (*) + ErrorRssLimitExceeded(u32 tid, BufferedStackTrace *stack_) + : ErrorBase(tid, 10, "rss-limit-exceeded"), + stack(stack_) {} + void Print(); +}; + +struct ErrorOutOfMemory : ErrorBase { + const BufferedStackTrace *stack; + uptr requested_size; + + ErrorOutOfMemory() = default; // (*) + ErrorOutOfMemory(u32 tid, BufferedStackTrace *stack_, uptr requested_size_) + : ErrorBase(tid, 10, "out-of-memory"), + stack(stack_), + requested_size(requested_size_) {} void Print(); }; struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase { - // ErrorStringFunctionMemoryRangesOverlap doesn't own the stack trace. const BufferedStackTrace *stack; uptr length1, length2; AddressDescription addr1_description; AddressDescription addr2_description; const char *function; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorStringFunctionMemoryRangesOverlap() = default; + + ErrorStringFunctionMemoryRangesOverlap() = default; // (*) ErrorStringFunctionMemoryRangesOverlap(u32 tid, BufferedStackTrace *stack_, uptr addr1, uptr length1_, uptr addr2, uptr length2_, const char *function_) @@ -193,65 +284,51 @@ struct ErrorStringFunctionMemoryRangesOverlap : ErrorBase { }; struct ErrorStringFunctionSizeOverflow : ErrorBase { - // ErrorStringFunctionSizeOverflow doesn't own the stack trace. const BufferedStackTrace *stack; AddressDescription addr_description; uptr size; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorStringFunctionSizeOverflow() = default; + + ErrorStringFunctionSizeOverflow() = default; // (*) ErrorStringFunctionSizeOverflow(u32 tid, BufferedStackTrace *stack_, uptr addr, uptr size_) - : ErrorBase(tid), + : ErrorBase(tid, 10, "negative-size-param"), stack(stack_), addr_description(addr, /*shouldLockThreadRegistry=*/false), - size(size_) { - scariness.Clear(); - scariness.Scare(10, "negative-size-param"); - } + size(size_) {} void Print(); }; struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase { - // ErrorBadParamsToAnnotateContiguousContainer doesn't own the stack trace. const BufferedStackTrace *stack; uptr beg, end, old_mid, new_mid; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorBadParamsToAnnotateContiguousContainer() = default; + + ErrorBadParamsToAnnotateContiguousContainer() = default; // (*) // PS4: Do we want an AddressDescription for beg? ErrorBadParamsToAnnotateContiguousContainer(u32 tid, BufferedStackTrace *stack_, uptr beg_, uptr end_, uptr old_mid_, uptr new_mid_) - : ErrorBase(tid), + : ErrorBase(tid, 10, "bad-__sanitizer_annotate_contiguous_container"), stack(stack_), beg(beg_), end(end_), old_mid(old_mid_), - new_mid(new_mid_) { - scariness.Clear(); - scariness.Scare(10, "bad-__sanitizer_annotate_contiguous_container"); - } + new_mid(new_mid_) {} void Print(); }; struct ErrorODRViolation : ErrorBase { __asan_global global1, global2; u32 stack_id1, stack_id2; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorODRViolation() = default; + + ErrorODRViolation() = default; // (*) ErrorODRViolation(u32 tid, const __asan_global *g1, u32 stack_id1_, const __asan_global *g2, u32 stack_id2_) - : ErrorBase(tid), + : ErrorBase(tid, 10, "odr-violation"), global1(*g1), global2(*g2), stack_id1(stack_id1_), - stack_id2(stack_id2_) { - scariness.Clear(); - scariness.Scare(10, "odr-violation"); - } + stack_id2(stack_id2_) {} void Print(); }; @@ -259,20 +336,16 @@ struct ErrorInvalidPointerPair : ErrorBase { uptr pc, bp, sp; AddressDescription addr1_description; AddressDescription addr2_description; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorInvalidPointerPair() = default; + + ErrorInvalidPointerPair() = default; // (*) ErrorInvalidPointerPair(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr p1, uptr p2) - : ErrorBase(tid), + : ErrorBase(tid, 10, "invalid-pointer-pair"), pc(pc_), bp(bp_), sp(sp_), addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false), - addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) { - scariness.Clear(); - scariness.Scare(10, "invalid-pointer-pair"); - } + addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {} void Print(); }; @@ -283,9 +356,8 @@ struct ErrorGeneric : ErrorBase { const char *bug_descr; bool is_write; u8 shadow_val; - // VS2013 doesn't implement unrestricted unions, so we need a trivial default - // constructor - ErrorGeneric() = default; + + ErrorGeneric() = default; // (*) ErrorGeneric(u32 tid, uptr addr, uptr pc_, uptr bp_, uptr sp_, bool is_write_, uptr access_size_); void Print(); @@ -300,6 +372,14 @@ struct ErrorGeneric : ErrorBase { macro(AllocTypeMismatch) \ macro(MallocUsableSizeNotOwned) \ macro(SanitizerGetAllocatedSizeNotOwned) \ + macro(CallocOverflow) \ + macro(PvallocOverflow) \ + macro(InvalidAllocationAlignment) \ + macro(InvalidAlignedAllocAlignment) \ + macro(InvalidPosixMemalignAlignment) \ + macro(AllocationSizeTooBig) \ + macro(RssLimitExceeded) \ + macro(OutOfMemory) \ macro(StringFunctionMemoryRangesOverlap) \ macro(StringFunctionSizeOverflow) \ macro(BadParamsToAnnotateContiguousContainer) \ @@ -334,6 +414,7 @@ struct ErrorDescription { }; ErrorDescription() { internal_memset(this, 0, sizeof(*this)); } + explicit ErrorDescription(LinkerInitialized) {} ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_CONSTRUCTOR) bool IsValid() { return kind != kErrorKindInvalid; } diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index 562168e6d428..5682ab4eb476 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -33,10 +33,7 @@ static const char *MaybeCallAsanDefaultOptions() { static const char *MaybeUseAsanDefaultOptionsCompileDefinition() { #ifdef ASAN_DEFAULT_OPTIONS -// Stringize the macro value. -# define ASAN_STRINGIZE(x) #x -# define ASAN_STRINGIZE_OPTIONS(options) ASAN_STRINGIZE(options) - return ASAN_STRINGIZE_OPTIONS(ASAN_DEFAULT_OPTIONS); + return SANITIZER_STRINGIFY(ASAN_DEFAULT_OPTIONS); #else return ""; #endif @@ -163,6 +160,10 @@ void InitializeFlags() { CHECK_LE(f->max_redzone, 2048); CHECK(IsPowerOfTwo(f->redzone)); CHECK(IsPowerOfTwo(f->max_redzone)); + if (SANITIZER_RTEMS) { + CHECK(!f->unmap_shadow_on_exit); + CHECK(!f->protect_shadow_gap); + } // quarantine_size is deprecated but we still honor it. // quarantine_size can not be used together with quarantine_size_mb. diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc index 00071d39f041..4af94c56fca0 100644 --- a/lib/asan/asan_flags.inc +++ b/lib/asan/asan_flags.inc @@ -88,7 +88,8 @@ ASAN_FLAG(bool, check_malloc_usable_size, true, "295.*.") ASAN_FLAG(bool, unmap_shadow_on_exit, false, "If set, explicitly unmaps the (huge) shadow at exit.") -ASAN_FLAG(bool, protect_shadow_gap, true, "If set, mprotect the shadow gap") +ASAN_FLAG(bool, protect_shadow_gap, !SANITIZER_RTEMS, + "If set, mprotect the shadow gap") ASAN_FLAG(bool, print_stats, false, "Print various statistics after printing an error message or if " "atexit=1.") @@ -136,9 +137,9 @@ ASAN_FLAG( "Android. ") ASAN_FLAG( int, detect_invalid_pointer_pairs, 0, - "If non-zero, try to detect operations like <, <=, >, >= and - on " - "invalid pointer pairs (e.g. when pointers belong to different objects). " - "The bigger the value the harder we try.") + "If >= 2, detect operations like <, <=, >, >= and - on invalid pointer " + "pairs (e.g. when pointers belong to different objects); " + "If == 1, detect invalid operations only when both pointers are non-null.") ASAN_FLAG( bool, detect_container_overflow, true, "If true, honor the container overflow annotations. See " diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index 0db65d010349..898f7f40d31b 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -224,8 +224,9 @@ static void RegisterGlobal(const Global *g) { list_of_all_globals = l; if (g->has_dynamic_init) { if (!dynamic_init_globals) { - dynamic_init_globals = new(allocator_for_globals) - VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); + dynamic_init_globals = + new (allocator_for_globals) VectorOfGlobals; // NOLINT + dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity); } DynInitGlobal dyn_global = { *g, false }; dynamic_init_globals->push_back(dyn_global); @@ -358,9 +359,11 @@ void __asan_register_globals(__asan_global *globals, uptr n) { GET_STACK_TRACE_MALLOC; u32 stack_id = StackDepotPut(stack); BlockingMutexLock lock(&mu_for_globals); - if (!global_registration_site_vector) + if (!global_registration_site_vector) { global_registration_site_vector = - new(allocator_for_globals) GlobalRegistrationSiteVector(128); + new (allocator_for_globals) GlobalRegistrationSiteVector; // NOLINT + global_registration_site_vector->reserve(128); + } GlobalRegistrationSite site = {stack_id, &globals[0], &globals[n - 1]}; global_registration_site_vector->push_back(site); if (flags()->report_globals >= 2) { diff --git a/lib/asan/asan_globals_win.cc b/lib/asan/asan_globals_win.cc index 261762b63e2c..29ab5ebf16d4 100644 --- a/lib/asan/asan_globals_win.cc +++ b/lib/asan/asan_globals_win.cc @@ -19,9 +19,9 @@ namespace __asan { #pragma section(".ASAN$GA", read, write) // NOLINT #pragma section(".ASAN$GZ", read, write) // NOLINT extern "C" __declspec(allocate(".ASAN$GA")) -__asan_global __asan_globals_start = {}; + ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_start = {}; extern "C" __declspec(allocate(".ASAN$GZ")) -__asan_global __asan_globals_end = {}; + ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_end = {}; #pragma comment(linker, "/merge:.ASAN=.data") static void call_on_globals(void (*hook)(__asan_global *, uptr)) { diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index cb7dcb3b1ca8..aac2bb8a6bbf 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -24,15 +24,20 @@ #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" -// There is no general interception at all on Fuchsia. +// There is no general interception at all on Fuchsia and RTEMS. // Only the functions in asan_interceptors_memintrinsics.cc are // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" #endif +#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION || \ + ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION +#include <unwind.h> +#endif + #if defined(__i386) && SANITIZER_LINUX #define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1" #elif defined(__mips__) && SANITIZER_LINUX @@ -178,6 +183,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) (void)(s); \ } while (false) #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" struct ThreadStartParam { atomic_uintptr_t t; @@ -269,7 +275,15 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, uptr stack, ssize; ReadContextStack(ucp, &stack, &ssize); ClearShadowMemoryForContextStack(stack, ssize); +#if __has_attribute(__indirect_return__) && \ + (defined(__x86_64__) || defined(__i386__)) + int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *) + __attribute__((__indirect_return__)) + = REAL(swapcontext); + int res = real_swapcontext(oucp, ucp); +#else int res = REAL(swapcontext)(oucp, ucp); +#endif // swapcontext technically does not return, but program may swap context to // "oucp" later, that would look as if swapcontext() returned 0. // We need to clear shadow for ucp once again, as it may be in arbitrary @@ -318,6 +332,32 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { } #endif +#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION +INTERCEPTOR(void, __cxa_rethrow_primary_exception, void *a) { + CHECK(REAL(__cxa_rethrow_primary_exception)); + __asan_handle_no_return(); + REAL(__cxa_rethrow_primary_exception)(a); +} +#endif + +#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION +INTERCEPTOR(_Unwind_Reason_Code, _Unwind_RaiseException, + _Unwind_Exception *object) { + CHECK(REAL(_Unwind_RaiseException)); + __asan_handle_no_return(); + return REAL(_Unwind_RaiseException)(object); +} +#endif + +#if ASAN_INTERCEPT__SJLJ_UNWIND_RAISEEXCEPTION +INTERCEPTOR(_Unwind_Reason_Code, _Unwind_SjLj_RaiseException, + _Unwind_Exception *object) { + CHECK(REAL(_Unwind_SjLj_RaiseException)); + __asan_handle_no_return(); + return REAL(_Unwind_SjLj_RaiseException)(object); +} +#endif + #if ASAN_INTERCEPT_INDEX # if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX INTERCEPTOR(char*, index, const char *string, int c) @@ -540,14 +580,6 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, } #endif // ASAN_INTERCEPT___CXA_ATEXIT -#if ASAN_INTERCEPT_FORK -INTERCEPTOR(int, fork, void) { - ENSURE_ASAN_INITED(); - int pid = REAL(fork)(); - return pid; -} -#endif // ASAN_INTERCEPT_FORK - // ---------------------- InitializeAsanInterceptors ---------------- {{{1 namespace __asan { void InitializeAsanInterceptors() { @@ -598,6 +630,17 @@ void InitializeAsanInterceptors() { #if ASAN_INTERCEPT___CXA_THROW ASAN_INTERCEPT_FUNC(__cxa_throw); #endif +#if ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION + ASAN_INTERCEPT_FUNC(__cxa_rethrow_primary_exception); +#endif + // Indirectly intercept std::rethrow_exception. +#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION + INTERCEPT_FUNCTION(_Unwind_RaiseException); +#endif + // Indirectly intercept std::rethrow_exception. +#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION + INTERCEPT_FUNCTION(_Unwind_SjLj_RaiseException); +#endif // Intercept threading-related functions #if ASAN_INTERCEPT_PTHREAD_CREATE @@ -614,10 +657,6 @@ void InitializeAsanInterceptors() { ASAN_INTERCEPT_FUNC(__cxa_atexit); #endif -#if ASAN_INTERCEPT_FORK - ASAN_INTERCEPT_FUNC(fork); -#endif - InitializePlatformInterceptors(); VReport(1, "AddressSanitizer: libc interceptors initialized\n"); diff --git a/lib/asan/asan_interceptors.h b/lib/asan/asan_interceptors.h index e13bdecfdede..50895b167990 100644 --- a/lib/asan/asan_interceptors.h +++ b/lib/asan/asan_interceptors.h @@ -34,10 +34,10 @@ void InitializePlatformInterceptors(); } // namespace __asan -// There is no general interception at all on Fuchsia. +// There is no general interception at all on Fuchsia and RTEMS. // Only the functions in asan_interceptors_memintrinsics.h are // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS // Use macro to describe if specific function should be // intercepted on a given platform. @@ -46,13 +46,11 @@ void InitializePlatformInterceptors(); # define ASAN_INTERCEPT__LONGJMP 1 # define ASAN_INTERCEPT_INDEX 1 # define ASAN_INTERCEPT_PTHREAD_CREATE 1 -# define ASAN_INTERCEPT_FORK 1 #else # define ASAN_INTERCEPT_ATOLL_AND_STRTOLL 0 # define ASAN_INTERCEPT__LONGJMP 0 # define ASAN_INTERCEPT_INDEX 0 # define ASAN_INTERCEPT_PTHREAD_CREATE 0 -# define ASAN_INTERCEPT_FORK 0 #endif #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ @@ -80,13 +78,20 @@ void InitializePlatformInterceptors(); # 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)) && \ - !SANITIZER_SOLARIS +#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \ + !SANITIZER_NETBSD # define ASAN_INTERCEPT___CXA_THROW 1 +# 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 +# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 1 +# endif #else # define ASAN_INTERCEPT___CXA_THROW 0 +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 +# define ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION 0 +# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 0 #endif #if !SANITIZER_WINDOWS diff --git a/lib/asan/asan_interceptors_memintrinsics.cc b/lib/asan/asan_interceptors_memintrinsics.cc index c89cb011492e..39e32cdad12e 100644 --- a/lib/asan/asan_interceptors_memintrinsics.cc +++ b/lib/asan/asan_interceptors_memintrinsics.cc @@ -31,14 +31,14 @@ void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } -#if SANITIZER_FUCHSIA +#if SANITIZER_FUCHSIA || SANITIZER_RTEMS -// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only -// things there it wants are these three. Just define them as aliases -// here rather than repeating the contents. +// Fuchsia and RTEMS don't use sanitizer_common_interceptors.inc, but +// the only things there it wants are these three. Just define them +// as aliases here rather than repeating the contents. -decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; -decltype(memmove) memmove[[gnu::alias("__asan_memmove")]]; -decltype(memset) memset[[gnu::alias("__asan_memset")]]; +extern "C" decltype(__asan_memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; +extern "C" decltype(__asan_memmove) memmove[[gnu::alias("__asan_memmove")]]; +extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]]; -#endif // SANITIZER_FUCHSIA +#endif // SANITIZER_FUCHSIA || SANITIZER_RTEMS diff --git a/lib/asan/asan_interceptors_memintrinsics.h b/lib/asan/asan_interceptors_memintrinsics.h index 5a8339a23e97..a071e8f684a0 100644 --- a/lib/asan/asan_interceptors_memintrinsics.h +++ b/lib/asan/asan_interceptors_memintrinsics.h @@ -133,15 +133,22 @@ static inline bool RangesOverlap(const char *offset1, uptr length1, const char *offset2, uptr length2) { return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1)); } -#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \ - const char *offset1 = (const char*)_offset1; \ - const char *offset2 = (const char*)_offset2; \ - if (RangesOverlap(offset1, length1, offset2, length2)) { \ - GET_STACK_TRACE_FATAL_HERE; \ - ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ - offset2, length2, &stack); \ - } \ -} while (0) +#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) \ + do { \ + const char *offset1 = (const char *)_offset1; \ + const char *offset2 = (const char *)_offset2; \ + if (RangesOverlap(offset1, length1, offset2, length2)) { \ + GET_STACK_TRACE_FATAL_HERE; \ + bool suppressed = IsInterceptorSuppressed(name); \ + if (!suppressed && HaveStackTraceBasedSuppressions()) { \ + suppressed = IsStackTraceSuppressed(&stack); \ + } \ + if (!suppressed) { \ + ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \ + offset2, length2, &stack); \ + } \ + } \ + } while (0) } // namespace __asan diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 19133e5291a9..654878cd15f0 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -36,7 +36,7 @@ // If set, values like allocator chunk size, as well as defaults for some flags // will be changed towards less memory overhead. #ifndef ASAN_LOW_MEMORY -# if SANITIZER_IOS || SANITIZER_ANDROID +# if SANITIZER_IOS || SANITIZER_ANDROID || SANITIZER_RTEMS # define ASAN_LOW_MEMORY 1 # else # define ASAN_LOW_MEMORY 0 @@ -78,7 +78,7 @@ void InitializeShadowMemory(); // asan_malloc_linux.cc / asan_malloc_mac.cc void ReplaceSystemMalloc(); -// asan_linux.cc / asan_mac.cc / asan_win.cc +// asan_linux.cc / asan_mac.cc / asan_rtems.cc / asan_win.cc uptr FindDynamicShadowStart(); void *AsanDoesNotSupportStaticLinkage(); void AsanCheckDynamicRTPrereqs(); @@ -147,6 +147,9 @@ const int kAsanArrayCookieMagic = 0xac; const int kAsanIntraObjectRedzone = 0xbb; const int kAsanAllocaLeftMagic = 0xca; const int kAsanAllocaRightMagic = 0xcb; +// Used to populate the shadow gap for systems without memory +// protection there (i.e. Myriad). +const int kAsanShadowGap = 0xcc; static const uptr kCurrentStackFrameMagic = 0x41B58AB3; static const uptr kRetiredStackFrameMagic = 0x45E0360E; diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 047e1dbb72fa..625f32d408df 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -32,6 +32,7 @@ #include <sys/types.h> #include <dlfcn.h> #include <fcntl.h> +#include <limits.h> #include <pthread.h> #include <stdio.h> #include <unistd.h> @@ -214,7 +215,7 @@ void AsanCheckIncompatibleRT() { // 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); - char filename[128]; + char filename[PATH_MAX]; MemoryMappedSegment segment(filename, sizeof(filename)); while (proc_maps.Next(&segment)) { if (IsDynamicRTName(segment.filename)) { diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index b7af1a58664c..17a0ec57701d 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -62,16 +62,36 @@ uptr FindDynamicShadowStart() { uptr space_size = kHighShadowEnd + left_padding; uptr largest_gap_found = 0; - uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, - granularity, &largest_gap_found); + uptr max_occupied_addr = 0; + VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); + uptr shadow_start = + FindAvailableMemoryRange(space_size, alignment, granularity, + &largest_gap_found, &max_occupied_addr); // If the shadow doesn't fit, restrict the address space to make it fit. if (shadow_start == 0) { + VReport( + 2, + "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", + largest_gap_found, max_occupied_addr); uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment); + if (new_max_vm < max_occupied_addr) { + Report("Unable to find a memory range for dynamic shadow.\n"); + Report( + "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " + "new_max_vm = %p\n", + space_size, largest_gap_found, max_occupied_addr, new_max_vm); + CHECK(0 && "cannot place shadow"); + } RestrictMemoryToMaxAddress(new_max_vm); kHighMemEnd = new_max_vm - 1; space_size = kHighShadowEnd + left_padding; - shadow_start = - FindAvailableMemoryRange(space_size, alignment, granularity, nullptr); + VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); + shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, + nullptr, nullptr); + if (shadow_start == 0) { + Report("Unable to find a memory range after restricting VM.\n"); + CHECK(0 && "cannot place shadow after restricting vm"); + } } CHECK_NE((uptr)0, shadow_start); CHECK(IsAligned(shadow_start, alignment)); diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 6697ff8764ed..76bdff999d62 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -16,19 +16,23 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ - SANITIZER_NETBSD || SANITIZER_SOLARIS + SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS +#include "sanitizer_common/sanitizer_allocator_checks.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "asan_allocator.h" #include "asan_interceptors.h" #include "asan_internal.h" +#include "asan_malloc_local.h" #include "asan_stack.h" // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT static uptr allocated_for_dlsym; -static const uptr kDlsymAllocPoolSize = 1024; +static uptr last_dlsym_alloc_size_in_words; +static const uptr kDlsymAllocPoolSize = SANITIZER_RTEMS ? 4096 : 1024; static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; static INLINE bool IsInDlsymAllocPool(const void *ptr) { @@ -39,21 +43,73 @@ static INLINE bool IsInDlsymAllocPool(const void *ptr) { static void *AllocateFromLocalPool(uptr size_in_bytes) { uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym]; + last_dlsym_alloc_size_in_words = size_in_words; allocated_for_dlsym += size_in_words; CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); return mem; } +static void DeallocateFromLocalPool(const void *ptr) { + // Hack: since glibc 2.27 dlsym no longer uses stack-allocated memory to store + // error messages and instead uses malloc followed by free. To avoid pool + // exhaustion due to long object filenames, handle that special case here. + uptr prev_offset = allocated_for_dlsym - last_dlsym_alloc_size_in_words; + void *prev_mem = (void*)&alloc_memory_for_dlsym[prev_offset]; + if (prev_mem == ptr) { + REAL(memset)(prev_mem, 0, last_dlsym_alloc_size_in_words * kWordSize); + allocated_for_dlsym = prev_offset; + last_dlsym_alloc_size_in_words = 0; + } +} + +static int PosixMemalignFromLocalPool(void **memptr, uptr alignment, + uptr size_in_bytes) { + if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) + return errno_EINVAL; + + CHECK(alignment >= kWordSize); + + uptr addr = (uptr)&alloc_memory_for_dlsym[allocated_for_dlsym]; + uptr aligned_addr = RoundUpTo(addr, alignment); + uptr aligned_size = RoundUpTo(size_in_bytes, kWordSize); + + uptr *end_mem = (uptr*)(aligned_addr + aligned_size); + uptr allocated = end_mem - alloc_memory_for_dlsym; + if (allocated >= kDlsymAllocPoolSize) + return errno_ENOMEM; + + allocated_for_dlsym = allocated; + *memptr = (void*)aligned_addr; + return 0; +} + +#if SANITIZER_RTEMS +void* MemalignFromLocalPool(uptr alignment, uptr size) { + void *ptr = nullptr; + alignment = Max(alignment, kWordSize); + PosixMemalignFromLocalPool(&ptr, alignment, size); + return ptr; +} + +bool IsFromLocalPool(const void *ptr) { + return IsInDlsymAllocPool(ptr); +} +#endif + static INLINE bool MaybeInDlsym() { // Fuchsia doesn't use dlsym-based interceptors. return !SANITIZER_FUCHSIA && asan_init_is_running; } +static INLINE bool UseLocalPool() { + return EarlyMalloc() || MaybeInDlsym(); +} + static void *ReallocFromLocalPool(void *ptr, uptr size) { const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); void *new_ptr; - if (UNLIKELY(MaybeInDlsym())) { + if (UNLIKELY(UseLocalPool())) { new_ptr = AllocateFromLocalPool(size); } else { ENSURE_ASAN_INITED(); @@ -66,8 +122,10 @@ static void *ReallocFromLocalPool(void *ptr, uptr size) { INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; - if (UNLIKELY(IsInDlsymAllocPool(ptr))) + if (UNLIKELY(IsInDlsymAllocPool(ptr))) { + DeallocateFromLocalPool(ptr); return; + } asan_free(ptr, &stack, FROM_MALLOC); } @@ -81,7 +139,7 @@ INTERCEPTOR(void, cfree, void *ptr) { #endif // SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void*, malloc, uptr size) { - if (UNLIKELY(MaybeInDlsym())) + if (UNLIKELY(UseLocalPool())) // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. return AllocateFromLocalPool(size); ENSURE_ASAN_INITED(); @@ -90,7 +148,7 @@ INTERCEPTOR(void*, malloc, uptr size) { } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { - if (UNLIKELY(MaybeInDlsym())) + if (UNLIKELY(UseLocalPool())) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. return AllocateFromLocalPool(nmemb * size); ENSURE_ASAN_INITED(); @@ -101,7 +159,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { INTERCEPTOR(void*, realloc, void *ptr, uptr size) { if (UNLIKELY(IsInDlsymAllocPool(ptr))) return ReallocFromLocalPool(ptr, size); - if (UNLIKELY(MaybeInDlsym())) + if (UNLIKELY(UseLocalPool())) return AllocateFromLocalPool(size); ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; @@ -122,10 +180,12 @@ INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) { } #endif // SANITIZER_INTERCEPT_MEMALIGN +#if SANITIZER_INTERCEPT_ALIGNED_ALLOC INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) { GET_STACK_TRACE_MALLOC; - return asan_memalign(boundary, size, &stack, FROM_MALLOC); + return asan_aligned_alloc(boundary, size, &stack); } +#endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { GET_CURRENT_PC_BP_SP; @@ -154,8 +214,9 @@ INTERCEPTOR(int, mallopt, int cmd, int value) { #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { + if (UNLIKELY(UseLocalPool())) + return PosixMemalignFromLocalPool(memptr, alignment, size); GET_STACK_TRACE_MALLOC; - // Printf("posix_memalign: %zx %zu\n", alignment, size); return asan_posix_memalign(memptr, alignment, size, &stack); } diff --git a/lib/asan/asan_malloc_local.h b/lib/asan/asan_malloc_local.h new file mode 100644 index 000000000000..0e8de207d98d --- /dev/null +++ b/lib/asan/asan_malloc_local.h @@ -0,0 +1,44 @@ +//===-- asan_malloc_local.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Provide interfaces to check for and handle local pool memory allocation. +//===----------------------------------------------------------------------===// + +#ifndef ASAN_MALLOC_LOCAL_H +#define ASAN_MALLOC_LOCAL_H + +#include "sanitizer_common/sanitizer_platform.h" +#include "asan_internal.h" + +// On RTEMS, we use the local pool to handle memory allocation when the ASan +// run-time is not up. +static INLINE bool EarlyMalloc() { + return SANITIZER_RTEMS && (!__asan::asan_inited || + __asan::asan_init_is_running); +} + +void* MemalignFromLocalPool(uptr alignment, uptr size); + +#if SANITIZER_RTEMS + +bool IsFromLocalPool(const void *ptr); + +#define ALLOCATE_FROM_LOCAL_POOL UNLIKELY(EarlyMalloc()) +#define IS_FROM_LOCAL_POOL(ptr) UNLIKELY(IsFromLocalPool(ptr)) + +#else // SANITIZER_RTEMS + +#define ALLOCATE_FROM_LOCAL_POOL 0 +#define IS_FROM_LOCAL_POOL(ptr) 0 + +#endif // SANITIZER_RTEMS + +#endif // ASAN_MALLOC_LOCAL_H diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index 744728d40df5..733ba2d86e13 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -38,6 +38,9 @@ using namespace __asan; #define COMMON_MALLOC_CALLOC(count, size) \ GET_STACK_TRACE_MALLOC; \ void *p = asan_calloc(count, size, &stack); +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ + GET_STACK_TRACE_MALLOC; \ + int res = asan_posix_memalign(memptr, alignment, size, &stack); #define COMMON_MALLOC_VALLOC(size) \ GET_STACK_TRACE_MALLOC; \ void *p = asan_memalign(GetPageSizeCached(), size, &stack, FROM_MALLOC); diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index d3f360ffc969..3f8cc004b95f 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -122,6 +122,13 @@ // || `[0x400000000000, 0x47ffffffffff]` || LowShadow || // || `[0x000000000000, 0x3fffffffffff]` || LowMem || // +// Shadow mapping on NerBSD/i386 with SHADOW_OFFSET == 0x40000000: +// || `[0x60000000, 0xfffff000]` || HighMem || +// || `[0x4c000000, 0x5fffffff]` || HighShadow || +// || `[0x48000000, 0x4bffffff]` || ShadowGap || +// || `[0x40000000, 0x47ffffff]` || LowShadow || +// || `[0x00000000, 0x3fffffff]` || LowMem || +// // Default Windows/i386 mapping: // (the exact location of HighShadow/HighMem may vary depending // on WoW64, /LARGEADDRESSAWARE, etc). @@ -130,11 +137,17 @@ // || `[0x36000000, 0x39ffffff]` || ShadowGap || // || `[0x30000000, 0x35ffffff]` || LowShadow || // || `[0x00000000, 0x2fffffff]` || LowMem || +// +// Shadow mapping on Myriad2 (for shadow scale 5): +// || `[0x9ff80000, 0x9fffffff]` || ShadowGap || +// || `[0x9f000000, 0x9ff7ffff]` || LowShadow || +// || `[0x80000000, 0x9effffff]` || LowMem || +// || `[0x00000000, 0x7fffffff]` || Ignored || #if defined(ASAN_SHADOW_SCALE) static const u64 kDefaultShadowScale = ASAN_SHADOW_SCALE; #else -static const u64 kDefaultShadowScale = 3; +static const u64 kDefaultShadowScale = SANITIZER_MYRIAD2 ? 5 : 3; #endif static const u64 kDefaultShadowSentinel = ~(uptr)0; static const u64 kDefaultShadowOffset32 = 1ULL << 29; // 0x20000000 @@ -152,9 +165,19 @@ static const u64 kPPC64_ShadowOffset64 = 1ULL << 44; static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 +static const u64 kNetBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000 static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 +static const u64 kMyriadMemoryOffset32 = 0x80000000ULL; +static const u64 kMyriadMemorySize32 = 0x20000000ULL; +static const u64 kMyriadMemoryEnd32 = + kMyriadMemoryOffset32 + kMyriadMemorySize32 - 1; +static const u64 kMyriadShadowOffset32 = + (kMyriadMemoryOffset32 + kMyriadMemorySize32 - + (kMyriadMemorySize32 >> kDefaultShadowScale)); +static const u64 kMyriadCacheBitMask32 = 0x40000000ULL; + #define SHADOW_SCALE kDefaultShadowScale #if SANITIZER_FUCHSIA @@ -166,6 +189,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # define SHADOW_OFFSET kMIPS32_ShadowOffset32 # elif SANITIZER_FREEBSD # define SHADOW_OFFSET kFreeBSD_ShadowOffset32 +# elif SANITIZER_NETBSD +# define SHADOW_OFFSET kNetBSD_ShadowOffset32 # elif SANITIZER_WINDOWS # define SHADOW_OFFSET kWindowsShadowOffset32 # elif SANITIZER_IOS @@ -174,6 +199,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 # else # define SHADOW_OFFSET kIosShadowOffset32 # endif +# elif SANITIZER_MYRIAD2 +# define SHADOW_OFFSET kMyriadShadowOffset32 # else # define SHADOW_OFFSET kDefaultShadowOffset32 # endif @@ -212,6 +239,39 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 #endif #define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE) + +#define DO_ASAN_MAPPING_PROFILE 0 // Set to 1 to profile the functions below. + +#if DO_ASAN_MAPPING_PROFILE +# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++; +#else +# define PROFILE_ASAN_MAPPING() +#endif + +// If 1, all shadow boundaries are constants. +// Don't set to 1 other than for testing. +#define ASAN_FIXED_MAPPING 0 + +namespace __asan { + +extern uptr AsanMappingProfile[]; + +#if ASAN_FIXED_MAPPING +// Fixed mapping for 64-bit Linux. Mostly used for performance comparison +// with non-fixed mapping. As of r175253 (Feb 2013) the performance +// difference between fixed and non-fixed mapping is below the noise level. +static uptr kHighMemEnd = 0x7fffffffffffULL; +static uptr kMidMemBeg = 0x3000000000ULL; +static uptr kMidMemEnd = 0x4fffffffffULL; +#else +extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. +#endif + +} // namespace __asan + +#if SANITIZER_MYRIAD2 +#include "asan_mapping_myriad.h" +#else #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) #define kLowMemBeg 0 @@ -243,36 +303,11 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000 #define kShadowGap3Beg (kMidMemBeg ? kMidMemEnd + 1 : 0) #define kShadowGap3End (kMidMemBeg ? kHighShadowBeg - 1 : 0) -#define DO_ASAN_MAPPING_PROFILE 0 // Set to 1 to profile the functions below. - -#if DO_ASAN_MAPPING_PROFILE -# define PROFILE_ASAN_MAPPING() AsanMappingProfile[__LINE__]++; -#else -# define PROFILE_ASAN_MAPPING() -#endif - -// If 1, all shadow boundaries are constants. -// Don't set to 1 other than for testing. -#define ASAN_FIXED_MAPPING 0 - namespace __asan { -extern uptr AsanMappingProfile[]; - -#if ASAN_FIXED_MAPPING -// Fixed mapping for 64-bit Linux. Mostly used for performance comparison -// with non-fixed mapping. As of r175253 (Feb 2013) the performance -// difference between fixed and non-fixed mapping is below the noise level. -static uptr kHighMemEnd = 0x7fffffffffffULL; -static uptr kMidMemBeg = 0x3000000000ULL; -static uptr kMidMemEnd = 0x4fffffffffULL; -#else -extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. -#endif - static inline bool AddrIsInLowMem(uptr a) { PROFILE_ASAN_MAPPING(); - return a < kLowMemEnd; + return a <= kLowMemEnd; } static inline bool AddrIsInLowShadow(uptr a) { @@ -280,14 +315,24 @@ static inline bool AddrIsInLowShadow(uptr a) { return a >= kLowShadowBeg && a <= kLowShadowEnd; } +static inline bool AddrIsInMidMem(uptr a) { + PROFILE_ASAN_MAPPING(); + return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd; +} + +static inline bool AddrIsInMidShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + return kMidMemBeg && a >= kMidShadowBeg && a <= kMidShadowEnd; +} + static inline bool AddrIsInHighMem(uptr a) { PROFILE_ASAN_MAPPING(); - return a >= kHighMemBeg && a <= kHighMemEnd; + return kHighMemBeg && a >= kHighMemBeg && a <= kHighMemEnd; } -static inline bool AddrIsInMidMem(uptr a) { +static inline bool AddrIsInHighShadow(uptr a) { PROFILE_ASAN_MAPPING(); - return kMidMemBeg && a >= kMidMemBeg && a <= kMidMemEnd; + return kHighMemBeg && a >= kHighShadowBeg && a <= kHighShadowEnd; } static inline bool AddrIsInShadowGap(uptr a) { @@ -305,6 +350,12 @@ static inline bool AddrIsInShadowGap(uptr a) { return a >= kShadowGapBeg && a <= kShadowGapEnd; } +} // namespace __asan + +#endif // SANITIZER_MYRIAD2 + +namespace __asan { + static inline bool AddrIsInMem(uptr a) { PROFILE_ASAN_MAPPING(); return AddrIsInLowMem(a) || AddrIsInMidMem(a) || AddrIsInHighMem(a) || @@ -317,16 +368,6 @@ static inline uptr MemToShadow(uptr p) { return MEM_TO_SHADOW(p); } -static inline bool AddrIsInHighShadow(uptr a) { - PROFILE_ASAN_MAPPING(); - return a >= kHighShadowBeg && a <= kHighMemEnd; -} - -static inline bool AddrIsInMidShadow(uptr a) { - PROFILE_ASAN_MAPPING(); - return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd; -} - static inline bool AddrIsInShadow(uptr a) { PROFILE_ASAN_MAPPING(); return AddrIsInLowShadow(a) || AddrIsInMidShadow(a) || AddrIsInHighShadow(a); @@ -339,6 +380,8 @@ static inline bool AddrIsAlignedByGranularity(uptr a) { static inline bool AddressIsPoisoned(uptr a) { PROFILE_ASAN_MAPPING(); + if (SANITIZER_MYRIAD2 && !AddrIsInMem(a) && !AddrIsInShadow(a)) + return false; const uptr kAccessSize = 1; u8 *shadow_address = (u8*)MEM_TO_SHADOW(a); s8 shadow_value = *shadow_address; diff --git a/lib/asan/asan_mapping_myriad.h b/lib/asan/asan_mapping_myriad.h new file mode 100644 index 000000000000..baa3247bd190 --- /dev/null +++ b/lib/asan/asan_mapping_myriad.h @@ -0,0 +1,86 @@ +//===-- asan_mapping_myriad.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Myriad-specific definitions for ASan memory mapping. +//===----------------------------------------------------------------------===// +#ifndef ASAN_MAPPING_MYRIAD_H +#define ASAN_MAPPING_MYRIAD_H + +#define RAW_ADDR(mem) ((mem) & ~kMyriadCacheBitMask32) +#define MEM_TO_SHADOW(mem) \ + (((RAW_ADDR(mem) - kLowMemBeg) >> SHADOW_SCALE) + (SHADOW_OFFSET)) + +#define kLowMemBeg kMyriadMemoryOffset32 +#define kLowMemEnd (SHADOW_OFFSET - 1) + +#define kLowShadowBeg SHADOW_OFFSET +#define kLowShadowEnd MEM_TO_SHADOW(kLowMemEnd) + +#define kHighMemBeg 0 + +#define kHighShadowBeg 0 +#define kHighShadowEnd 0 + +#define kMidShadowBeg 0 +#define kMidShadowEnd 0 + +#define kShadowGapBeg (kLowShadowEnd + 1) +#define kShadowGapEnd kMyriadMemoryEnd32 + +#define kShadowGap2Beg 0 +#define kShadowGap2End 0 + +#define kShadowGap3Beg 0 +#define kShadowGap3End 0 + +namespace __asan { + +static inline bool AddrIsInLowMem(uptr a) { + PROFILE_ASAN_MAPPING(); + a = RAW_ADDR(a); + return a >= kLowMemBeg && a <= kLowMemEnd; +} + +static inline bool AddrIsInLowShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + a = RAW_ADDR(a); + return a >= kLowShadowBeg && a <= kLowShadowEnd; +} + +static inline bool AddrIsInMidMem(uptr a) { + PROFILE_ASAN_MAPPING(); + return false; +} + +static inline bool AddrIsInMidShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + return false; +} + +static inline bool AddrIsInHighMem(uptr a) { + PROFILE_ASAN_MAPPING(); + return false; +} + +static inline bool AddrIsInHighShadow(uptr a) { + PROFILE_ASAN_MAPPING(); + return false; +} + +static inline bool AddrIsInShadowGap(uptr a) { + PROFILE_ASAN_MAPPING(); + a = RAW_ADDR(a); + return a >= kShadowGapBeg && a <= kShadowGapEnd; +} + +} // namespace __asan + +#endif // ASAN_MAPPING_MYRIAD_H diff --git a/lib/asan/asan_memory_profile.cc b/lib/asan/asan_memory_profile.cc index 603284c8c688..8c86d9fe49f2 100644 --- a/lib/asan/asan_memory_profile.cc +++ b/lib/asan/asan_memory_profile.cc @@ -31,9 +31,9 @@ struct AllocationSite { class HeapProfile { public: - HeapProfile() : allocations_(1024) {} + HeapProfile() { allocations_.reserve(1024); } - void ProcessChunk(const AsanChunkView& cv) { + void ProcessChunk(const AsanChunkView &cv) { if (cv.IsAllocated()) { total_allocated_user_size_ += cv.UsedSize(); total_allocated_count_++; @@ -49,10 +49,10 @@ class HeapProfile { } void Print(uptr top_percent, uptr max_number_of_contexts) { - InternalSort(&allocations_, allocations_.size(), - [](const AllocationSite &a, const AllocationSite &b) { - return a.total_size > b.total_size; - }); + Sort(allocations_.data(), allocations_.size(), + [](const AllocationSite &a, const AllocationSite &b) { + return a.total_size > b.total_size; + }); CHECK(total_allocated_user_size_); uptr total_shown = 0; Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: " diff --git a/lib/asan/asan_new_delete.cc b/lib/asan/asan_new_delete.cc index 072f027addd6..30efd61a9680 100644 --- a/lib/asan/asan_new_delete.cc +++ b/lib/asan/asan_new_delete.cc @@ -14,6 +14,8 @@ #include "asan_allocator.h" #include "asan_internal.h" +#include "asan_malloc_local.h" +#include "asan_report.h" #include "asan_stack.h" #include "interception/interception.h" @@ -67,16 +69,28 @@ struct nothrow_t {}; enum class align_val_t: size_t {}; } // namespace std -// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +// TODO(alekseyshl): throw std::bad_alloc instead of dying on OOM. +// For local pool allocation, align to SHADOW_GRANULARITY to match asan +// allocator behavior. #define OPERATOR_NEW_BODY(type, nothrow) \ + if (ALLOCATE_FROM_LOCAL_POOL) {\ + void *res = MemalignFromLocalPool(SHADOW_GRANULARITY, size);\ + if (!nothrow) CHECK(res);\ + return res;\ + }\ GET_STACK_TRACE_MALLOC;\ void *res = asan_memalign(0, size, &stack, type);\ - if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ return res; #define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \ + if (ALLOCATE_FROM_LOCAL_POOL) {\ + void *res = MemalignFromLocalPool((uptr)align, size);\ + if (!nothrow) CHECK(res);\ + return res;\ + }\ GET_STACK_TRACE_MALLOC;\ void *res = asan_memalign((uptr)align, size, &stack, type);\ - if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\ + if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\ return res; // On OS X it's not enough to just provide our own 'operator new' and @@ -128,18 +142,22 @@ INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) { #endif // !SANITIZER_MAC #define OPERATOR_DELETE_BODY(type) \ + if (IS_FROM_LOCAL_POOL(ptr)) return;\ GET_STACK_TRACE_FREE;\ asan_delete(ptr, 0, 0, &stack, type); #define OPERATOR_DELETE_BODY_SIZE(type) \ + if (IS_FROM_LOCAL_POOL(ptr)) return;\ GET_STACK_TRACE_FREE;\ asan_delete(ptr, size, 0, &stack, type); #define OPERATOR_DELETE_BODY_ALIGN(type) \ + if (IS_FROM_LOCAL_POOL(ptr)) return;\ GET_STACK_TRACE_FREE;\ asan_delete(ptr, 0, static_cast<uptr>(align), &stack, type); #define OPERATOR_DELETE_BODY_SIZE_ALIGN(type) \ + if (IS_FROM_LOCAL_POOL(ptr)) return;\ GET_STACK_TRACE_FREE;\ asan_delete(ptr, size, static_cast<uptr>(align), &stack, type); diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc index c3a82aa0049e..1e9c37a13a16 100644 --- a/lib/asan/asan_poisoning.cc +++ b/lib/asan/asan_poisoning.cc @@ -32,7 +32,7 @@ bool CanPoisonMemory() { } void PoisonShadow(uptr addr, uptr size, u8 value) { - if (!CanPoisonMemory()) return; + if (value && !CanPoisonMemory()) return; CHECK(AddrIsAlignedByGranularity(addr)); CHECK(AddrIsInMem(addr)); CHECK(AddrIsAlignedByGranularity(addr + size)); @@ -182,8 +182,15 @@ int __asan_address_is_poisoned(void const volatile *addr) { uptr __asan_region_is_poisoned(uptr beg, uptr size) { if (!size) return 0; uptr end = beg + size; - if (!AddrIsInMem(beg)) return beg; - if (!AddrIsInMem(end)) return end; + if (SANITIZER_MYRIAD2) { + // On Myriad, address not in DRAM range need to be treated as + // unpoisoned. + if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0; + if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0; + } else { + if (!AddrIsInMem(beg)) return beg; + if (!AddrIsInMem(end)) return end; + } CHECK_LT(beg, end); uptr aligned_b = RoundUpTo(beg, SHADOW_GRANULARITY); uptr aligned_e = RoundDownTo(end, SHADOW_GRANULARITY); @@ -452,4 +459,3 @@ bool WordIsPoisoned(uptr addr) { return (__asan_region_is_poisoned(addr, sizeof(uptr)) != 0); } } - diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h index 1e00070bcf63..c94794cead89 100644 --- a/lib/asan/asan_poisoning.h +++ b/lib/asan/asan_poisoning.h @@ -38,7 +38,7 @@ void PoisonShadowPartialRightRedzone(uptr addr, // performance-critical code with care. ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, u8 value) { - DCHECK(CanPoisonMemory()); + DCHECK(!value || CanPoisonMemory()); uptr shadow_beg = MEM_TO_SHADOW(aligned_beg); uptr shadow_end = MEM_TO_SHADOW( aligned_beg + aligned_size - SHADOW_GRANULARITY) + 1; @@ -51,6 +51,9 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, // changed at all. It doesn't currently have an efficient means // to zero a bunch of pages, but maybe we should add one. SANITIZER_FUCHSIA == 1 || + // RTEMS doesn't have have pages, let alone a fast way to zero + // them, so default to memset. + SANITIZER_RTEMS == 1 || shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index e3bc02994efd..439712350e46 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -84,7 +84,7 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, bool ParseFrameDescription(const char *frame_descr, InternalMmapVector<StackVarDescr> *vars) { CHECK(frame_descr); - char *p; + const char *p; // This string is created by the compiler and has the following form: // "n alloc_1 alloc_2 ... alloc_n" // where alloc_i looks like "offset size len ObjectName" @@ -134,6 +134,10 @@ class ScopedInErrorReport { } ~ScopedInErrorReport() { + if (halt_on_error_ && !__sanitizer_acquire_crash_state()) { + asanThreadRegistry().Unlock(); + return; + } ASAN_ON_ERROR(); if (current_error_.IsValid()) current_error_.Print(); @@ -152,7 +156,7 @@ class ScopedInErrorReport { // Copy the message buffer so that we could start logging without holding a // lock that gets aquired during printing. - InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize); + InternalMmapVector<char> buffer_copy(kErrorMessageBufferSize); { BlockingMutexLock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), @@ -202,7 +206,7 @@ class ScopedInErrorReport { bool halt_on_error_; }; -ErrorDescription ScopedInErrorReport::current_error_; +ErrorDescription ScopedInErrorReport::current_error_(LINKER_INITIALIZED); void ReportDeadlySignal(const SignalContext &sig) { ScopedInErrorReport in_report(/*fatal*/ true); @@ -254,6 +258,62 @@ void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, in_report.ReportError(error); } +void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size); + in_report.ReportError(error); +} + +void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size); + in_report.ReportError(error); +} + +void ReportInvalidAllocationAlignment(uptr alignment, + BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack, + alignment); + in_report.ReportError(error); +} + +void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, + BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorInvalidAlignedAllocAlignment error(GetCurrentTidOrInvalid(), stack, + size, alignment); + in_report.ReportError(error); +} + +void ReportInvalidPosixMemalignAlignment(uptr alignment, + BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack, + alignment); + in_report.ReportError(error); +} + +void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size, + BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size, + total_size, max_size); + in_report.ReportError(error); +} + +void ReportRssLimitExceeded(BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack); + in_report.ReportError(error); +} + +void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) { + ScopedInErrorReport in_report(/*fatal*/ true); + ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size); + in_report.ReportError(error); +} + void ReportStringFunctionMemoryRangesOverlap(const char *function, const char *offset1, uptr length1, const char *offset2, uptr length2, @@ -343,7 +403,11 @@ static bool IsInvalidPointerPair(uptr a1, uptr a2) { } static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) { - if (!flags()->detect_invalid_pointer_pairs) return; + switch (flags()->detect_invalid_pointer_pairs) { + case 0 : return; + case 1 : if (p1 == nullptr || p2 == nullptr) return; break; + } + uptr a1 = reinterpret_cast<uptr>(p1); uptr a2 = reinterpret_cast<uptr>(p2); diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index f2cdad47ee81..f7153d4810d0 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -58,6 +58,18 @@ void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack, void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack); void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, BufferedStackTrace *stack); +void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack); +void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack); +void ReportInvalidAllocationAlignment(uptr alignment, + BufferedStackTrace *stack); +void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment, + BufferedStackTrace *stack); +void ReportInvalidPosixMemalignAlignment(uptr alignment, + BufferedStackTrace *stack); +void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size, + BufferedStackTrace *stack); +void ReportRssLimitExceeded(BufferedStackTrace *stack); +void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack); void ReportStringFunctionMemoryRangesOverlap(const char *function, const char *offset1, uptr length1, const char *offset2, uptr length2, diff --git a/lib/asan/asan_rtems.cc b/lib/asan/asan_rtems.cc new file mode 100644 index 000000000000..a4af940057eb --- /dev/null +++ b/lib/asan/asan_rtems.cc @@ -0,0 +1,253 @@ +//===-- asan_rtems.cc -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// RTEMS-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_rtems.h" +#if SANITIZER_RTEMS + +#include "asan_internal.h" +#include "asan_interceptors.h" +#include "asan_mapping.h" +#include "asan_poisoning.h" +#include "asan_report.h" +#include "asan_stack.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libc.h" + +#include <pthread.h> +#include <stdlib.h> + +namespace __asan { + +static void ResetShadowMemory() { + uptr shadow_start = SHADOW_OFFSET; + uptr shadow_end = MEM_TO_SHADOW(kMyriadMemoryEnd32); + uptr gap_start = MEM_TO_SHADOW(shadow_start); + uptr gap_end = MEM_TO_SHADOW(shadow_end); + + REAL(memset)((void *)shadow_start, 0, shadow_end - shadow_start); + REAL(memset)((void *)gap_start, kAsanShadowGap, gap_end - gap_start); +} + +void InitializeShadowMemory() { + kHighMemEnd = 0; + kMidMemBeg = 0; + kMidMemEnd = 0; + + ResetShadowMemory(); +} + +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + +void AsanCheckDynamicRTPrereqs() {} +void AsanCheckIncompatibleRT() {} +void InitializeAsanInterceptors() {} +void InitializePlatformInterceptors() {} +void InitializePlatformExceptionHandlers() {} + +// RTEMS only support static linking; it sufficies to return with no +// error. +void *AsanDoesNotSupportStaticLinkage() { return nullptr; } + +void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { + UNIMPLEMENTED(); +} + +void EarlyInit() { + // Provide early initialization of shadow memory so that + // instrumented code running before full initialzation will not + // report spurious errors. + ResetShadowMemory(); +} + +// We can use a plain thread_local variable for TSD. +static thread_local void *per_thread; + +void *AsanTSDGet() { return per_thread; } + +void AsanTSDSet(void *tsd) { per_thread = tsd; } + +// There's no initialization needed, and the passed-in destructor +// will never be called. Instead, our own thread destruction hook +// (below) will call AsanThread::TSDDtor directly. +void AsanTSDInit(void (*destructor)(void *tsd)) { + DCHECK(destructor == &PlatformTSDDtor); +} + +void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); } + +// +// Thread registration. We provide an API similar to the Fushia port. +// + +struct AsanThread::InitOptions { + uptr stack_bottom, stack_size, tls_bottom, tls_size; +}; + +// Shared setup between thread creation and startup for the initial thread. +static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, + uptr user_id, bool detached, + uptr stack_bottom, uptr stack_size, + uptr tls_bottom, uptr tls_size) { + // In lieu of AsanThread::Create. + AsanThread *thread = (AsanThread *)MmapOrDie(sizeof(AsanThread), __func__); + AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; + asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); + + // On other systems, AsanThread::Init() is called from the new + // thread itself. But on RTEMS we already know the stack address + // range beforehand, so we can do most of the setup right now. + const AsanThread::InitOptions options = {stack_bottom, stack_size, + tls_bottom, tls_size}; + thread->Init(&options); + return thread; +} + +// This gets the same arguments passed to Init by CreateAsanThread, above. +// We're in the creator thread before the new thread is actually started, but +// its stack and tls address range are already known. +void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) { + DCHECK_NE(GetCurrentThread(), this); + DCHECK_NE(GetCurrentThread(), nullptr); + CHECK_NE(options->stack_bottom, 0); + CHECK_NE(options->stack_size, 0); + stack_bottom_ = options->stack_bottom; + stack_top_ = options->stack_bottom + options->stack_size; + tls_begin_ = options->tls_bottom; + tls_end_ = options->tls_bottom + options->tls_size; +} + +// Called by __asan::AsanInitInternal (asan_rtl.c). Unlike other ports, the +// main thread on RTEMS does not require special treatment; its AsanThread is +// already created by the provided hooks. This function simply looks up and +// returns the created thread. +AsanThread *CreateMainThread() { + return GetThreadContextByTidLocked(0)->thread; +} + +// This is called before each thread creation is attempted. So, in +// its first call, the calling thread is the initial and sole thread. +static void *BeforeThreadCreateHook(uptr user_id, bool detached, + uptr stack_bottom, uptr stack_size, + uptr tls_bottom, uptr tls_size) { + EnsureMainThreadIDIsCorrect(); + // Strict init-order checking is thread-hostile. + if (flags()->strict_init_order) StopInitOrderChecking(); + + GET_STACK_TRACE_THREAD; + u32 parent_tid = GetCurrentTidOrInvalid(); + + return CreateAsanThread(&stack, parent_tid, user_id, detached, + stack_bottom, stack_size, tls_bottom, tls_size); +} + +// This is called after creating a new thread (in the creating thread), +// with the pointer returned by BeforeThreadCreateHook (above). +static void ThreadCreateHook(void *hook, bool aborted) { + AsanThread *thread = static_cast<AsanThread *>(hook); + if (!aborted) { + // The thread was created successfully. + // ThreadStartHook is already running in the new thread. + } else { + // The thread wasn't created after all. + // Clean up everything we set up in BeforeThreadCreateHook. + asanThreadRegistry().FinishThread(thread->tid()); + UnmapOrDie(thread, sizeof(AsanThread)); + } +} + +// This is called (1) in the newly-created thread before it runs anything else, +// with the pointer returned by BeforeThreadCreateHook (above). (2) before a +// thread restart. +static void ThreadStartHook(void *hook, uptr os_id) { + if (!hook) + return; + + AsanThread *thread = static_cast<AsanThread *>(hook); + SetCurrentThread(thread); + + ThreadStatus status = + asanThreadRegistry().GetThreadLocked(thread->tid())->status; + DCHECK(status == ThreadStatusCreated || status == ThreadStatusRunning); + // Determine whether we are starting or restarting the thread. + if (status == ThreadStatusCreated) + // In lieu of AsanThread::ThreadStart. + asanThreadRegistry().StartThread(thread->tid(), os_id, + /*workerthread*/ false, nullptr); + else { + // In a thread restart, a thread may resume execution at an + // arbitrary function entry point, with its stack and TLS state + // reset. We unpoison the stack in that case. + PoisonShadow(thread->stack_bottom(), thread->stack_size(), 0); + } +} + +// Each thread runs this just before it exits, +// with the pointer returned by BeforeThreadCreateHook (above). +// All per-thread destructors have already been called. +static void ThreadExitHook(void *hook, uptr os_id) { + AsanThread *thread = static_cast<AsanThread *>(hook); + if (thread) + AsanThread::TSDDtor(thread->context()); +} + +static void HandleExit() { + // Disable ASan by setting it to uninitialized. Also reset the + // shadow memory to avoid reporting errors after the run-time has + // been desroyed. + if (asan_inited) { + asan_inited = false; + ResetShadowMemory(); + } +} + +} // namespace __asan + +// These are declared (in extern "C") by <some_path/sanitizer.h>. +// The system runtime will call our definitions directly. + +extern "C" { +void __sanitizer_early_init() { + __asan::EarlyInit(); +} + +void *__sanitizer_before_thread_create_hook(uptr thread, bool detached, + const char *name, + void *stack_base, size_t stack_size, + void *tls_base, size_t tls_size) { + return __asan::BeforeThreadCreateHook( + thread, detached, + reinterpret_cast<uptr>(stack_base), stack_size, + reinterpret_cast<uptr>(tls_base), tls_size); +} + +void __sanitizer_thread_create_hook(void *handle, uptr thread, int status) { + __asan::ThreadCreateHook(handle, status != 0); +} + +void __sanitizer_thread_start_hook(void *handle, uptr self) { + __asan::ThreadStartHook(handle, self); +} + +void __sanitizer_thread_exit_hook(void *handle, uptr self) { + __asan::ThreadExitHook(handle, self); +} + +void __sanitizer_exit() { + __asan::HandleExit(); +} +} // "C" + +#endif // SANITIZER_RTEMS diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index 21fd0e240708..4cff736f213a 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -56,7 +56,8 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); UnmapOrDie((void*)kMidMemEnd, kHighShadowEnd - kMidMemEnd); } else { - UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); + if (kHighShadowEnd) + UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } } @@ -65,8 +66,14 @@ static void AsanCheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2) { Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file, line, cond, (uptr)v1, (uptr)v2); - // FIXME: check for infinite recursion without a thread-local counter here. - PRINT_CURRENT_STACK_CHECK(); + + // Print a stack trace the first time we come here. Otherwise, we probably + // failed a CHECK during symbolization. + static atomic_uint32_t num_calls; + if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) { + PRINT_CURRENT_STACK_CHECK(); + } + Die(); } @@ -140,6 +147,8 @@ ASAN_REPORT_ERROR_N(load, false) ASAN_REPORT_ERROR_N(store, true) #define ASAN_MEMORY_ACCESS_CALLBACK_BODY(type, is_write, size, exp_arg, fatal) \ + if (SANITIZER_MYRIAD2 && !AddrIsInMem(addr) && !AddrIsInShadow(addr)) \ + return; \ uptr sp = MEM_TO_SHADOW(addr); \ uptr s = size <= SHADOW_GRANULARITY ? *reinterpret_cast<u8 *>(sp) \ : *reinterpret_cast<u16 *>(sp); \ @@ -306,6 +315,7 @@ static void asan_atexit() { } static void InitializeHighMemEnd() { +#if !SANITIZER_MYRIAD2 #if !ASAN_FIXED_MAPPING kHighMemEnd = GetMaxUserVirtualAddress(); // Increase kHighMemEnd to make sure it's properly @@ -313,13 +323,16 @@ static void InitializeHighMemEnd() { kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1; #endif // !ASAN_FIXED_MAPPING CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0); +#endif // !SANITIZER_MYRIAD2 } void PrintAddressSpaceLayout() { - Printf("|| `[%p, %p]` || HighMem ||\n", - (void*)kHighMemBeg, (void*)kHighMemEnd); - Printf("|| `[%p, %p]` || HighShadow ||\n", - (void*)kHighShadowBeg, (void*)kHighShadowEnd); + if (kHighMemBeg) { + Printf("|| `[%p, %p]` || HighMem ||\n", + (void*)kHighMemBeg, (void*)kHighMemEnd); + Printf("|| `[%p, %p]` || HighShadow ||\n", + (void*)kHighShadowBeg, (void*)kHighShadowEnd); + } if (kMidMemBeg) { Printf("|| `[%p, %p]` || ShadowGap3 ||\n", (void*)kShadowGap3Beg, (void*)kShadowGap3End); @@ -338,11 +351,14 @@ void PrintAddressSpaceLayout() { Printf("|| `[%p, %p]` || LowMem ||\n", (void*)kLowMemBeg, (void*)kLowMemEnd); } - Printf("MemToShadow(shadow): %p %p %p %p", + Printf("MemToShadow(shadow): %p %p", (void*)MEM_TO_SHADOW(kLowShadowBeg), - (void*)MEM_TO_SHADOW(kLowShadowEnd), - (void*)MEM_TO_SHADOW(kHighShadowBeg), - (void*)MEM_TO_SHADOW(kHighShadowEnd)); + (void*)MEM_TO_SHADOW(kLowShadowEnd)); + if (kHighMemBeg) { + Printf(" %p %p", + (void*)MEM_TO_SHADOW(kHighShadowBeg), + (void*)MEM_TO_SHADOW(kHighShadowEnd)); + } if (kMidMemBeg) { Printf(" %p %p", (void*)MEM_TO_SHADOW(kMidShadowBeg), @@ -374,6 +390,7 @@ static void AsanInitInternal() { asan_init_is_running = true; CacheBinaryName(); + CheckASLR(); // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). @@ -526,6 +543,9 @@ void NOINLINE __asan_handle_no_return() { if (curr_thread) { top = curr_thread->stack_top(); bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); + } else if (SANITIZER_RTEMS) { + // Give up On RTEMS. + return; } else { CHECK(!SANITIZER_FUCHSIA); // If we haven't seen this thread, try asking the OS for stack bounds. diff --git a/lib/asan/asan_shadow_setup.cc b/lib/asan/asan_shadow_setup.cc index b3cf0b5c1ce2..083926e70aa2 100644 --- a/lib/asan/asan_shadow_setup.cc +++ b/lib/asan/asan_shadow_setup.cc @@ -14,8 +14,9 @@ #include "sanitizer_common/sanitizer_platform.h" -// asan_fuchsia.cc has its own InitializeShadowMemory implementation. -#if !SANITIZER_FUCHSIA +// asan_fuchsia.cc and asan_rtems.cc have their own +// InitializeShadowMemory implementation. +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS #include "asan_internal.h" #include "asan_mapping.h" @@ -30,8 +31,7 @@ void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); uptr size = end - beg + 1; DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. - void *res = MmapFixedNoReserve(beg, size, name); - if (res != (void *)beg) { + if (!MmapFixedNoReserve(beg, size, name)) { Report( "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " "Perhaps you're using ulimit -v\n", @@ -162,4 +162,4 @@ void InitializeShadowMemory() { } // namespace __asan -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index ad81512dff08..faf423d305b7 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -221,22 +221,25 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { void AsanThread::Init(const InitOptions *options) { next_stack_top_ = next_stack_bottom_ = 0; atomic_store(&stack_switching_, false, memory_order_release); - fake_stack_ = nullptr; // Will be initialized lazily if needed. CHECK_EQ(this->stack_size(), 0U); SetThreadStackAndTls(options); CHECK_GT(this->stack_size(), 0U); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); ClearShadowForThreadStackAndTLS(); + fake_stack_ = nullptr; + if (__asan_option_detect_stack_use_after_return) + AsyncSignalSafeLazyInitFakeStack(); int local = 0; VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, &local); } -// Fuchsia doesn't use ThreadStart. -// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls. -#if !SANITIZER_FUCHSIA +// Fuchsia and RTEMS don't use ThreadStart. +// asan_fuchsia.c/asan_rtems.c define CreateMainThread and +// SetThreadStackAndTls. +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS thread_return_t AsanThread::ThreadStart( tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) { @@ -296,12 +299,17 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) { CHECK(AddrIsInStack((uptr)&local)); } -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); - if (tls_begin_ != tls_end_) - PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); + if (tls_begin_ != tls_end_) { + uptr tls_begin_aligned = RoundDownTo(tls_begin_, SHADOW_GRANULARITY); + uptr tls_end_aligned = RoundUpTo(tls_end_, SHADOW_GRANULARITY); + FastPoisonShadowPartialRightRedzone(tls_begin_aligned, + tls_end_ - tls_begin_aligned, + tls_end_aligned - tls_end_, 0); + } } bool AsanThread::GetStackFrameAccessByAddr(uptr addr, @@ -386,6 +394,9 @@ static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, } AsanThread *GetCurrentThread() { + if (SANITIZER_RTEMS && !asan_inited) + return nullptr; + AsanThreadContext *context = reinterpret_cast<AsanThreadContext *>(AsanTSDGet()); if (!context) { @@ -477,6 +488,11 @@ void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); } +ThreadRegistry *GetThreadRegistryLocked() { + __asan::asanThreadRegistry().CheckLocked(); + return &__asan::asanThreadRegistry(); +} + void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); } diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index 68eedd1863bc..67125d38ad4a 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -222,8 +222,8 @@ uptr FindDynamicShadowStart() { uptr alignment = 8 * granularity; uptr left_padding = granularity; uptr space_size = kHighShadowEnd + left_padding; - uptr shadow_start = - FindAvailableMemoryRange(space_size, alignment, granularity, nullptr); + uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, + granularity, nullptr, nullptr); CHECK_NE((uptr)0, shadow_start); CHECK(IsAligned(shadow_start, alignment)); return shadow_start; @@ -265,11 +265,6 @@ ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) { // Determine the address of the page that is being accessed. uptr page = RoundDownTo(addr, page_size); - // Query the existing page. - MEMORY_BASIC_INFORMATION mem_info = {}; - if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0) - return EXCEPTION_CONTINUE_SEARCH; - // Commit the page. uptr result = (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE); diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc index c67116c42ca2..c6a313d24026 100644 --- a/lib/asan/asan_win_dll_thunk.cc +++ b/lib/asan/asan_win_dll_thunk.cc @@ -99,7 +99,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { } #endif -// Window specific functions not included in asan_interface.inc. +// Windows specific functions not included in asan_interface.inc. INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return) INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address) INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter) diff --git a/lib/asan/scripts/asan_device_setup b/lib/asan/scripts/asan_device_setup index 92a109727267..5e679e366514 100755 --- a/lib/asan/scripts/asan_device_setup +++ b/lib/asan/scripts/asan_device_setup @@ -309,7 +309,7 @@ if [[ -n "$ASAN_RT64" ]]; then cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/" fi -ASAN_OPTIONS=start_deactivated=1,malloc_context_size=0 +ASAN_OPTIONS=start_deactivated=1 # The name of a symlink to libclang_rt.asan-$ARCH-android.so used in LD_PRELOAD. # The idea is to have the same name in lib and lib64 to keep it from falling @@ -336,6 +336,13 @@ exec $_to \$@ EOF } +# On Android-L not allowing user segv handler breaks some applications. +# Since ~May 2017 this is the default setting; included for compatibility with +# older library versions. +if [[ PRE_L -eq 0 ]]; then + ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" +fi + if [[ x$extra_options != x ]] ; then ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" fi diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 67a8fafaba3c..1b7060591530 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -237,6 +237,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) if(APPLE) darwin_filter_host_archs(ASAN_SUPPORTED_ARCH ASAN_TEST_ARCH) endif() + if(OS_NAME MATCHES "SunOS") + list(REMOVE_ITEM ASAN_TEST_ARCH x86_64) + endif() foreach(arch ${ASAN_TEST_ARCH}) @@ -248,6 +251,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) $<TARGET_OBJECTS:RTInterception.osx> $<TARGET_OBJECTS:RTSanitizerCommon.osx> $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx> + $<TARGET_OBJECTS:RTSanitizerCommonCoverage.osx> + $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.osx> $<TARGET_OBJECTS:RTLSanCommon.osx> $<TARGET_OBJECTS:RTUbsan.osx>) else() @@ -257,6 +262,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) $<TARGET_OBJECTS:RTInterception.${arch}> $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}> $<TARGET_OBJECTS:RTLSanCommon.${arch}> $<TARGET_OBJECTS:RTUbsan.${arch}> $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>) @@ -280,6 +287,8 @@ if(ANDROID) $<TARGET_OBJECTS:RTInterception.${arch}> $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}> $<TARGET_OBJECTS:RTUbsan.${arch}> $<TARGET_OBJECTS:RTUbsan_cxx.${arch}> ${COMPILER_RT_GTEST_SOURCE} diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index ed000327f126..11a3506a4853 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -25,6 +25,11 @@ #endif #endif +#if defined(__sun__) && defined(__svr4__) +using std::_setjmp; +using std::_longjmp; +#endif + NOINLINE void *malloc_fff(size_t size) { void *res = malloc/**/(size); break_optimization(0); return res;} NOINLINE void *malloc_eee(size_t size) { |