Path: blob/main/contrib/llvm-project/compiler-rt/lib/nsan/nsan_thread.cpp
213766 views
//===- nsan_threads.cpp ---------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// Thread management.8//===----------------------------------------------------------------------===//910#include "nsan_thread.h"1112#include <pthread.h>1314#include "nsan.h"15#include "sanitizer_common/sanitizer_tls_get_addr.h"1617using namespace __nsan;1819NsanThread *NsanThread::Create(thread_callback_t start_routine, void *arg) {20uptr PageSize = GetPageSizeCached();21uptr size = RoundUpTo(sizeof(NsanThread), PageSize);22NsanThread *thread = (NsanThread *)MmapOrDie(size, __func__);23thread->start_routine_ = start_routine;24thread->arg_ = arg;25thread->destructor_iterations_ = GetPthreadDestructorIterations();2627return thread;28}2930void NsanThread::SetThreadStackAndTls() {31GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_.top, &tls_begin_,32&tls_end_);33int local;34CHECK(AddrIsInStack((uptr)&local));35}3637void NsanThread::ClearShadowForThreadStackAndTLS() {38__nsan_set_value_unknown((const u8 *)stack_.bottom,39stack_.top - stack_.bottom);40if (tls_begin_ != tls_end_)41__nsan_set_value_unknown((const u8 *)tls_begin_, tls_end_ - tls_begin_);42DTLS *dtls = DTLS_Get();43CHECK_NE(dtls, 0);44ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) {45__nsan_set_value_unknown((const u8 *)dtv.beg, dtv.size);46});47}4849void NsanThread::Init() {50SetThreadStackAndTls();51ClearShadowForThreadStackAndTLS();52malloc_storage().Init();53}5455void NsanThread::TSDDtor(void *tsd) {56NsanThread *t = (NsanThread *)tsd;57t->Destroy();58}5960void NsanThread::Destroy() {61malloc_storage().CommitBack();62// We also clear the shadow on thread destruction because63// some code may still be executing in later TSD destructors64// and we don't want it to have any poisoned stack.65ClearShadowForThreadStackAndTLS();66uptr size = RoundUpTo(sizeof(NsanThread), GetPageSizeCached());67UnmapOrDie(this, size);68DTLS_Destroy();69}7071thread_return_t NsanThread::ThreadStart() {72if (!start_routine_) {73// start_routine_ == 0 if we're on the main thread or on one of the74// OS X libdispatch worker threads. But nobody is supposed to call75// ThreadStart() for the worker threads.76return 0;77}7879return start_routine_(arg_);80}8182NsanThread::StackBounds NsanThread::GetStackBounds() const {83if (!stack_switching_)84return {stack_.bottom, stack_.top};85const uptr cur_stack = GET_CURRENT_FRAME();86// Note: need to check next stack first, because FinishSwitchFiber87// may be in process of overwriting stack_.top/bottom_. But in such case88// we are already on the next stack.89if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top)90return {next_stack_.bottom, next_stack_.top};91return {stack_.bottom, stack_.top};92}9394uptr NsanThread::stack_top() { return GetStackBounds().top; }9596uptr NsanThread::stack_bottom() { return GetStackBounds().bottom; }9798bool NsanThread::AddrIsInStack(uptr addr) {99const auto bounds = GetStackBounds();100return addr >= bounds.bottom && addr < bounds.top;101}102103void NsanThread::StartSwitchFiber(uptr bottom, uptr size) {104CHECK(!stack_switching_);105next_stack_.bottom = bottom;106next_stack_.top = bottom + size;107stack_switching_ = true;108}109110void NsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) {111CHECK(stack_switching_);112if (bottom_old)113*bottom_old = stack_.bottom;114if (size_old)115*size_old = stack_.top - stack_.bottom;116stack_.bottom = next_stack_.bottom;117stack_.top = next_stack_.top;118stack_switching_ = false;119next_stack_.top = 0;120next_stack_.bottom = 0;121}122123static pthread_key_t tsd_key;124static bool tsd_key_inited;125126void __nsan::NsanTSDInit(void (*destructor)(void *tsd)) {127CHECK(!tsd_key_inited);128tsd_key_inited = true;129CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));130}131132static THREADLOCAL NsanThread *nsan_current_thread;133134NsanThread *__nsan::GetCurrentThread() { return nsan_current_thread; }135136void __nsan::SetCurrentThread(NsanThread *t) {137// Make sure we do not reset the current NsanThread.138CHECK_EQ(0, nsan_current_thread);139nsan_current_thread = t;140// Make sure that NsanTSDDtor gets called at the end.141CHECK(tsd_key_inited);142pthread_setspecific(tsd_key, t);143}144145void __nsan::NsanTSDDtor(void *tsd) {146NsanThread *t = (NsanThread *)tsd;147if (t->destructor_iterations_ > 1) {148t->destructor_iterations_--;149CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));150return;151}152nsan_current_thread = nullptr;153// Make sure that signal handler can not see a stale current thread pointer.154atomic_signal_fence(memory_order_seq_cst);155NsanThread::TSDDtor(tsd);156}157158159