diff options
author | Kostya Serebryany <kcc@google.com> | 2013-12-05 09:18:38 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@gcc.gnu.org> | 2013-12-05 09:18:38 +0000 |
commit | df77f0e4ec043bc4fa155efbd5c1c74ce73d2b50 (patch) | |
tree | 20d85354103063e38b162a6a90b7ae51fb4b6104 /libsanitizer/asan | |
parent | 649d196dbd78a119786f204d36b7c5d4dcb3a949 (diff) | |
download | gcc-df77f0e4ec043bc4fa155efbd5c1c74ce73d2b50.tar.gz |
libsanitizer merge from upstream r196090
From-SVN: r205695
Diffstat (limited to 'libsanitizer/asan')
25 files changed, 344 insertions, 219 deletions
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h index 1f83dcd6780..763f4a58ef9 100644 --- a/libsanitizer/asan/asan_allocator.h +++ b/libsanitizer/asan/asan_allocator.h @@ -33,10 +33,11 @@ void InitializeAllocator(); class AsanChunkView { public: explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} - bool IsValid() { return chunk_ != 0; } - uptr Beg(); // first byte of user memory. - uptr End(); // last byte of user memory. - uptr UsedSize(); // size requested by the user. + bool IsValid(); // Checks if AsanChunkView points to a valid allocated + // or quarantined chunk. + uptr Beg(); // First byte of user memory. + uptr End(); // Last byte of user memory. + uptr UsedSize(); // Size requested by the user. uptr AllocTid(); uptr FreeTid(); void GetAllocStack(StackTrace *stack); @@ -88,16 +89,12 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> { }; struct AsanThreadLocalMallocStorage { - explicit AsanThreadLocalMallocStorage(LinkerInitialized x) - { } - AsanThreadLocalMallocStorage() { - CHECK(REAL(memset)); - REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage)); - } - uptr quarantine_cache[16]; uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque. void CommitBack(); + private: + // These objects are allocated via mmap() and are zero-initialized. + AsanThreadLocalMallocStorage() {} }; void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, @@ -112,7 +109,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, StackTrace *stack); -uptr asan_malloc_usable_size(void *ptr, StackTrace *stack); +uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp); uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); diff --git a/libsanitizer/asan/asan_allocator2.cc b/libsanitizer/asan/asan_allocator2.cc index 34aad11ed75..b9d66dc7a4a 100644 --- a/libsanitizer/asan/asan_allocator2.cc +++ b/libsanitizer/asan/asan_allocator2.cc @@ -92,7 +92,7 @@ AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) { static Allocator allocator; static const uptr kMaxAllowedMallocSize = - FIRST_32_SECOND_64(3UL << 30, 8UL << 30); + FIRST_32_SECOND_64(3UL << 30, 64UL << 30); static const uptr kMaxThreadLocalQuarantine = FIRST_32_SECOND_64(1 << 18, 1 << 20); @@ -184,14 +184,19 @@ COMPILER_CHECK(kChunkHeader2Size <= 16); struct AsanChunk: ChunkBase { uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; } - uptr UsedSize() { + uptr UsedSize(bool locked_version = false) { if (user_requested_size != SizeClassMap::kMaxSize) return user_requested_size; - return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBeg())); - } - void *AllocBeg() { - if (from_memalign) + return *reinterpret_cast<uptr *>( + allocator.GetMetaData(AllocBeg(locked_version))); + } + void *AllocBeg(bool locked_version = false) { + if (from_memalign) { + if (locked_version) + return allocator.GetBlockBeginFastLocked( + reinterpret_cast<void *>(this)); return allocator.GetBlockBegin(reinterpret_cast<void *>(this)); + } return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log)); } // If we don't use stack depot, we store the alloc/free stack traces @@ -211,11 +216,14 @@ struct AsanChunk: ChunkBase { uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY); return (available - kChunkHeader2Size) / sizeof(u32); } - bool AddrIsInside(uptr addr) { - return (addr >= Beg()) && (addr < Beg() + UsedSize()); + bool AddrIsInside(uptr addr, bool locked_version = false) { + return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version)); } }; +bool AsanChunkView::IsValid() { + return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE; +} uptr AsanChunkView::Beg() { return chunk_->Beg(); } uptr AsanChunkView::End() { return Beg() + UsedSize(); } uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } @@ -226,25 +234,16 @@ static void GetStackTraceFromId(u32 id, StackTrace *stack) { CHECK(id); uptr size = 0; const uptr *trace = StackDepotGet(id, &size); - CHECK_LT(size, kStackTraceMax); - internal_memcpy(stack->trace, trace, sizeof(uptr) * size); - stack->size = size; + CHECK(trace); + stack->CopyFrom(trace, size); } void AsanChunkView::GetAllocStack(StackTrace *stack) { - if (flags()->use_stack_depot) - GetStackTraceFromId(chunk_->alloc_context_id, stack); - else - StackTrace::UncompressStack(stack, chunk_->AllocStackBeg(), - chunk_->AllocStackSize()); + GetStackTraceFromId(chunk_->alloc_context_id, stack); } void AsanChunkView::GetFreeStack(StackTrace *stack) { - if (flags()->use_stack_depot) - GetStackTraceFromId(chunk_->free_context_id, stack); - else - StackTrace::UncompressStack(stack, chunk_->FreeStackBeg(), - chunk_->FreeStackSize()); + GetStackTraceFromId(chunk_->free_context_id, stack); } struct QuarantineCallback; @@ -390,12 +389,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, meta[1] = chunk_beg; } - if (fl.use_stack_depot) { - m->alloc_context_id = StackDepotPut(stack->trace, stack->size); - } else { - m->alloc_context_id = 0; - StackTrace::CompressStack(stack, m->AllocStackBeg(), m->AllocStackSize()); - } + m->alloc_context_id = StackDepotPut(stack->trace, stack->size); uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY); // Unpoison the bulk of the memory region. @@ -404,7 +398,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, // Deal with the end of the region if size is not aligned to granularity. if (size != size_rounded_down_to_granularity && fl.poison_heap) { u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity); - *shadow = size & (SHADOW_GRANULARITY - 1); + *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0; } AsanStats &thread_stats = GetCurrentThreadStats(); @@ -463,12 +457,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, CHECK_EQ(m->free_tid, kInvalidTid); AsanThread *t = GetCurrentThread(); m->free_tid = t ? t->tid() : 0; - if (flags()->use_stack_depot) { - m->free_context_id = StackDepotPut(stack->trace, stack->size); - } else { - m->free_context_id = 0; - StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize()); - } + m->free_context_id = StackDepotPut(stack->trace, stack->size); // Poison the region. PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), @@ -673,12 +662,13 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, return 0; } -uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) { - CHECK(stack); +uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) { if (ptr == 0) return 0; uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr)); - if (flags()->check_malloc_usable_size && (usable_size == 0)) - ReportMallocUsableSizeNotOwned((uptr)ptr, stack); + if (flags()->check_malloc_usable_size && (usable_size == 0)) { + GET_STACK_TRACE_FATAL(pc, bp); + ReportMallocUsableSizeNotOwned((uptr)ptr, &stack); + } return usable_size; } @@ -718,7 +708,8 @@ uptr PointsIntoChunk(void* p) { __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr); if (!m) return 0; uptr chunk = m->Beg(); - if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) + if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && + m->AddrIsInside(addr, /*locked_version=*/true)) return chunk; return 0; } @@ -751,7 +742,7 @@ void LsanMetadata::set_tag(ChunkTag value) { uptr LsanMetadata::requested_size() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); - return m->UsedSize(); + return m->UsedSize(/*locked_version=*/true); } u32 LsanMetadata::stack_trace_id() const { diff --git a/libsanitizer/asan/asan_dll_thunk.cc b/libsanitizer/asan/asan_dll_thunk.cc index 26e19441523..19c31f0def8 100644 --- a/libsanitizer/asan/asan_dll_thunk.cc +++ b/libsanitizer/asan/asan_dll_thunk.cc @@ -130,6 +130,8 @@ extern "C" { } } +WRAP_V_V(__asan_handle_no_return) + WRAP_V_W(__asan_report_store1) WRAP_V_W(__asan_report_store2) WRAP_V_W(__asan_report_store4) diff --git a/libsanitizer/asan/asan_fake_stack.cc b/libsanitizer/asan/asan_fake_stack.cc index b9cce88f34f..cf4122472ef 100644 --- a/libsanitizer/asan/asan_fake_stack.cc +++ b/libsanitizer/asan/asan_fake_stack.cc @@ -43,7 +43,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) { FakeStack *res = reinterpret_cast<FakeStack *>( MmapOrDie(RequiredSize(stack_size_log), "FakeStack")); res->stack_size_log_ = stack_size_log; - if (flags()->verbosity) { + if (common_flags()->verbosity) { u8 *p = reinterpret_cast<u8 *>(res); Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n", GetCurrentTidOrInvalid(), p, @@ -132,6 +132,20 @@ NOINLINE void FakeStack::GC(uptr real_stack) { needs_gc_ = false; } +void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { + for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { + u8 *flags = GetFlags(stack_size_log(), class_id); + for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; + i++) { + if (flags[i] == 0) continue; // not allocated. + FakeFrame *ff = reinterpret_cast<FakeFrame *>( + GetFrame(stack_size_log(), class_id, i)); + uptr begin = reinterpret_cast<uptr>(ff); + callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg); + } + } +} + #if SANITIZER_LINUX && !SANITIZER_ANDROID static THREADLOCAL FakeStack *fake_stack_tls; diff --git a/libsanitizer/asan/asan_fake_stack.h b/libsanitizer/asan/asan_fake_stack.h index 4287497fd5d..5196025681c 100644 --- a/libsanitizer/asan/asan_fake_stack.h +++ b/libsanitizer/asan/asan_fake_stack.h @@ -146,6 +146,8 @@ class FakeStack { void HandleNoReturn(); void GC(uptr real_stack); + void ForEachFakeFrame(RangeIteratorCallback callback, void *arg); + private: FakeStack() { } static const uptr kFlagsOffset = 4096; // This is were the flags begin. diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h index c115997ff29..62b5d3215d3 100644 --- a/libsanitizer/asan/asan_flags.h +++ b/libsanitizer/asan/asan_flags.h @@ -30,8 +30,6 @@ struct Flags { // Lower value may reduce memory usage but increase the chance of // false negatives. int quarantine_size; - // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output). - int verbosity; // Size (in bytes) of redzones around heap objects. // Requirement: redzone >= 32, is a power of two. int redzone; @@ -83,6 +81,9 @@ struct Flags { bool print_legend; // If set, prints ASan exit stats even after program terminates successfully. bool atexit; + // If set, coverage information will be dumped at shutdown time if the + // appropriate instrumentation was enabled. + bool coverage; // By default, disable core dumper on 64-bit - it makes little sense // to dump 16T+ core. bool disable_core; @@ -96,10 +97,11 @@ struct Flags { // Poison (or not) the heap memory on [de]allocation. Zero value is useful // for benchmarking the allocator or instrumentator. bool poison_heap; + // If true, poison partially addressable 8-byte aligned words (default=true). + // This flag affects heap and global buffers, but not stack buffers. + bool poison_partial; // Report errors on malloc/delete, new/free, new/delete[], etc. bool alloc_dealloc_mismatch; - // Use stack depot instead of storing stacks in the redzones. - bool use_stack_depot; // If true, assume that memcmp(p1, p2, n) always reads n bytes before // comparing p1 and p2. bool strict_memcmp; diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc index 96985af71a9..e97850a854a 100644 --- a/libsanitizer/asan/asan_globals.cc +++ b/libsanitizer/asan/asan_globals.cc @@ -92,15 +92,13 @@ static void RegisterGlobal(const Global *g) { CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (flags()->poison_heap) PoisonRedZones(*g); - ListOfGlobals *l = - (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals)); + ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals; l->g = g; l->next = list_of_all_globals; list_of_all_globals = l; if (g->has_dynamic_init) { if (dynamic_init_globals == 0) { - void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals)); - dynamic_init_globals = new(mem) + dynamic_init_globals = new(allocator_for_globals) VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); } DynInitGlobal dyn_global = { *g, false }; diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc index 72f7aae814a..decbfea5f75 100644 --- a/libsanitizer/asan/asan_interceptors.cc +++ b/libsanitizer/asan/asan_interceptors.cc @@ -92,6 +92,11 @@ void SetThreadName(const char *name) { asanThreadRegistry().SetThreadName(t->tid(), name); } +int OnExit() { + // FIXME: ask frontend whether we need to return failure. + return 0; +} + } // namespace __asan // ---------------------- Wrappers ---------------- {{{1 @@ -100,6 +105,19 @@ using namespace __asan; // NOLINT DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) +#if !SANITIZER_MAC +#define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \ + common_flags()->verbosity > 0) \ + Report("AddressSanitizer: failed to intercept '" #name "'\n"); \ + } while (0) +#else +// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. +#define ASAN_INTERCEPT_FUNC(name) +#endif // SANITIZER_MAC + +#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) #define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \ do { \ } while (false) @@ -124,16 +142,28 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) do { \ } while (false) #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) +// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name) +// But asan does not remember UserId's for threads (pthread_t); +// and remembers all ever existed threads, so the linear search by UserId +// can be slow. +#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + do { \ + } while (false) #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() #include "sanitizer_common/sanitizer_common_interceptors.inc" #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s) #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s) #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ do { \ + (void)(p); \ + (void)(s); \ } while (false) #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ do { \ + (void)(p); \ + (void)(s); \ } while (false) #include "sanitizer_common/sanitizer_common_syscalls.inc" @@ -144,8 +174,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { } #if ASAN_INTERCEPT_PTHREAD_CREATE -extern "C" int pthread_attr_getdetachstate(void *attr, int *v); - INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { EnsureMainThreadIDIsCorrect(); @@ -155,7 +183,7 @@ INTERCEPTOR(int, pthread_create, void *thread, GET_STACK_TRACE_THREAD; int detached = 0; if (attr != 0) - pthread_attr_getdetachstate(attr, &detached); + REAL(pthread_attr_getdetachstate)(attr, &detached); u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg); @@ -256,7 +284,7 @@ static void MlockIsUnsupported() { static bool printed = false; if (printed) return; printed = true; - if (flags()->verbosity > 0) { + if (common_flags()->verbosity > 0) { Printf("INFO: AddressSanitizer ignores " "mlock/mlockall/munlock/munlockall\n"); } @@ -645,16 +673,6 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, } #endif // ASAN_INTERCEPT___CXA_ATEXIT -#if !SANITIZER_MAC -#define ASAN_INTERCEPT_FUNC(name) do { \ - if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \ - Report("AddressSanitizer: failed to intercept '" #name "'\n"); \ - } while (0) -#else -// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. -#define ASAN_INTERCEPT_FUNC(name) -#endif // SANITIZER_MAC - #if SANITIZER_WINDOWS INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, uptr stack_size, @@ -767,7 +785,7 @@ void InitializeAsanInterceptors() { InitializeWindowsInterceptors(); #endif - if (flags()->verbosity > 0) { + if (common_flags()->verbosity > 0) { Report("AddressSanitizer: libc interceptors initialized\n"); } } diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h index b5b48708090..ede273a7170 100644 --- a/libsanitizer/asan/asan_internal.h +++ b/libsanitizer/asan/asan_internal.h @@ -96,6 +96,7 @@ void StopInitOrderChecking(); void AsanTSDInit(void (*destructor)(void *tsd)); void *AsanTSDGet(); void AsanTSDSet(void *tsd); +void PlatformTSDDtor(void *tsd); void AppendToErrorMessageBuffer(const char *buffer); @@ -133,6 +134,7 @@ const int kAsanStackPartialRedzoneMagic = 0xf4; const int kAsanStackAfterReturnMagic = 0xf5; const int kAsanInitializationOrderMagic = 0xf6; const int kAsanUserPoisonedMemoryMagic = 0xf7; +const int kAsanContiguousContainerOOBMagic = 0xfc; const int kAsanStackUseAfterScopeMagic = 0xf8; const int kAsanGlobalRedzoneMagic = 0xf9; const int kAsanInternalHeapMagic = 0xfe; diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc index 10c6175092b..0692eb1f455 100644 --- a/libsanitizer/asan/asan_linux.cc +++ b/libsanitizer/asan/asan_linux.cc @@ -56,6 +56,12 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.arm_pc; *bp = ucontext->uc_mcontext.arm_fp; *sp = ucontext->uc_mcontext.arm_sp; +# elif defined(__hppa__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.sc_iaoq[0]; + /* GCC uses %r3 whenever a frame pointer is needed. */ + *bp = ucontext->uc_mcontext.sc_gr[3]; + *sp = ucontext->uc_mcontext.sc_gr[30]; # elif defined(__x86_64__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_RIP]; diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc index 4b28c1422cd..8d01843afaf 100644 --- a/libsanitizer/asan/asan_mac.cc +++ b/libsanitizer/asan/asan_mac.cc @@ -172,7 +172,7 @@ void MaybeReexec() { // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); } - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Report("exec()-ing the program with\n"); Report("%s=%s\n", kDyldInsertLibraries, new_env); Report("to enable ASan wrappers.\n"); @@ -309,7 +309,7 @@ extern "C" void asan_dispatch_call_block_and_release(void *block) { GET_STACK_TRACE_THREAD; asan_block_context_t *context = (asan_block_context_t*)block; - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("asan_dispatch_call_block_and_release(): " "context: %p, pthread_self: %p\n", block, pthread_self()); @@ -344,7 +344,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, dispatch_function_t func) { \ GET_STACK_TRACE_THREAD; \ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ - if (flags()->verbosity >= 2) { \ + if (common_flags()->verbosity >= 2) { \ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ asan_ctxt, pthread_self()); \ PRINT_CURRENT_STACK(); \ @@ -362,7 +362,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("dispatch_after_f: %p\n", asan_ctxt); PRINT_CURRENT_STACK(); } @@ -375,7 +375,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", asan_ctxt, pthread_self()); PRINT_CURRENT_STACK(); diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc index 97691fcd361..e3495cb0900 100644 --- a/libsanitizer/asan/asan_malloc_linux.cc +++ b/libsanitizer/asan/asan_malloc_linux.cc @@ -103,8 +103,9 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s) ALIAS("memalign"); INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc_usable_size(ptr, &stack); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(ptr, pc, bp); } // We avoid including malloc.h for portability reasons. diff --git a/libsanitizer/asan/asan_malloc_win.cc b/libsanitizer/asan/asan_malloc_win.cc index cabf8cd254c..1f2495ffc50 100644 --- a/libsanitizer/asan/asan_malloc_win.cc +++ b/libsanitizer/asan/asan_malloc_win.cc @@ -96,8 +96,9 @@ void* _recalloc(void* p, size_t n, size_t elem_size) { SANITIZER_INTERFACE_ATTRIBUTE size_t _msize(void *ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc_usable_size(ptr, &stack); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(ptr, pc, bp); } int _CrtDbgReport(int, const char*, int, diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc index b967acded63..86d49909b68 100644 --- a/libsanitizer/asan/asan_poisoning.cc +++ b/libsanitizer/asan/asan_poisoning.cc @@ -12,6 +12,7 @@ #include "asan_poisoning.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_flags.h" namespace __asan { @@ -66,7 +67,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Printf("Trying to poison memory region [%p, %p)\n", (void*)beg_addr, (void*)end_addr); } @@ -108,7 +109,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Printf("Trying to unpoison memory region [%p, %p)\n", (void*)beg_addr, (void*)end_addr); } @@ -242,13 +243,57 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) { } void __asan_poison_stack_memory(uptr addr, uptr size) { - if (flags()->verbosity > 0) + if (common_flags()->verbosity > 0) Report("poisoning: %p %zx\n", (void*)addr, size); PoisonAlignedStackMemory(addr, size, true); } void __asan_unpoison_stack_memory(uptr addr, uptr size) { - if (flags()->verbosity > 0) + if (common_flags()->verbosity > 0) Report("unpoisoning: %p %zx\n", (void*)addr, size); PoisonAlignedStackMemory(addr, size, false); } + +void __sanitizer_annotate_contiguous_container(const void *beg_p, + const void *end_p, + const void *old_mid_p, + const void *new_mid_p) { + if (common_flags()->verbosity >= 2) + Printf("contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p, + new_mid_p); + uptr beg = reinterpret_cast<uptr>(beg_p); + uptr end= reinterpret_cast<uptr>(end_p); + uptr old_mid = reinterpret_cast<uptr>(old_mid_p); + uptr new_mid = reinterpret_cast<uptr>(new_mid_p); + uptr granularity = SHADOW_GRANULARITY; + CHECK(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end && + IsAligned(beg, granularity)); + CHECK_LE(end - beg, + FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check. + + uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); + uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); + uptr d1 = RoundDownTo(old_mid, granularity); + uptr d2 = RoundUpTo(old_mid, granularity); + // Currently we should be in this state: + // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good. + // Make a quick sanity check that we are indeed in this state. + if (d1 != d2) + CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1); + if (a + granularity <= d1) + CHECK_EQ(*(u8*)MemToShadow(a), 0); + if (d2 + granularity <= c && c <= end) + CHECK_EQ(*(u8 *)MemToShadow(c - granularity), + kAsanContiguousContainerOOBMagic); + + uptr b1 = RoundDownTo(new_mid, granularity); + uptr b2 = RoundUpTo(new_mid, granularity); + // New state: + // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good. + PoisonShadow(a, b1 - a, 0); + PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic); + if (b1 != b2) { + CHECK_EQ(b2 - b1, granularity); + *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1); + } +} diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h index 866c0a57c7e..da79a0ff2e4 100644 --- a/libsanitizer/asan/asan_poisoning.h +++ b/libsanitizer/asan/asan_poisoning.h @@ -41,6 +41,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( uptr aligned_addr, uptr size, uptr redzone_size, u8 value) { DCHECK(flags()->poison_heap); + bool poison_partial = flags()->poison_partial; u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr); for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) { if (i + SHADOW_GRANULARITY <= size) { @@ -49,7 +50,7 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable } else { // first size-i bytes are addressable - *shadow = static_cast<u8>(size - i); + *shadow = poison_partial ? static_cast<u8>(size - i) : 0; } } } diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc index a210a810036..ac4ec9e0191 100644 --- a/libsanitizer/asan/asan_posix.cc +++ b/libsanitizer/asan/asan_posix.cc @@ -1,4 +1,4 @@ -//===-- asan_linux.cc -----------------------------------------------------===// +//===-- asan_posix.cc -----------------------------------------------------===// // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. @@ -42,7 +42,7 @@ static void MaybeInstallSigaction(int signum, sigact.sa_flags = SA_SIGINFO; if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0)); - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Report("Installed the sigaction for signal %d\n", signum); } } @@ -69,7 +69,7 @@ void SetAlternateSignalStack() { altstack.ss_flags = 0; altstack.ss_size = kAltStackSize; CHECK_EQ(0, sigaltstack(&altstack, 0)); - if (flags()->verbosity > 0) { + if (common_flags()->verbosity > 0) { Report("Alternative stack for T%d set: [%p,%p)\n", GetCurrentTidOrInvalid(), altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); @@ -114,6 +114,15 @@ void AsanTSDSet(void *tsd) { pthread_setspecific(tsd_key, tsd); } +void PlatformTSDDtor(void *tsd) { + AsanThreadContext *context = (AsanThreadContext*)tsd; + if (context->destructor_iterations > 1) { + context->destructor_iterations--; + CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); + return; + } + AsanThread::TSDDtor(tsd); +} } // namespace __asan #endif // SANITIZER_LINUX || SANITIZER_MAC diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc index 8f11ff4eac3..70c4b481a2f 100644 --- a/libsanitizer/asan/asan_report.cc +++ b/libsanitizer/asan/asan_report.cc @@ -18,6 +18,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_symbolizer.h" namespace __asan { @@ -71,6 +72,7 @@ class Decorator: private __sanitizer::AnsiColorDecorator { case kAsanInitializationOrderMagic: return Cyan(); case kAsanUserPoisonedMemoryMagic: + case kAsanContiguousContainerOOBMagic: return Blue(); case kAsanStackUseAfterScopeMagic: return Magenta(); @@ -117,19 +119,21 @@ static void PrintLegend() { for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte("", i, " "); Printf("\n"); - PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic); - PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic); - PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic); - PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic); - PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic); - PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic); - PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic); - PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic); - PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic); - PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic); - PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic); - PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic); - PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic); + PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic); + PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic); + PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic); + PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic); + PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic); + PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic); + PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic); + PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic); + PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic); + PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic); + PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic); + PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic); + PrintShadowByte(" Contiguous container OOB:", + kAsanContiguousContainerOOBMagic); + PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic); } static void PrintShadowMemoryForAddress(uptr addr) { @@ -178,8 +182,8 @@ static bool IsASCII(unsigned char c) { static const char *MaybeDemangleGlobalName(const char *name) { // We can spoil names of globals with C linkage, so use an heuristic // approach to check if the name should be demangled. - return (name[0] == '_' && name[1] == 'Z' && &getSymbolizer) - ? getSymbolizer()->Demangle(name) + return (name[0] == '_' && name[1] == 'Z') + ? Symbolizer::Get()->Demangle(name) : name; } @@ -412,7 +416,11 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr, void DescribeHeapAddress(uptr addr, uptr access_size) { AsanChunkView chunk = FindHeapChunkByAddress(addr); - if (!chunk.IsValid()) return; + if (!chunk.IsValid()) { + Printf("AddressSanitizer can not describe address in more detail " + "(wild memory access suspected).\n"); + return; + } DescribeAccessToHeapChunk(chunk, addr, access_size); CHECK(chunk.AllocTid() != kInvalidTid); asanThreadRegistry().CheckLocked(); @@ -479,7 +487,9 @@ void DescribeThread(AsanThreadContext *context) { context->parent_tid, ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); - PrintStack(&context->stack); + uptr stack_size; + const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size); + PrintStack(stack_trace, stack_size); // Recursively described parent thread if needed. if (flags()->print_full_thread_history) { AsanThreadContext *parent_context = @@ -540,22 +550,6 @@ class ScopedInErrorReport { } }; -static void ReportSummary(const char *error_type, StackTrace *stack) { - if (!stack->size) return; - if (&getSymbolizer && getSymbolizer()->IsAvailable()) { - AddressInfo ai; - // Currently, we include the first stack frame into the report summary. - // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). - uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); - getSymbolizer()->SymbolizeCode(pc, &ai, 1); - ReportErrorSummary(error_type, - StripPathPrefix(ai.file, - common_flags()->strip_path_prefix), - ai.line, ai.function); - } - // FIXME: do we need to print anything at all if there is no symbolizer? -} - void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { ScopedInErrorReport in_report; Decorator d; @@ -565,13 +559,13 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { (void*)addr, (void*)pc, (void*)sp, (void*)bp, GetCurrentTidOrInvalid()); Printf("%s", d.EndWarning()); - Printf("AddressSanitizer can not provide additional info.\n"); GET_STACK_TRACE_FATAL(pc, bp); PrintStack(&stack); - ReportSummary("SEGV", &stack); + Printf("AddressSanitizer can not provide additional info.\n"); + ReportErrorSummary("SEGV", &stack); } -void ReportDoubleFree(uptr addr, StackTrace *stack) { +void ReportDoubleFree(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -581,14 +575,15 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) { "thread T%d%s:\n", addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportSummary("double-free", stack); + ReportErrorSummary("double-free", &stack); } -void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { +void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -598,12 +593,14 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { "which was not malloc()-ed: %p in thread T%d%s\n", addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportSummary("bad-free", stack); + ReportErrorSummary("bad-free", &stack); } -void ReportAllocTypeMismatch(uptr addr, StackTrace *stack, +void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type) { static const char *alloc_names[] = @@ -617,9 +614,11 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack, Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n", alloc_names[alloc_type], dealloc_names[dealloc_type], addr); Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportSummary("alloc-dealloc-mismatch", stack); + ReportErrorSummary("alloc-dealloc-mismatch", &stack); Report("HINT: if you don't care about these warnings you may set " "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); } @@ -634,7 +633,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) { Printf("%s", d.EndWarning()); PrintStack(stack); DescribeHeapAddress(addr, 1); - ReportSummary("bad-malloc_usable_size", stack); + ReportErrorSummary("bad-malloc_usable_size", stack); } void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { @@ -647,7 +646,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { Printf("%s", d.EndWarning()); PrintStack(stack); DescribeHeapAddress(addr, 1); - ReportSummary("bad-__asan_get_allocated_size", stack); + ReportErrorSummary("bad-__asan_get_allocated_size", stack); } void ReportStringFunctionMemoryRangesOverlap( @@ -665,7 +664,7 @@ void ReportStringFunctionMemoryRangesOverlap( PrintStack(stack); DescribeAddress((uptr)offset1, length1); DescribeAddress((uptr)offset2, length2); - ReportSummary(bug_type, stack); + ReportErrorSummary(bug_type, stack); } // ----------------------- Mac-specific reports ----------------- {{{1 @@ -747,6 +746,9 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, case kAsanUserPoisonedMemoryMagic: bug_descr = "use-after-poison"; break; + case kAsanContiguousContainerOOBMagic: + bug_descr = "container-overflow"; + break; case kAsanStackUseAfterScopeMagic: bug_descr = "stack-use-after-scope"; break; @@ -775,7 +777,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, PrintStack(&stack); DescribeAddress(addr, access_size); - ReportSummary(bug_descr, &stack); + ReportErrorSummary(bug_descr, &stack); PrintShadowMemoryForAddress(addr); } diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h index afe7673304c..e4c756e557f 100644 --- a/libsanitizer/asan/asan_report.h +++ b/libsanitizer/asan/asan_report.h @@ -31,9 +31,9 @@ void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr); -void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack); -void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack); -void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack, +void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack); +void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack); +void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type); void NORETURN ReportMallocUsableSizeNotOwned(uptr addr, diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index 67327611e84..537d40612aa 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -49,6 +49,8 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } + if (flags()->coverage) + __sanitizer_cov_dump(); if (death_callback) death_callback(); if (flags()->abort_on_error) @@ -86,11 +88,11 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() { } static void ParseFlagsFromString(Flags *f, const char *str) { - ParseCommonFlagsFromString(str); - CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax); + CommonFlags *cf = common_flags(); + ParseCommonFlagsFromString(cf, str); + CHECK((uptr)cf->malloc_context_size <= kStackTraceMax); ParseFlag(str, &f->quarantine_size, "quarantine_size"); - ParseFlag(str, &f->verbosity, "verbosity"); ParseFlag(str, &f->redzone, "redzone"); CHECK_GE(f->redzone, 16); CHECK(IsPowerOfTwo(f->redzone)); @@ -119,32 +121,25 @@ static void ParseFlagsFromString(Flags *f, const char *str) { ParseFlag(str, &f->print_stats, "print_stats"); ParseFlag(str, &f->print_legend, "print_legend"); ParseFlag(str, &f->atexit, "atexit"); + ParseFlag(str, &f->coverage, "coverage"); ParseFlag(str, &f->disable_core, "disable_core"); ParseFlag(str, &f->allow_reexec, "allow_reexec"); ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history"); ParseFlag(str, &f->poison_heap, "poison_heap"); + ParseFlag(str, &f->poison_partial, "poison_partial"); ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch"); - ParseFlag(str, &f->use_stack_depot, "use_stack_depot"); ParseFlag(str, &f->strict_memcmp, "strict_memcmp"); ParseFlag(str, &f->strict_init_order, "strict_init_order"); } void InitializeFlags(Flags *f, const char *env) { CommonFlags *cf = common_flags(); + SetCommonFlagsDefaults(cf); cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); - cf->symbolize = true; cf->malloc_context_size = kDefaultMallocContextSize; - cf->fast_unwind_on_fatal = false; - cf->fast_unwind_on_malloc = true; - cf->strip_path_prefix = ""; - cf->handle_ioctl = false; - cf->log_path = 0; - cf->detect_leaks = false; - cf->leak_check_at_exit = true; internal_memset(f, 0, sizeof(*f)); f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28; - f->verbosity = 0; f->redzone = 16; f->debug = false; f->report_globals = 1; @@ -168,14 +163,15 @@ void InitializeFlags(Flags *f, const char *env) { f->print_stats = false; f->print_legend = true; f->atexit = false; + f->coverage = false; f->disable_core = (SANITIZER_WORDSIZE == 64); f->allow_reexec = true; f->print_full_thread_history = true; f->poison_heap = true; + f->poison_partial = true; // Turn off alloc/dealloc mismatch checker on Mac and Windows for now. // TODO(glider,timurrrr): Fix known issues and enable this back. f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0); - f->use_stack_depot = true; f->strict_memcmp = true; f->strict_init_order = false; @@ -184,7 +180,7 @@ void InitializeFlags(Flags *f, const char *env) { // Override from user-specified string. ParseFlagsFromString(f, MaybeCallAsanDefaultOptions()); - if (flags()->verbosity) { + if (cf->verbosity) { Report("Using the defaults from __asan_default_options: %s\n", MaybeCallAsanDefaultOptions()); } @@ -200,10 +196,10 @@ void InitializeFlags(Flags *f, const char *env) { } #endif - if (cf->detect_leaks && !f->use_stack_depot) { - Report("%s: detect_leaks is ignored (requires use_stack_depot).\n", - SanitizerToolName); - cf->detect_leaks = false; + // Make "strict_init_order" imply "check_initialization_order". + // TODO(samsonov): Use a single runtime flag for an init-order checker. + if (f->strict_init_order) { + f->check_initialization_order = true; } } @@ -462,7 +458,7 @@ void __asan_init() { __asan_option_detect_stack_use_after_return = flags()->detect_stack_use_after_return; - if (flags()->verbosity && options) { + if (common_flags()->verbosity && options) { Report("Parsed ASAN_OPTIONS: %s\n", options); } @@ -472,11 +468,6 @@ void __asan_init() { // Setup internal allocator callback. SetLowLevelAllocateCallback(OnLowLevelAllocate); - if (flags()->atexit) { - Atexit(asan_atexit); - } - - // interceptors InitializeAsanInterceptors(); ReplaceSystemMalloc(); @@ -495,7 +486,7 @@ void __asan_init() { } #endif - if (flags()->verbosity) + if (common_flags()->verbosity) PrintAddressSpaceLayout(); if (flags()->disable_core) { @@ -531,17 +522,18 @@ void __asan_init() { Die(); } + AsanTSDInit(PlatformTSDDtor); InstallSignalHandlers(); - AsanTSDInit(AsanThread::TSDDtor); // Allocator should be initialized before starting external symbolizer, as // fork() on Mac locks the allocator. InitializeAllocator(); // Start symbolizer process if necessary. - if (common_flags()->symbolize && &getSymbolizer) { - getSymbolizer() - ->InitializeExternal(common_flags()->external_symbolizer_path); + if (common_flags()->symbolize) { + Symbolizer::Init(common_flags()->external_symbolizer_path); + } else { + Symbolizer::Disable(); } // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited @@ -549,6 +541,13 @@ void __asan_init() { asan_inited = 1; asan_init_is_running = false; + if (flags()->atexit) + Atexit(asan_atexit); + + if (flags()->coverage) + Atexit(__sanitizer_cov_dump); + + // interceptors InitTlsSize(); // Create main thread. @@ -568,7 +567,7 @@ void __asan_init() { } #endif // CAN_SANITIZE_LEAKS - if (flags()->verbosity) { + if (common_flags()->verbosity) { Report("AddressSanitizer Init done\n"); } } diff --git a/libsanitizer/asan/asan_stack.cc b/libsanitizer/asan/asan_stack.cc index 74952518642..93671a03a92 100644 --- a/libsanitizer/asan/asan_stack.cc +++ b/libsanitizer/asan/asan_stack.cc @@ -22,9 +22,12 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer, : false; } +void PrintStack(const uptr *trace, uptr size) { + StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize); +} + void PrintStack(StackTrace *stack) { - stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize, - common_flags()->strip_path_prefix, MaybeCallAsanSymbolize); + PrintStack(stack->trace, stack->size); } } // namespace __asan diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h index 3c0ac31f6c6..c929c887d06 100644 --- a/libsanitizer/asan/asan_stack.h +++ b/libsanitizer/asan/asan_stack.h @@ -20,6 +20,7 @@ namespace __asan { void PrintStack(StackTrace *stack); +void PrintStack(const uptr *trace, uptr size); } // namespace __asan @@ -29,19 +30,24 @@ void PrintStack(StackTrace *stack); #if SANITIZER_WINDOWS #define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ StackTrace stack; \ - GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast) + stack.Unwind(max_s, pc, bp, 0, 0, fast) #else -#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ - StackTrace stack; \ - { \ - AsanThread *t; \ - stack.size = 0; \ - if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \ - uptr stack_top = t->stack_top(); \ - uptr stack_bottom = t->stack_bottom(); \ - ScopedUnwinding unwind_scope(t); \ - GetStackTrace(&stack, max_s, pc, bp, stack_top, stack_bottom, fast); \ - } \ +#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ + StackTrace stack; \ + { \ + AsanThread *t; \ + stack.size = 0; \ + if (asan_inited) { \ + if ((t = GetCurrentThread()) && !t->isUnwinding()) { \ + uptr stack_top = t->stack_top(); \ + uptr stack_bottom = t->stack_bottom(); \ + ScopedUnwinding unwind_scope(t); \ + stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \ + } else if (t == 0 && !fast) { \ + /* If GetCurrentThread() has failed, try to do slow unwind anyways. */ \ + stack.Unwind(max_s, pc, bp, 0, 0, false); \ + } \ + } \ } #endif // SANITIZER_WINDOWS diff --git a/libsanitizer/asan/asan_stats.h b/libsanitizer/asan/asan_stats.h index 2f964f8d052..5b04b1718eb 100644 --- a/libsanitizer/asan/asan_stats.h +++ b/libsanitizer/asan/asan_stats.h @@ -45,9 +45,9 @@ struct AsanStats { uptr malloc_large; uptr malloc_small_slow; - // Ctor for global AsanStats (accumulated stats and main thread stats). + // Ctor for global AsanStats (accumulated stats for dead threads). explicit AsanStats(LinkerInitialized) { } - // Default ctor for thread-local stats. + // Creates empty stats. AsanStats(); void Print(); // Prints formatted stats to stderr. diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc index 1da714c6013..5a9c2dddffb 100644 --- a/libsanitizer/asan/asan_thread.cc +++ b/libsanitizer/asan/asan_thread.cc @@ -17,6 +17,7 @@ #include "asan_mapping.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "lsan/lsan_common.h" namespace __asan { @@ -25,9 +26,8 @@ namespace __asan { void AsanThreadContext::OnCreated(void *arg) { CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg); - if (args->stack) { - internal_memcpy(&stack, args->stack, sizeof(stack)); - } + if (args->stack) + stack_id = StackDepotPut(args->stack->trace, args->stack->size); thread = args->thread; thread->set_context(this); } @@ -41,9 +41,12 @@ void AsanThreadContext::OnFinished() { static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadRegistry *asan_thread_registry; +static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED); +static LowLevelAllocator allocator_for_thread_context; + static ThreadContextBase *GetAsanThreadContext(u32 tid) { - void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext"); - return new(mem) AsanThreadContext(tid); + BlockingMutexLock lock(&mu_for_thread_context); + return new(allocator_for_thread_context) AsanThreadContext(tid); } ThreadRegistry &asanThreadRegistry() { @@ -76,24 +79,25 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__); thread->start_routine_ = start_routine; thread->arg_ = arg; - thread->context_ = 0; return thread; } void AsanThread::TSDDtor(void *tsd) { AsanThreadContext *context = (AsanThreadContext*)tsd; - if (flags()->verbosity >= 1) + if (common_flags()->verbosity >= 1) Report("T%d TSDDtor\n", context->tid); if (context->thread) context->thread->Destroy(); } void AsanThread::Destroy() { - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Report("T%d exited\n", tid()); } + malloc_storage().CommitBack(); + if (flags()->use_sigaltstack) UnsetAlternateSignalStack(); asanThreadRegistry().FinishThread(tid()); FlushToDeadThreadStats(&stats_); // We also clear the shadow on thread destruction because @@ -136,7 +140,7 @@ void AsanThread::Init() { CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); ClearShadowForThreadStackAndTLS(); - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { int local = 0; Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void*)stack_bottom_, (void*)stack_top_, @@ -160,10 +164,14 @@ thread_return_t AsanThread::ThreadStart(uptr os_id) { } thread_return_t res = start_routine_(arg_); - malloc_storage().CommitBack(); - if (flags()->use_sigaltstack) UnsetAlternateSignalStack(); - this->Destroy(); + // On POSIX systems we defer this to the TSD destructor. LSan will consider + // the thread's memory as non-live from the moment we call Destroy(), even + // though that memory might contain pointers to heap objects which will be + // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before + // the TSD destructors have run might cause false positives in LSan. + if (!SANITIZER_POSIX) + this->Destroy(); return res; } @@ -257,7 +265,7 @@ AsanThread *GetCurrentThread() { void SetCurrentThread(AsanThread *t) { CHECK(t->context()); - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("SetCurrentThread: %p for thread %p\n", t->context(), (void*)GetThreadSelf()); } @@ -286,6 +294,13 @@ void EnsureMainThreadIDIsCorrect() { if (context && (context->tid == 0)) context->os_id = GetTid(); } + +__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { + __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( + __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); + if (!context) return 0; + return context->thread; +} } // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 @@ -293,10 +308,7 @@ namespace __lsan { bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end) { - __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( - __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); - if (!context) return false; - __asan::AsanThread *t = context->thread; + __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); if (!t) return false; *stack_begin = t->stack_bottom(); *stack_end = t->stack_top(); @@ -308,6 +320,13 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, return true; } +void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, + void *arg) { + __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); + if (t && t->has_fake_stack()) + t->fake_stack()->ForEachFakeFrame(callback, arg); +} + void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); } diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h index f21971ff430..5a917fa9a3d 100644 --- a/libsanitizer/asan/asan_thread.h +++ b/libsanitizer/asan/asan_thread.h @@ -17,6 +17,7 @@ #include "asan_fake_stack.h" #include "asan_stack.h" #include "asan_stats.h" +#include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_thread_registry.h" @@ -34,11 +35,13 @@ class AsanThreadContext : public ThreadContextBase { explicit AsanThreadContext(int tid) : ThreadContextBase(tid), announced(false), + destructor_iterations(kPthreadDestructorIterations), + stack_id(0), thread(0) { - internal_memset(&stack, 0, sizeof(stack)); } bool announced; - StackTrace stack; + u8 destructor_iterations; + u32 stack_id; AsanThread *thread; void OnCreated(void *arg); @@ -46,7 +49,7 @@ class AsanThreadContext : public ThreadContextBase { }; // AsanThreadContext objects are never freed, so we need many of them. -COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096); +COMPILER_CHECK(sizeof(AsanThreadContext) <= 256); // AsanThread are stored in TSD and destroyed when the thread dies. class AsanThread { @@ -96,14 +99,15 @@ class AsanThread { // True is this thread is currently unwinding stack (i.e. collecting a stack // trace). Used to prevent deadlocks on platforms where libc unwinder calls // malloc internally. See PR17116 for more details. - bool isUnwinding() const { return unwinding; } - void setUnwinding(bool b) { unwinding = b; } + bool isUnwinding() const { return unwinding_; } + void setUnwinding(bool b) { unwinding_ = b; } AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanStats &stats() { return stats_; } private: - AsanThread() : unwinding(false) {} + // NOTE: There is no AsanThread constructor. It is allocated + // via mmap() and *must* be valid in zero-initialized state. void SetThreadStackAndTls(); void ClearShadowForThreadStackAndTLS(); FakeStack *AsyncSignalSafeLazyInitFakeStack(); @@ -111,18 +115,18 @@ class AsanThread { AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; - uptr stack_top_; - uptr stack_bottom_; + uptr stack_top_; + uptr stack_bottom_; // stack_size_ == stack_top_ - stack_bottom_; // It needs to be set in a async-signal-safe manner. - uptr stack_size_; + uptr stack_size_; uptr tls_begin_; uptr tls_end_; FakeStack *fake_stack_; AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; - bool unwinding; + bool unwinding_; }; // ScopedUnwinding is a scope for stacktracing member of a context diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc index ed785b69281..8ffa58faa37 100644 --- a/libsanitizer/asan/asan_win.cc +++ b/libsanitizer/asan/asan_win.cc @@ -58,6 +58,9 @@ void AsanTSDSet(void *tsd) { fake_tsd = tsd; } +void PlatformTSDDtor(void *tsd) { + AsanThread::TSDDtor(tsd); +} // ---------------------- Various stuff ---------------- {{{1 void MaybeReexec() { // No need to re-exec on Windows. |