asan_thread.cc revision e5931fd7d2a74fd7fb60bd8d7f644cca51a24364
1//===-- asan_thread.cc ----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Thread-related code.
13//===----------------------------------------------------------------------===//
14#include "asan_allocator.h"
15#include "asan_interceptors.h"
16#include "asan_procmaps.h"
17#include "asan_stack.h"
18#include "asan_thread.h"
19#include "asan_thread_registry.h"
20#include "asan_mapping.h"
21#include "sanitizer_common/sanitizer_common.h"
22
23namespace __asan {
24
25AsanThread::AsanThread(LinkerInitialized x)
26    : fake_stack_(x),
27      malloc_storage_(x),
28      stats_(x) { }
29
30AsanThread *AsanThread::Create(u32 parent_tid, thread_callback_t start_routine,
31                               void *arg, AsanStackTrace *stack) {
32  uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
33  AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
34  thread->start_routine_ = start_routine;
35  thread->arg_ = arg;
36
37  AsanThreadSummary *summary = new AsanThreadSummary(parent_tid, stack);
38  summary->set_thread(thread);
39  thread->set_summary(summary);
40
41  return thread;
42}
43
44void AsanThreadSummary::TSDDtor(void *tsd) {
45  AsanThreadSummary *summary = (AsanThreadSummary*)tsd;
46  if (FLAG_v >= 1) {
47    Report("T%d TSDDtor\n", summary->tid());
48  }
49  if (summary->thread()) {
50    summary->thread()->Destroy();
51  }
52}
53
54void AsanThread::Destroy() {
55  if (FLAG_v >= 1) {
56    Report("T%d exited\n", tid());
57  }
58
59  asanThreadRegistry().UnregisterThread(this);
60  CHECK(summary()->thread() == 0);
61  // We also clear the shadow on thread destruction because
62  // some code may still be executing in later TSD destructors
63  // and we don't want it to have any poisoned stack.
64  ClearShadowForThreadStack();
65  fake_stack().Cleanup();
66  uptr size = RoundUpTo(sizeof(AsanThread), kPageSize);
67  UnmapOrDie(this, size);
68}
69
70void AsanThread::Init() {
71  SetThreadStackTopAndBottom();
72  CHECK(AddrIsInMem(stack_bottom_));
73  CHECK(AddrIsInMem(stack_top_));
74  ClearShadowForThreadStack();
75  if (FLAG_v >= 1) {
76    int local = 0;
77    Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
78           tid(), (void*)stack_bottom_, (void*)stack_top_,
79           stack_top_ - stack_bottom_, &local);
80  }
81  fake_stack_.Init(stack_size());
82}
83
84thread_return_t AsanThread::ThreadStart() {
85  Init();
86  if (FLAG_use_sigaltstack) SetAlternateSignalStack();
87
88  if (!start_routine_) {
89    // start_routine_ == 0 if we're on the main thread or on one of the
90    // OS X libdispatch worker threads. But nobody is supposed to call
91    // ThreadStart() for the worker threads.
92    CHECK(tid() == 0);
93    return 0;
94  }
95
96  thread_return_t res = start_routine_(arg_);
97  malloc_storage().CommitBack();
98  if (FLAG_use_sigaltstack) UnsetAlternateSignalStack();
99
100  this->Destroy();
101
102  return res;
103}
104
105void AsanThread::SetThreadStackTopAndBottom() {
106  GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_);
107  int local;
108  CHECK(AddrIsInStack((uptr)&local));
109}
110
111void AsanThread::ClearShadowForThreadStack() {
112  PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
113}
114
115const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
116  uptr bottom = 0;
117  bool is_fake_stack = false;
118  if (AddrIsInStack(addr)) {
119    bottom = stack_bottom();
120  } else {
121    bottom = fake_stack().AddrIsInFakeStack(addr);
122    CHECK(bottom);
123    is_fake_stack = true;
124  }
125  uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
126  u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
127  u8 *shadow_bottom = (u8*)MemToShadow(bottom);
128
129  while (shadow_ptr >= shadow_bottom &&
130      *shadow_ptr != kAsanStackLeftRedzoneMagic) {
131    shadow_ptr--;
132  }
133
134  while (shadow_ptr >= shadow_bottom &&
135      *shadow_ptr == kAsanStackLeftRedzoneMagic) {
136    shadow_ptr--;
137  }
138
139  if (shadow_ptr < shadow_bottom) {
140    *offset = 0;
141    return "UNKNOWN";
142  }
143
144  uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
145  CHECK((ptr[0] == kCurrentStackFrameMagic) ||
146      (is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
147  *offset = addr - (uptr)ptr;
148  return (const char*)ptr[1];
149}
150
151}  // namespace __asan
152