tsan_platform_linux.cc revision 88207ab15125e2f1e9b3d541b735b2b8aba9b6d9
1//===-- tsan_platform_linux.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 ThreadSanitizer (TSan), a race detector.
11//
12// Linux-specific code.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_common/sanitizer_libc.h"
16#include "tsan_platform.h"
17#include "tsan_rtl.h"
18#include "tsan_flags.h"
19
20#include <asm/prctl.h>
21#include <fcntl.h>
22#include <pthread.h>
23#include <signal.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdarg.h>
28#include <sys/mman.h>
29#include <sys/prctl.h>
30#include <sys/syscall.h>
31#include <sys/time.h>
32#include <sys/types.h>
33#include <sys/resource.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#include <errno.h>
37#include <sched.h>
38#include <dlfcn.h>
39
40extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
41
42namespace __sanitizer {
43
44void Die() {
45  _exit(1);
46}
47
48}  // namespace __sanitizer
49
50namespace __tsan {
51
52static uptr g_tls_size;
53
54ScopedInRtl::ScopedInRtl()
55    : thr_(cur_thread()) {
56  in_rtl_ = thr_->in_rtl;
57  thr_->in_rtl++;
58  errno_ = errno;
59}
60
61ScopedInRtl::~ScopedInRtl() {
62  thr_->in_rtl--;
63  errno = errno_;
64  CHECK_EQ(in_rtl_, thr_->in_rtl);
65}
66
67uptr GetShadowMemoryConsumption() {
68  return 0;
69}
70
71void FlushShadowMemory() {
72  madvise((void*)kLinuxShadowBeg,
73          kLinuxShadowEnd - kLinuxShadowBeg,
74          MADV_DONTNEED);
75}
76
77void internal_yield() {
78  ScopedInRtl in_rtl;
79  syscall(__NR_sched_yield);
80}
81
82void internal_sleep_ms(u32 ms) {
83  usleep(ms * 1000);
84}
85
86const char *internal_getpwd() {
87  return getenv("PWD");
88}
89
90static void ProtectRange(uptr beg, uptr end) {
91  ScopedInRtl in_rtl;
92  CHECK_LE(beg, end);
93  if (beg == end)
94    return;
95  if (beg != (uptr)internal_mmap((void*)(beg), end - beg,
96      PROT_NONE,
97      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
98      -1, 0)) {
99    TsanPrintf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
100    TsanPrintf("FATAL: Make sure you are not using unlimited stack\n");
101    Die();
102  }
103}
104
105void InitializeShadowMemory() {
106  const uptr kClosedLowBeg  = 0x200000;
107  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
108  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
109  const uptr kClosedMidEnd = kLinuxAppMemBeg - 1;
110  uptr shadow = (uptr)internal_mmap((void*)kLinuxShadowBeg,
111      kLinuxShadowEnd - kLinuxShadowBeg,
112      PROT_READ | PROT_WRITE,
113      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
114      -1, 0);
115  if (shadow != kLinuxShadowBeg) {
116    TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
117    TsanPrintf("FATAL: Make sure to compile with -fPIE and "
118               "to link with -pie.\n");
119    Die();
120  }
121  ProtectRange(kClosedLowBeg, kClosedLowEnd);
122  ProtectRange(kClosedMidBeg, kClosedMidEnd);
123  DPrintf("kClosedLow   %zx-%zx (%zuGB)\n",
124      kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
125  DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
126      kLinuxShadowBeg, kLinuxShadowEnd,
127      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
128  DPrintf("kClosedMid   %zx-%zx (%zuGB)\n",
129      kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
130  DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
131      kLinuxAppMemBeg, kLinuxAppMemEnd,
132      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
133  DPrintf("stack        %zx\n", (uptr)&shadow);
134}
135
136static void CheckPIE() {
137  // Ensure that the binary is indeed compiled with -pie.
138  fd_t fmaps = internal_open("/proc/self/maps", false);
139  if (fmaps == kInvalidFd)
140    return;
141  char buf[20];
142  if (internal_read(fmaps, buf, sizeof(buf)) == sizeof(buf)) {
143    buf[sizeof(buf) - 1] = 0;
144    u64 addr = strtoll(buf, 0, 16);
145    if ((u64)addr < kLinuxAppMemBeg) {
146      TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
147             "something is mapped at 0x%zx < 0x%zx)\n",
148             (uptr)addr, kLinuxAppMemBeg);
149      TsanPrintf("FATAL: Make sure to compile with -fPIE"
150             " and to link with -pie.\n");
151      Die();
152    }
153  }
154  internal_close(fmaps);
155}
156
157#ifdef __i386__
158# define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
159#else
160# define INTERNAL_FUNCTION
161#endif
162extern "C" void _dl_get_tls_static_info(size_t*, size_t*)
163    __attribute__((weak)) INTERNAL_FUNCTION;
164
165static int InitTlsSize() {
166  typedef void (*get_tls_func)(size_t*, size_t*) INTERNAL_FUNCTION;
167  get_tls_func get_tls = &_dl_get_tls_static_info;
168  if (get_tls == 0)
169    get_tls = (get_tls_func)dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
170  CHECK_NE(get_tls, 0);
171  size_t tls_size = 0;
172  size_t tls_align = 0;
173  get_tls(&tls_size, &tls_align);
174  return tls_size;
175}
176
177const char *InitializePlatform() {
178  void *p = 0;
179  if (sizeof(p) == 8) {
180    // Disable core dumps, dumping of 16TB usually takes a bit long.
181    // The following magic is to prevent clang from replacing it with memset.
182    volatile rlimit lim;
183    lim.rlim_cur = 0;
184    lim.rlim_max = 0;
185    setrlimit(RLIMIT_CORE, (rlimit*)&lim);
186  }
187
188  CheckPIE();
189  g_tls_size = (uptr)InitTlsSize();
190  return getenv("TSAN_OPTIONS");
191}
192
193void FinalizePlatform() {
194  fflush(0);
195}
196
197uptr GetTlsSize() {
198  return g_tls_size;
199}
200
201void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
202                          uptr *tls_addr, uptr *tls_size) {
203  arch_prctl(ARCH_GET_FS, tls_addr);
204  *tls_addr -= g_tls_size;
205  *tls_size = g_tls_size;
206
207  if (main) {
208    uptr kBufSize = 1 << 26;
209    char *buf = (char*)internal_mmap(0, kBufSize, PROT_READ | PROT_WRITE,
210                               MAP_PRIVATE | MAP_ANON, -1, 0);
211    fd_t maps = internal_open("/proc/self/maps", false);
212    if (maps == kInvalidFd) {
213      TsanPrintf("Failed to open /proc/self/maps\n");
214      Die();
215    }
216    char *end = buf;
217    while (end + kPageSize < buf + kBufSize) {
218      uptr read = internal_read(maps, end, kPageSize);
219      if ((int)read <= 0)
220        break;
221      end += read;
222    }
223    end[0] = 0;
224    end = (char*)REAL(strstr)(buf, "[stack]");
225    if (end == 0) {
226      TsanPrintf("Can't find [stack] in /proc/self/maps\n");
227      Die();
228    }
229    end[0] = 0;
230    char *pos = (char*)internal_strrchr(buf, '\n');
231    if (pos == 0) {
232      TsanPrintf("Can't find [stack] in /proc/self/maps\n");
233      Die();
234    }
235    pos = (char*)internal_strchr(pos, '-');
236    if (pos == 0) {
237      TsanPrintf("Can't find [stack] in /proc/self/maps\n");
238      Die();
239    }
240    uptr stack = 0;
241    for (; pos++;) {
242      uptr num = 0;
243      if (pos[0] >= '0' && pos[0] <= '9')
244        num = pos[0] - '0';
245      else if (pos[0] >= 'a' && pos[0] <= 'f')
246        num = pos[0] - 'a' + 10;
247      else
248        break;
249      stack = stack * 16 + num;
250    }
251    internal_close(maps);
252    internal_munmap(buf, kBufSize);
253
254    struct rlimit rl;
255    CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
256    *stk_addr = stack - rl.rlim_cur;
257    *stk_size = rl.rlim_cur;
258  } else {
259    *stk_addr = 0;
260    *stk_size = 0;
261    pthread_attr_t attr;
262    if (pthread_getattr_np(pthread_self(), &attr) == 0) {
263      pthread_attr_getstack(&attr, (void**)stk_addr, (size_t*)stk_size);
264      pthread_attr_destroy(&attr);
265    }
266
267    // If stack and tls intersect, make them non-intersecting.
268    if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
269      CHECK_GT(*tls_addr + *tls_size, *stk_addr);
270      CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
271      *stk_size -= *tls_size;
272      *tls_addr = *stk_addr + *stk_size;
273    }
274  }
275}
276
277}  // namespace __tsan
278