#ifndef ASAN_THREAD_H
#define ASAN_THREAD_H
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_fake_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"
namespace __asan {
const u32 kInvalidTid = 0xffffff; const u32 kMaxNumberOfThreads = (1 << 22);
class AsanThread;
class AsanThreadContext : public ThreadContextBase {
public:
explicit AsanThreadContext(int tid)
: ThreadContextBase(tid),
announced(false),
destructor_iterations(kPthreadDestructorIterations),
stack_id(0),
thread(0) {
}
bool announced;
u8 destructor_iterations;
u32 stack_id;
AsanThread *thread;
void OnCreated(void *arg);
void OnFinished();
};
COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
class AsanThread {
public:
static AsanThread *Create(thread_callback_t start_routine, void *arg,
u32 parent_tid, StackTrace *stack, bool detached);
static void TSDDtor(void *tsd);
void Destroy();
void Init(); thread_return_t ThreadStart(uptr os_id,
atomic_uintptr_t *signal_thread_is_registered);
uptr stack_top() { return stack_top_; }
uptr stack_bottom() { return stack_bottom_; }
uptr stack_size() { return stack_size_; }
uptr tls_begin() { return tls_begin_; }
uptr tls_end() { return tls_end_; }
u32 tid() { return context_->tid; }
AsanThreadContext *context() { return context_; }
void set_context(AsanThreadContext *context) { context_ = context; }
struct StackFrameAccess {
uptr offset;
uptr frame_pc;
const char *frame_descr;
};
bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
bool AddrIsInStack(uptr addr) {
return addr >= stack_bottom_ && addr < stack_top_;
}
void DeleteFakeStack(int tid) {
if (!fake_stack_) return;
FakeStack *t = fake_stack_;
fake_stack_ = 0;
SetTLSFakeStack(0);
t->Destroy(tid);
}
bool has_fake_stack() {
return (reinterpret_cast<uptr>(fake_stack_) > 1);
}
FakeStack *fake_stack() {
if (!__asan_option_detect_stack_use_after_return)
return 0;
if (!has_fake_stack())
return AsyncSignalSafeLazyInitFakeStack();
return fake_stack_;
}
bool isUnwinding() const { return unwinding_; }
void setUnwinding(bool b) { unwinding_ = b; }
bool isInDeadlySignal() const { return in_deadly_signal_; }
void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
uptr stack_top_;
uptr stack_bottom_;
uptr stack_size_;
uptr tls_begin_;
uptr tls_end_;
FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
bool in_deadly_signal_;
};
class ScopedUnwinding {
public:
explicit ScopedUnwinding(AsanThread *t) : thread(t) {
t->setUnwinding(true);
}
~ScopedUnwinding() { thread->setUnwinding(false); }
private:
AsanThread *thread;
};
class ScopedDeadlySignal {
public:
explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
if (thread) thread->setInDeadlySignal(true);
}
~ScopedDeadlySignal() {
if (thread) thread->setInDeadlySignal(false);
}
private:
AsanThread *thread;
};
ThreadRegistry &asanThreadRegistry();
AsanThreadContext *GetThreadContextByTidLocked(u32 tid);
AsanThread *GetCurrentThread();
void SetCurrentThread(AsanThread *t);
u32 GetCurrentTidOrInvalid();
AsanThread *FindThreadByStackAddress(uptr addr);
void EnsureMainThreadIDIsCorrect();
}
#endif // ASAN_THREAD_H