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#ifdef __linux__
16
17#include "sanitizer_common/sanitizer_common.h"
18#include "sanitizer_common/sanitizer_libc.h"
19#include "sanitizer_common/sanitizer_procmaps.h"
20#include "tsan_platform.h"
21#include "tsan_rtl.h"
22#include "tsan_flags.h"
23
24#include <asm/prctl.h>
25#include <fcntl.h>
26#include <pthread.h>
27#include <signal.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <stdarg.h>
32#include <sys/mman.h>
33#include <sys/prctl.h>
34#include <sys/syscall.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <sys/resource.h>
38#include <sys/stat.h>
39#include <unistd.h>
40#include <errno.h>
41#include <sched.h>
42#include <dlfcn.h>
43#define __need_res_state
44#include <resolv.h>
45#include <malloc.h>
46
47extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
48extern "C" struct mallinfo __libc_mallinfo();
49
50namespace __tsan {
51
52#ifndef TSAN_GO
53ScopedInRtl::ScopedInRtl()
54    : thr_(cur_thread()) {
55  in_rtl_ = thr_->in_rtl;
56  thr_->in_rtl++;
57  errno_ = errno;
58}
59
60ScopedInRtl::~ScopedInRtl() {
61  thr_->in_rtl--;
62  errno = errno_;
63  CHECK_EQ(in_rtl_, thr_->in_rtl);
64}
65#else
66ScopedInRtl::ScopedInRtl() {
67}
68
69ScopedInRtl::~ScopedInRtl() {
70}
71#endif
72
73static bool ishex(char c) {
74  return (c >= '0' && c <= '9')
75      || (c >= 'a' && c <= 'f');
76}
77
78static uptr readhex(const char *p) {
79  uptr v = 0;
80  for (; ishex(p[0]); p++) {
81    if (p[0] >= '0' && p[0] <= '9')
82      v = v * 16 + p[0] - '0';
83    else
84      v = v * 16 + p[0] - 'a' + 10;
85  }
86  return v;
87}
88
89static uptr readdec(const char *p) {
90  uptr v = 0;
91  for (; p[0] >= '0' && p[0] <= '9' ; p++)
92    v = v * 10 + p[0] - '0';
93  return v;
94}
95
96void WriteMemoryProfile(char *buf, uptr buf_size) {
97  char *smaps = 0;
98  uptr smaps_cap = 0;
99  uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
100      &smaps, &smaps_cap, 64<<20);
101  uptr mem[6] = {};
102  uptr total = 0;
103  uptr start = 0;
104  bool file = false;
105  const char *pos = smaps;
106  while (pos < smaps + smaps_len) {
107    if (ishex(pos[0])) {
108      start = readhex(pos);
109      for (; *pos != '/' && *pos > '\n'; pos++) {}
110      file = *pos == '/';
111    } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
112      for (; *pos < '0' || *pos > '9'; pos++) {}
113      uptr rss = readdec(pos) * 1024;
114      total += rss;
115      start >>= 40;
116      if (start < 0x10)  // shadow
117        mem[0] += rss;
118      else if (start >= 0x20 && start < 0x30)  // compat modules
119        mem[file ? 1 : 2] += rss;
120      else if (start >= 0x7e)  // modules
121        mem[file ? 1 : 2] += rss;
122      else if (start >= 0x60 && start < 0x62)  // traces
123        mem[3] += rss;
124      else if (start >= 0x7d && start < 0x7e)  // heap
125        mem[4] += rss;
126      else  // other
127        mem[5] += rss;
128    }
129    while (*pos++ != '\n') {}
130  }
131  UnmapOrDie(smaps, smaps_cap);
132  char *buf_pos = buf;
133  char *buf_end = buf + buf_size;
134  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
135      "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
136      total >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
137      mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
138  struct mallinfo mi = __libc_mallinfo();
139  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
140      "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
141      mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
142}
143
144void FlushShadowMemory() {
145  FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
146}
147
148#ifndef TSAN_GO
149static void ProtectRange(uptr beg, uptr end) {
150  ScopedInRtl in_rtl;
151  CHECK_LE(beg, end);
152  if (beg == end)
153    return;
154  if (beg != (uptr)Mprotect(beg, end - beg)) {
155    Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
156    Printf("FATAL: Make sure you are not using unlimited stack\n");
157    Die();
158  }
159}
160#endif
161
162#ifndef TSAN_GO
163void InitializeShadowMemory() {
164  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
165    kLinuxShadowEnd - kLinuxShadowBeg);
166  if (shadow != kLinuxShadowBeg) {
167    Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
168    Printf("FATAL: Make sure to compile with -fPIE and "
169               "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
170    Die();
171  }
172  const uptr kClosedLowBeg  = 0x200000;
173  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
174  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
175  const uptr kClosedMidEnd = min(kLinuxAppMemBeg, kTraceMemBegin);
176  ProtectRange(kClosedLowBeg, kClosedLowEnd);
177  ProtectRange(kClosedMidBeg, kClosedMidEnd);
178  DPrintf("kClosedLow   %zx-%zx (%zuGB)\n",
179      kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
180  DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
181      kLinuxShadowBeg, kLinuxShadowEnd,
182      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
183  DPrintf("kClosedMid   %zx-%zx (%zuGB)\n",
184      kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
185  DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
186      kLinuxAppMemBeg, kLinuxAppMemEnd,
187      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
188  DPrintf("stack        %zx\n", (uptr)&shadow);
189}
190#endif
191
192static uptr g_data_start;
193static uptr g_data_end;
194
195#ifndef TSAN_GO
196static void CheckPIE() {
197  // Ensure that the binary is indeed compiled with -pie.
198  MemoryMappingLayout proc_maps;
199  uptr start, end;
200  if (proc_maps.Next(&start, &end,
201                     /*offset*/0, /*filename*/0, /*filename_size*/0,
202                     /*protection*/0)) {
203    if ((u64)start < kLinuxAppMemBeg) {
204      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
205             "something is mapped at 0x%zx < 0x%zx)\n",
206             start, kLinuxAppMemBeg);
207      Printf("FATAL: Make sure to compile with -fPIE"
208             " and to link with -pie.\n");
209      Die();
210    }
211  }
212}
213
214static void InitDataSeg() {
215  MemoryMappingLayout proc_maps;
216  uptr start, end, offset;
217  char name[128];
218  bool prev_is_data = false;
219  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
220                        /*protection*/ 0)) {
221    DPrintf("%p-%p %p %s\n", start, end, offset, name);
222    bool is_data = offset != 0 && name[0] != 0;
223    // BSS may get merged with [heap] in /proc/self/maps. This is not very
224    // reliable.
225    bool is_bss = offset == 0 &&
226      (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
227    if (g_data_start == 0 && is_data)
228      g_data_start = start;
229    if (is_bss)
230      g_data_end = end;
231    prev_is_data = is_data;
232  }
233  DPrintf("guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
234  CHECK_LT(g_data_start, g_data_end);
235  CHECK_GE((uptr)&g_data_start, g_data_start);
236  CHECK_LT((uptr)&g_data_start, g_data_end);
237}
238
239#endif  // #ifndef TSAN_GO
240
241static rlim_t getlim(int res) {
242  rlimit rlim;
243  CHECK_EQ(0, getrlimit(res, &rlim));
244  return rlim.rlim_cur;
245}
246
247static void setlim(int res, rlim_t lim) {
248  // The following magic is to prevent clang from replacing it with memset.
249  volatile rlimit rlim;
250  rlim.rlim_cur = lim;
251  rlim.rlim_max = lim;
252  setrlimit(res, (rlimit*)&rlim);
253}
254
255const char *InitializePlatform() {
256  void *p = 0;
257  if (sizeof(p) == 8) {
258    // Disable core dumps, dumping of 16TB usually takes a bit long.
259    setlim(RLIMIT_CORE, 0);
260  }
261
262  // Go maps shadow memory lazily and works fine with limited address space.
263  // Unlimited stack is not a problem as well, because the executable
264  // is not compiled with -pie.
265  if (kCppMode) {
266    bool reexec = false;
267    // TSan doesn't play well with unlimited stack size (as stack
268    // overlaps with shadow memory). If we detect unlimited stack size,
269    // we re-exec the program with limited stack size as a best effort.
270    if (getlim(RLIMIT_STACK) == (rlim_t)-1) {
271      const uptr kMaxStackSize = 32 * 1024 * 1024;
272      Report("WARNING: Program is run with unlimited stack size, which "
273             "wouldn't work with ThreadSanitizer.\n");
274      Report("Re-execing with stack size limited to %zd bytes.\n",
275             kMaxStackSize);
276      SetStackSizeLimitInBytes(kMaxStackSize);
277      reexec = true;
278    }
279
280    if (getlim(RLIMIT_AS) != (rlim_t)-1) {
281      Report("WARNING: Program is run with limited virtual address space,"
282             " which wouldn't work with ThreadSanitizer.\n");
283      Report("Re-execing with unlimited virtual address space.\n");
284      setlim(RLIMIT_AS, -1);
285      reexec = true;
286    }
287    if (reexec)
288      ReExec();
289  }
290
291#ifndef TSAN_GO
292  CheckPIE();
293  InitTlsSize();
294  InitDataSeg();
295#endif
296  return GetEnv(kTsanOptionsEnv);
297}
298
299void FinalizePlatform() {
300  fflush(0);
301}
302
303void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
304                          uptr *tls_addr, uptr *tls_size) {
305#ifndef TSAN_GO
306  arch_prctl(ARCH_GET_FS, tls_addr);
307  *tls_size = GetTlsSize();
308  *tls_addr -= *tls_size;
309
310  uptr stack_top, stack_bottom;
311  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
312  *stk_addr = stack_bottom;
313  *stk_size = stack_top - stack_bottom;
314
315  if (!main) {
316    // If stack and tls intersect, make them non-intersecting.
317    if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
318      CHECK_GT(*tls_addr + *tls_size, *stk_addr);
319      CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
320      *stk_size -= *tls_size;
321      *tls_addr = *stk_addr + *stk_size;
322    }
323  }
324#else
325  *stk_addr = 0;
326  *stk_size = 0;
327  *tls_addr = 0;
328  *tls_size = 0;
329#endif
330}
331
332bool IsGlobalVar(uptr addr) {
333  return g_data_start && addr >= g_data_start && addr < g_data_end;
334}
335
336#ifndef TSAN_GO
337int ExtractResolvFDs(void *state, int *fds, int nfd) {
338  int cnt = 0;
339  __res_state *statp = (__res_state*)state;
340  for (int i = 0; i < MAXNS && cnt < nfd; i++) {
341    if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
342      fds[cnt++] = statp->_u._ext.nssocks[i];
343  }
344  return cnt;
345}
346#endif
347
348
349}  // namespace __tsan
350
351#endif  // #ifdef __linux__
352