Index: lib/asan/CMakeLists.txt =================================================================== --- lib/asan/CMakeLists.txt +++ lib/asan/CMakeLists.txt @@ -8,6 +8,7 @@ asan_errors.cc asan_fake_stack.cc asan_flags.cc + asan_fuchsia.cc asan_globals.cc asan_globals_win.cc asan_interceptors.cc Index: lib/asan/asan_allocator.h =================================================================== --- lib/asan/asan_allocator.h +++ lib/asan/asan_allocator.h @@ -119,7 +119,11 @@ }; #if SANITIZER_CAN_USE_ALLOCATOR64 -# if defined(__powerpc64__) +# if SANITIZER_FUCHSIA +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +typedef DefaultSizeClassMap SizeClassMap; +# elif defined(__powerpc64__) const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. typedef DefaultSizeClassMap SizeClassMap; Index: lib/asan/asan_errors.cc =================================================================== --- lib/asan/asan_errors.cc +++ lib/asan/asan_errors.cc @@ -70,6 +70,9 @@ } void ErrorDeadlySignal::Print() { +#if SANITIZER_FUCHSIA + UNIMPLEMENTED(); +#else Decorator d; Printf("%s", d.Warning()); const char *description = __sanitizer::DescribeSignalOrException(signo); @@ -98,6 +101,7 @@ MaybeDumpRegisters(context); Printf("AddressSanitizer can not provide additional info.\n"); ReportErrorSummary(description, &stack); +#endif } void ErrorDoubleFree::Print() { Index: lib/asan/asan_fake_stack.cc =================================================================== --- lib/asan/asan_fake_stack.cc +++ lib/asan/asan_fake_stack.cc @@ -171,7 +171,7 @@ } } -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA static THREADLOCAL FakeStack *fake_stack_tls; FakeStack *GetTLSFakeStack() { @@ -183,7 +183,7 @@ #else FakeStack *GetTLSFakeStack() { return 0; } void SetTLSFakeStack(FakeStack *fs) { } -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA static FakeStack *GetFakeStack() { AsanThread *t = GetCurrentThread(); Index: lib/asan/asan_fuchsia.cc =================================================================== --- /dev/null +++ lib/asan/asan_fuchsia.cc @@ -0,0 +1,209 @@ +//===-- asan_fuchsia.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. +// +// Fuchsia-specific details. +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_fuchsia.h" +#if SANITIZER_FUCHSIA + +#include "asan_interceptors.h" +#include "asan_internal.h" +#include "asan_stack.h" +#include "asan_thread.h" + +#include +#include +#include +#include + +namespace __asan { + +// The system already set up the shadow memory for us. +// __sanitizer::GetMaxVirtualAddress has already been called by +// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc). +// Just do some additional sanity checks here. +void InitializeShadowMemory() { + if (Verbosity()) PrintAddressSpaceLayout(); + + // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address. + __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; + DCHECK(kLowShadowBeg != kDefaultShadowSentinel); + __asan_shadow_memory_dynamic_address = kLowShadowBeg; + + CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); + CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1); + CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit); + CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base); + CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1); + CHECK_EQ(kLowShadowEnd, 0); + CHECK_EQ(kLowShadowBeg, 0); +} + +void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { + UNIMPLEMENTED(); +} + +void AsanCheckDynamicRTPrereqs() {} +void AsanCheckIncompatibleRT() {} +void InitializeAsanInterceptors() {} + +void *AsanDoesNotSupportStaticLinkage() { + return nullptr; +} + +void InitializePlatformExceptionHandlers() {} +void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { + UNIMPLEMENTED(); +} + +// 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__); +} + +static inline size_t AsanThreadMmapSize() { + return RoundUpTo(sizeof(AsanThread), PAGE_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, + const char *name, + uptr stack_bottom, uptr stack_size) { + // In lieu of AsanThread::Create. + AsanThread *thread = + (AsanThread*)MmapOrDie(AsanThreadMmapSize(), __func__); + + AsanThreadContext::CreateThreadContextArgs args = { thread, stack }; + u32 tid = asanThreadRegistry().CreateThread(user_id, detached, + parent_tid, &args); + asanThreadRegistry().SetThreadName(tid, name); + + // On other systems, AsanThread::Init() is called from the new + // thread itself. But on Fuchsia we already know the stack address + // range beforehand, so we can do most of the setup right now. + thread->Init(stack_bottom, stack_size); + + return thread; +} + +// Called by __asan::AsanInitInternal (asan_rtl.c). +AsanThread *CreateMainThread() { + thrd_t self = thrd_current(); + char name[MX_MAX_NAME_LEN]; + CHECK_NE(__sanitizer::MainThreadStackBase, 0); + CHECK_GT(__sanitizer::MainThreadStackSize, 0); + AsanThread *t = CreateAsanThread( + nullptr, 0, reinterpret_cast(self), true, + _mx_object_get_property(thrd_get_mx_handle(self), MX_PROP_NAME, + name, sizeof(name)) == MX_OK ? name : nullptr, + __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize); + SetCurrentThread(t); + return t; +} + +// 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, + const char *name, + uptr stack_bottom, uptr stack_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, name, stack_bottom, stack_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(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(), true); + UnmapOrDie(thread, AsanThreadMmapSize()); + } +} + +// This is called in the newly-created thread before it runs anything else, +// with the pointer returned by BeforeThreadCreateHook (above). +// cf. asan_interceptors.cc:asan_thread_start +static void ThreadStartHook(void *hook, uptr os_id) { + AsanThread *thread = static_cast(hook); + SetCurrentThread(thread); + + // In lieu of AsanThread::ThreadStart. + asanThreadRegistry().StartThread(thread->tid(), + os_id, /*workerthread*/ false, + nullptr); +} + +// 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::TSDDtor(per_thread); +} + +} // namespace __asan + +// These are declared (in extern "C") by . +// The system runtime will call our definitions directly. + +void *__sanitizer_before_thread_create_hook( + thrd_t thread, bool detached, const char* name, + void* stack_base, size_t stack_size) { + return __asan::BeforeThreadCreateHook(reinterpret_cast(thread), + detached, name, + reinterpret_cast(stack_base), + stack_size); +} + +void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { + __asan::ThreadCreateHook(hook, error != thrd_success); +} + +void __sanitizer_thread_start_hook(void* hook, thrd_t self) { + __asan::ThreadStartHook(hook, reinterpret_cast(self)); +} + +void __sanitizer_thread_exit_hook(void* hook, thrd_t self) { + __asan::ThreadExitHook(hook, reinterpret_cast(self)); +} + +#endif // SANITIZER_FUCHSIA Index: lib/asan/asan_interceptors.h =================================================================== --- lib/asan/asan_interceptors.h +++ lib/asan/asan_interceptors.h @@ -19,6 +19,8 @@ #include "interception/interception.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" +#if !SANITIZER_FUCHSIA + // Use macro to describe if specific function should be // intercepted on a given platform. #if !SANITIZER_WINDOWS @@ -112,6 +114,8 @@ #define ASAN_INTERCEPT_FUNC(name) #endif // SANITIZER_MAC +#endif // !SANITIZER_FUCHSIA + namespace __asan { void InitializeAsanInterceptors(); Index: lib/asan/asan_interceptors.cc =================================================================== --- lib/asan/asan_interceptors.cc +++ lib/asan/asan_interceptors.cc @@ -24,6 +24,8 @@ #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" +#if !SANITIZER_FUCHSIA + #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" #endif @@ -654,3 +656,5 @@ } } // namespace __asan + +#endif // !SANITIZER_FUCHSIA Index: lib/asan/asan_interceptors_memintrinsics.cc =================================================================== --- lib/asan/asan_interceptors_memintrinsics.cc +++ lib/asan/asan_interceptors_memintrinsics.cc @@ -30,3 +30,15 @@ void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } + +#if SANITIZER_FUCHSIA + +// 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. + +decltype(memcpy) memcpy [[gnu::alias("__asan_memcpy")]]; +decltype(memmove) memmove [[gnu::alias("__asan_memmove")]]; +decltype(memset) memset [[gnu::alias("__asan_memset")]]; + +#endif // SANITIZER_FUCHSIA Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -69,6 +69,7 @@ bool IsSystemHeapAddress(uptr addr); // asan_rtl.cc +AsanThread *CreateMainThread(); void PrintAddressSpaceLayout(); void NORETURN ShowStatsAndAbort(); Index: lib/asan/asan_malloc_linux.cc =================================================================== --- lib/asan/asan_malloc_linux.cc +++ lib/asan/asan_malloc_linux.cc @@ -15,7 +15,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "asan_allocator.h" @@ -26,6 +26,8 @@ // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT +#if !SANITIZER_FUCHSIA + static uptr allocated_for_dlsym; static const uptr kDlsymAllocPoolSize = 1024; static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; @@ -43,6 +45,47 @@ return mem; } +static bool MaybeInDlsym() { + return UNLIKELY(asan_init_is_running); +} + +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())) { + new_ptr = AllocateFromLocalPool(size); + } else { + ENSURE_ASAN_INITED(); + GET_STACK_TRACE_MALLOC; + new_ptr = asan_malloc(size, &stack); + } + internal_memcpy(new_ptr, ptr, copy_size); + return new_ptr; +} + +#else // SANITIZER_FUCHSIA + +// Fuchsia doesn't use dlsym-based interceptors. + +static bool IsInDlsymAllocPool(const void *) { + return false; +} + +static bool MaybeInDlsym() { + return false; +} + +// These will never be called. +static void *AllocateFromLocalPool(uptr) { + __builtin_trap(); +} +static void *ReallocFromLocalPool(void *, uptr) { + __builtin_trap(); +} + +#endif // !SANITIZER_FUCHSIA + INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; if (UNLIKELY(IsInDlsymAllocPool(ptr))) @@ -60,7 +103,7 @@ #endif // SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void*, malloc, uptr size) { - if (UNLIKELY(asan_init_is_running)) + if (UNLIKELY(MaybeInDlsym())) // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. return AllocateFromLocalPool(size); ENSURE_ASAN_INITED(); @@ -69,7 +112,7 @@ } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { - if (UNLIKELY(asan_init_is_running)) + if (UNLIKELY(MaybeInDlsym())) // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. return AllocateFromLocalPool(nmemb * size); ENSURE_ASAN_INITED(); @@ -78,21 +121,9 @@ } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { - if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr; - if (UNLIKELY(asan_init_is_running)) { - new_ptr = AllocateFromLocalPool(size); - } else { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - new_ptr = asan_malloc(size, &stack); - } - internal_memcpy(new_ptr, ptr, copy_size); - return new_ptr; - } - if (UNLIKELY(asan_init_is_running)) + if (UNLIKELY(IsInDlsymAllocPool(ptr))) + return ReallocFromLocalPool(ptr, size); + if (UNLIKELY(MaybeInDlsym())) return AllocateFromLocalPool(size); ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; @@ -226,4 +257,4 @@ } // namespace __asan #endif // SANITIZER_ANDROID -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX Index: lib/asan/asan_mapping.h =================================================================== --- lib/asan/asan_mapping.h +++ lib/asan/asan_mapping.h @@ -145,7 +145,9 @@ #define SHADOW_SCALE kDefaultShadowScale -#if SANITIZER_WORDSIZE == 32 +#if SANITIZER_FUCHSIA +# define SHADOW_OFFSET (0) +#elif SANITIZER_WORDSIZE == 32 # if SANITIZER_ANDROID # define SHADOW_OFFSET (0) # elif defined(__mips__) Index: lib/asan/asan_poisoning.h =================================================================== --- lib/asan/asan_poisoning.h +++ lib/asan/asan_poisoning.h @@ -48,6 +48,10 @@ // For now, just memset on Windows. if (value || SANITIZER_WINDOWS == 1 || + // TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be + // 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 || shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { Index: lib/asan/asan_report.cc =================================================================== --- lib/asan/asan_report.cc +++ lib/asan/asan_report.cc @@ -267,11 +267,13 @@ in_report.ReportError(error); } +#if !SANITIZER_FUCHSIA void ReportDeadlySignal(int signo, const SignalContext &sig) { ScopedInErrorReport in_report(/*fatal*/ true); ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo); in_report.ReportError(error); } +#endif // !SANITIZER_FUCHSIA void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) { ScopedInErrorReport in_report; Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -367,6 +367,18 @@ kHighShadowBeg > kMidMemEnd); } +#if !SANITIZER_FUCHSIA +AsanThread *CreateMainThread() { + AsanThread *main_thread = AsanThread::Create( + /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, + /* stack */ nullptr, /* detached */ true); + SetCurrentThread(main_thread); + main_thread->ThreadStart(internal_getpid(), + /* signal_thread_is_registered */ nullptr); + return main_thread; +} +#endif + static void AsanInitInternal() { if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; @@ -451,13 +463,8 @@ InitTlsSize(); // Create main thread. - AsanThread *main_thread = AsanThread::Create( - /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0, - /* stack */ nullptr, /* detached */ true); + AsanThread *main_thread = CreateMainThread(); CHECK_EQ(0, main_thread->tid()); - SetCurrentThread(main_thread); - main_thread->ThreadStart(internal_getpid(), - /* signal_thread_is_registered */ nullptr); force_interface_symbols(); // no-op. SanitizerInitializeUnwinder(); @@ -523,6 +530,7 @@ top = curr_thread->stack_top(); bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1); } else { + CHECK(!SANITIZER_FUCHSIA); // If we haven't seen this thread, try asking the OS for stack bounds. uptr tls_addr, tls_size, stack_size; GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr, Index: lib/asan/asan_thread.h =================================================================== --- lib/asan/asan_thread.h +++ lib/asan/asan_thread.h @@ -49,6 +49,11 @@ void OnCreated(void *arg) override; void OnFinished() override; + + struct CreateThreadContextArgs { + AsanThread *thread; + StackTrace *stack; + }; }; // AsanThreadContext objects are never freed, so we need many of them. @@ -62,7 +67,10 @@ static void TSDDtor(void *tsd); void Destroy(); - void Init(); // Should be called from the thread itself. + // Should be called from the thread itself when called with default zeros. + // On Fuchsia, this is called from the creator thread instead, and gets + // nonzero arguments (and ThreadStart is not used). + void Init(uptr stack_bottom = 0, uptr stack_size = 0); thread_return_t ThreadStart(tid_t os_id, atomic_uintptr_t *signal_thread_is_registered); Index: lib/asan/asan_thread.cc =================================================================== --- lib/asan/asan_thread.cc +++ lib/asan/asan_thread.cc @@ -27,11 +27,6 @@ // AsanThreadContext implementation. -struct CreateThreadContextArgs { - AsanThread *thread; - StackTrace *stack; -}; - void AsanThreadContext::OnCreated(void *arg) { CreateThreadContextArgs *args = static_cast(arg); if (args->stack) @@ -88,7 +83,7 @@ AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__); thread->start_routine_ = start_routine; thread->arg_ = arg; - CreateThreadContextArgs args = { thread, stack }; + AsanThreadContext::CreateThreadContextArgs args = { thread, stack }; asanThreadRegistry().CreateThread(*reinterpret_cast(thread), detached, parent_tid, &args); @@ -223,12 +218,25 @@ return nullptr; } -void AsanThread::Init() { +void AsanThread::Init(uptr init_stack_bottom, uptr init_stack_size) { 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(); + if (init_stack_bottom == 0) { + CHECK(!SANITIZER_FUCHSIA); + SetThreadStackAndTls(); + } else { + // On Fuchsia, Init() is called in the creator thread before the new + // thread is actually started, but its stack address range is already + // known. We don't bother tracking the static TLS address range + // because the system itself uses an ASan-aware allocator for that. + CHECK(SANITIZER_FUCHSIA); + DCHECK_NE(GetCurrentThread(), this); + DCHECK_NE(GetCurrentThread(), nullptr); + stack_bottom_ = init_stack_bottom; + stack_top_ = init_stack_bottom + init_stack_size; + } CHECK_GT(this->stack_size(), 0U); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); @@ -270,6 +278,9 @@ return res; } +// On Fuchsia, Init() is called by the creator thread after the +// stack bounds have already been stored. +#if !SANITIZER_FUCHSIA void AsanThread::SetThreadStackAndTls() { uptr tls_size = 0; uptr stack_size = 0; @@ -282,6 +293,7 @@ int local; CHECK(AddrIsInStack((uptr)&local)); } +#endif // !SANITIZER_FUCHSIA void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); Index: lib/sanitizer_common/sanitizer_thread_registry.h =================================================================== --- lib/sanitizer_common/sanitizer_thread_registry.h +++ lib/sanitizer_common/sanitizer_thread_registry.h @@ -115,7 +115,7 @@ void SetThreadNameByUserId(uptr user_id, const char *name); void DetachThread(u32 tid, void *arg); void JoinThread(u32 tid, void *arg); - void FinishThread(u32 tid); + void FinishThread(u32 tid, bool aborted = false); void StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg); private: Index: lib/sanitizer_common/sanitizer_thread_registry.cc =================================================================== --- lib/sanitizer_common/sanitizer_thread_registry.cc +++ lib/sanitizer_common/sanitizer_thread_registry.cc @@ -204,7 +204,8 @@ CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); - CHECK_EQ(ThreadStatusRunning, tctx->status); + CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning, + tctx->status); tctx->SetName(name); } @@ -251,18 +252,26 @@ QuarantinePush(tctx); } -void ThreadRegistry::FinishThread(u32 tid) { +void ThreadRegistry::FinishThread(u32 tid, bool aborted) { BlockingMutexLock l(&mtx_); CHECK_GT(alive_threads_, 0); alive_threads_--; - CHECK_GT(running_threads_, 0); - running_threads_--; + if (!aborted) { + CHECK_GT(running_threads_, 0); + running_threads_--; + } CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; CHECK_NE(tctx, 0); - CHECK_EQ(ThreadStatusRunning, tctx->status); + if (aborted) { + // The thread never really existed. + CHECK_EQ(ThreadStatusCreated, tctx->status); + tctx->detached = false; + } else { + CHECK_EQ(ThreadStatusRunning, tctx->status); + } tctx->SetFinished(); - if (tctx->detached) { + if (aborted || tctx->detached) { tctx->SetDead(); QuarantinePush(tctx); }