blob: a71ad8d37511c12aa3f61ea12c952a0756d8fbaf [file] [log] [blame]
Kostya Serebryany1e172b42011-11-30 01:07:02 +00001//===-- asan_thread.cc ------------------------------------------*- C++ -*-===//
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_thread.h"
17#include "asan_thread_registry.h"
18#include "asan_mapping.h"
19
20#include <sys/mman.h>
21#include <pthread.h>
22#include <stdlib.h>
23#include <string.h>
24
25namespace __asan {
26
27AsanThread::AsanThread(LinkerInitialized x)
28 : fake_stack_(x),
29 malloc_storage_(x),
30 stats_(x) { }
31
32AsanThread::AsanThread(int parent_tid, void *(*start_routine) (void *),
33 void *arg, AsanStackTrace *stack)
34 : start_routine_(start_routine),
35 arg_(arg) {
36 asanThreadRegistry().RegisterThread(this, parent_tid, stack);
37}
38
39AsanThread::~AsanThread() {
40 asanThreadRegistry().UnregisterThread(this);
41 fake_stack().Cleanup();
42 // We also clear the shadow on thread destruction because
43 // some code may still be executing in later TSD destructors
44 // and we don't want it to have any poisoned stack.
45 ClearShadowForThreadStack();
46}
47
48void AsanThread::ClearShadowForThreadStack() {
49 uintptr_t shadow_bot = MemToShadow(stack_bottom_);
50 uintptr_t shadow_top = MemToShadow(stack_top_);
51 real_memset((void*)shadow_bot, 0, shadow_top - shadow_bot);
52}
53
Kostya Serebryany69eca732011-12-16 19:13:35 +000054void AsanThread::Init() {
Kostya Serebryany1e172b42011-11-30 01:07:02 +000055 SetThreadStackTopAndBottom();
56 fake_stack_.Init(stack_size());
57 if (FLAG_v >= 1) {
58 int local = 0;
59 Report("T%d: stack [%p,%p) size 0x%lx; local=%p, pthread_self=%p\n",
60 tid(), stack_bottom_, stack_top_,
61 stack_top_ - stack_bottom_, &local, pthread_self());
62 }
63
64 CHECK(AddrIsInMem(stack_bottom_));
65 CHECK(AddrIsInMem(stack_top_));
66
67 ClearShadowForThreadStack();
Kostya Serebryany69eca732011-12-16 19:13:35 +000068}
69
70void *AsanThread::ThreadStart() {
71 Init();
Kostya Serebryany1e172b42011-11-30 01:07:02 +000072
73 if (!start_routine_) {
74 // start_routine_ == NULL if we're on the main thread or on one of the
75 // OS X libdispatch worker threads. But nobody is supposed to call
76 // ThreadStart() for the worker threads.
77 CHECK(tid() == 0);
78 return 0;
79 }
80
81 void *res = start_routine_(arg_);
82 malloc_storage().CommitBack();
83
84 if (FLAG_v >= 1) {
85 Report("T%d exited\n", tid());
86 }
87
88 return res;
89}
90
91const char *AsanThread::GetFrameNameByAddr(uintptr_t addr, uintptr_t *offset) {
92 uintptr_t bottom = 0;
93 bool is_fake_stack = false;
94 if (AddrIsInStack(addr)) {
95 bottom = stack_bottom();
96 } else {
97 bottom = fake_stack().AddrIsInFakeStack(addr);
98 CHECK(bottom);
99 is_fake_stack = true;
100 }
101 uintptr_t aligned_addr = addr & ~(__WORDSIZE/8 - 1); // align addr.
102 uintptr_t *ptr = (uintptr_t*)aligned_addr;
103 while (ptr >= (uintptr_t*)bottom) {
104 if (ptr[0] == kCurrentStackFrameMagic ||
105 (is_fake_stack && ptr[0] == kRetiredStackFrameMagic)) {
106 *offset = addr - (uintptr_t)ptr;
107 return (const char*)ptr[1];
108 }
109 ptr--;
110 }
111 *offset = 0;
112 return "UNKNOWN";
113}
114
115void AsanThread::SetThreadStackTopAndBottom() {
116#ifdef __APPLE__
117 size_t stacksize = pthread_get_stacksize_np(pthread_self());
118 void *stackaddr = pthread_get_stackaddr_np(pthread_self());
119 stack_top_ = (uintptr_t)stackaddr;
120 stack_bottom_ = stack_top_ - stacksize;
121 int local;
122 CHECK(AddrIsInStack((uintptr_t)&local));
123#else
124 pthread_attr_t attr;
125 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
126 size_t stacksize = 0;
127 void *stackaddr = NULL;
128 pthread_attr_getstack(&attr, &stackaddr, &stacksize);
129 pthread_attr_destroy(&attr);
130
131 stack_top_ = (uintptr_t)stackaddr + stacksize;
132 stack_bottom_ = (uintptr_t)stackaddr;
133 // When running with unlimited stack size, we still want to set some limit.
134 // The unlimited stack size is caused by 'ulimit -s unlimited'.
135 // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
136 if (stacksize > kMaxThreadStackSize) {
137 stack_bottom_ = stack_top_ - kMaxThreadStackSize;
138 }
139 CHECK(AddrIsInStack((uintptr_t)&attr));
140#endif
141}
142
143} // namespace __asan