brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · 6662c9b Raw
158 lines · cpp
1//===- nsan_threads.cpp ---------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8// Thread management.9//===----------------------------------------------------------------------===//10 11#include "nsan_thread.h"12 13#include <pthread.h>14 15#include "nsan.h"16#include "sanitizer_common/sanitizer_tls_get_addr.h"17 18using namespace __nsan;19 20NsanThread *NsanThread::Create(thread_callback_t start_routine, void *arg) {21  uptr PageSize = GetPageSizeCached();22  uptr size = RoundUpTo(sizeof(NsanThread), PageSize);23  NsanThread *thread = (NsanThread *)MmapOrDie(size, __func__);24  thread->start_routine_ = start_routine;25  thread->arg_ = arg;26  thread->destructor_iterations_ = GetPthreadDestructorIterations();27 28  return thread;29}30 31void NsanThread::SetThreadStackAndTls() {32  GetThreadStackAndTls(IsMainThread(), &stack_.bottom, &stack_.top, &tls_begin_,33                       &tls_end_);34  int local;35  CHECK(AddrIsInStack((uptr)&local));36}37 38void NsanThread::ClearShadowForThreadStackAndTLS() {39  __nsan_set_value_unknown((const u8 *)stack_.bottom,40                           stack_.top - stack_.bottom);41  if (tls_begin_ != tls_end_)42    __nsan_set_value_unknown((const u8 *)tls_begin_, tls_end_ - tls_begin_);43  DTLS *dtls = DTLS_Get();44  CHECK_NE(dtls, 0);45  ForEachDVT(dtls, [](const DTLS::DTV &dtv, int id) {46    __nsan_set_value_unknown((const u8 *)dtv.beg, dtv.size);47  });48}49 50void NsanThread::Init() {51  SetThreadStackAndTls();52  ClearShadowForThreadStackAndTLS();53  malloc_storage().Init();54}55 56void NsanThread::TSDDtor(void *tsd) {57  NsanThread *t = (NsanThread *)tsd;58  t->Destroy();59}60 61void NsanThread::Destroy() {62  malloc_storage().CommitBack();63  // We also clear the shadow on thread destruction because64  // some code may still be executing in later TSD destructors65  // and we don't want it to have any poisoned stack.66  ClearShadowForThreadStackAndTLS();67  uptr size = RoundUpTo(sizeof(NsanThread), GetPageSizeCached());68  UnmapOrDie(this, size);69  DTLS_Destroy();70}71 72thread_return_t NsanThread::ThreadStart() {73  if (!start_routine_) {74    // start_routine_ == 0 if we're on the main thread or on one of the75    // OS X libdispatch worker threads. But nobody is supposed to call76    // ThreadStart() for the worker threads.77    return 0;78  }79 80  return start_routine_(arg_);81}82 83NsanThread::StackBounds NsanThread::GetStackBounds() const {84  if (!stack_switching_)85    return {stack_.bottom, stack_.top};86  const uptr cur_stack = GET_CURRENT_FRAME();87  // Note: need to check next stack first, because FinishSwitchFiber88  // may be in process of overwriting stack_.top/bottom_. But in such case89  // we are already on the next stack.90  if (cur_stack >= next_stack_.bottom && cur_stack < next_stack_.top)91    return {next_stack_.bottom, next_stack_.top};92  return {stack_.bottom, stack_.top};93}94 95uptr NsanThread::stack_top() { return GetStackBounds().top; }96 97uptr NsanThread::stack_bottom() { return GetStackBounds().bottom; }98 99bool NsanThread::AddrIsInStack(uptr addr) {100  const auto bounds = GetStackBounds();101  return addr >= bounds.bottom && addr < bounds.top;102}103 104void NsanThread::StartSwitchFiber(uptr bottom, uptr size) {105  CHECK(!stack_switching_);106  next_stack_.bottom = bottom;107  next_stack_.top = bottom + size;108  stack_switching_ = true;109}110 111void NsanThread::FinishSwitchFiber(uptr *bottom_old, uptr *size_old) {112  CHECK(stack_switching_);113  if (bottom_old)114    *bottom_old = stack_.bottom;115  if (size_old)116    *size_old = stack_.top - stack_.bottom;117  stack_.bottom = next_stack_.bottom;118  stack_.top = next_stack_.top;119  stack_switching_ = false;120  next_stack_.top = 0;121  next_stack_.bottom = 0;122}123 124static pthread_key_t tsd_key;125static bool tsd_key_inited;126 127void __nsan::NsanTSDInit(void (*destructor)(void *tsd)) {128  CHECK(!tsd_key_inited);129  tsd_key_inited = true;130  CHECK_EQ(0, pthread_key_create(&tsd_key, destructor));131}132 133static THREADLOCAL NsanThread *nsan_current_thread;134 135NsanThread *__nsan::GetCurrentThread() { return nsan_current_thread; }136 137void __nsan::SetCurrentThread(NsanThread *t) {138  // Make sure we do not reset the current NsanThread.139  CHECK_EQ(0, nsan_current_thread);140  nsan_current_thread = t;141  // Make sure that NsanTSDDtor gets called at the end.142  CHECK(tsd_key_inited);143  pthread_setspecific(tsd_key, t);144}145 146void __nsan::NsanTSDDtor(void *tsd) {147  NsanThread *t = (NsanThread *)tsd;148  if (t->destructor_iterations_ > 1) {149    t->destructor_iterations_--;150    CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));151    return;152  }153  nsan_current_thread = nullptr;154  // Make sure that signal handler can not see a stale current thread pointer.155  atomic_signal_fence(memory_order_seq_cst);156  NsanThread::TSDDtor(tsd);157}158