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