• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
44 extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
45 
46 namespace __sanitizer {
47 
Die()48 void Die() {
49   _exit(1);
50 }
51 
52 }  // namespace __sanitizer
53 
54 namespace __tsan {
55 
56 #ifndef TSAN_GO
ScopedInRtl()57 ScopedInRtl::ScopedInRtl()
58     : thr_(cur_thread()) {
59   in_rtl_ = thr_->in_rtl;
60   thr_->in_rtl++;
61   errno_ = errno;
62 }
63 
~ScopedInRtl()64 ScopedInRtl::~ScopedInRtl() {
65   thr_->in_rtl--;
66   errno = errno_;
67   CHECK_EQ(in_rtl_, thr_->in_rtl);
68 }
69 #else
70 ScopedInRtl::ScopedInRtl() {
71 }
72 
73 ScopedInRtl::~ScopedInRtl() {
74 }
75 #endif
76 
GetShadowMemoryConsumption()77 uptr GetShadowMemoryConsumption() {
78   return 0;
79 }
80 
FlushShadowMemory()81 void FlushShadowMemory() {
82   madvise((void*)kLinuxShadowBeg,
83           kLinuxShadowEnd - kLinuxShadowBeg,
84           MADV_DONTNEED);
85 }
86 
87 #ifndef TSAN_GO
ProtectRange(uptr beg,uptr end)88 static void ProtectRange(uptr beg, uptr end) {
89   ScopedInRtl in_rtl;
90   CHECK_LE(beg, end);
91   if (beg == end)
92     return;
93   if (beg != (uptr)Mprotect(beg, end - beg)) {
94     TsanPrintf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
95     TsanPrintf("FATAL: Make sure you are not using unlimited stack\n");
96     Die();
97   }
98 }
99 #endif
100 
InitializeShadowMemory()101 void InitializeShadowMemory() {
102   uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
103     kLinuxShadowEnd - kLinuxShadowBeg);
104   if (shadow != kLinuxShadowBeg) {
105     TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
106     TsanPrintf("FATAL: Make sure to compile with -fPIE and "
107                "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
108     Die();
109   }
110 #ifndef TSAN_GO
111   const uptr kClosedLowBeg  = 0x200000;
112   const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
113   const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
114   const uptr kClosedMidEnd = kLinuxAppMemBeg - 1;
115   ProtectRange(kClosedLowBeg, kClosedLowEnd);
116   ProtectRange(kClosedMidBeg, kClosedMidEnd);
117 #endif
118 #ifndef TSAN_GO
119   DPrintf("kClosedLow   %zx-%zx (%zuGB)\n",
120       kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
121 #endif
122   DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
123       kLinuxShadowBeg, kLinuxShadowEnd,
124       (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
125 #ifndef TSAN_GO
126   DPrintf("kClosedMid   %zx-%zx (%zuGB)\n",
127       kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
128 #endif
129   DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
130       kLinuxAppMemBeg, kLinuxAppMemEnd,
131       (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
132   DPrintf("stack        %zx\n", (uptr)&shadow);
133 }
134 
135 static uptr g_tls_size;
136 static uptr g_data_start;
137 static uptr g_data_end;
138 
139 #ifndef TSAN_GO
CheckPIE()140 static void CheckPIE() {
141   // Ensure that the binary is indeed compiled with -pie.
142   MemoryMappingLayout proc_maps;
143   uptr start, end;
144   if (proc_maps.Next(&start, &end,
145                      /*offset*/0, /*filename*/0, /*filename_size*/0)) {
146     if ((u64)start < kLinuxAppMemBeg) {
147       TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
148              "something is mapped at 0x%zx < 0x%zx)\n",
149              start, kLinuxAppMemBeg);
150       TsanPrintf("FATAL: Make sure to compile with -fPIE"
151              " and to link with -pie.\n");
152       Die();
153     }
154   }
155 }
156 
InitDataSeg()157 static void InitDataSeg() {
158   MemoryMappingLayout proc_maps;
159   uptr start, end, offset;
160   char name[128];
161   bool prev_is_data = false;
162   while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name))) {
163     DPrintf("%p-%p %p %s\n", start, end, offset, name);
164     bool is_data = offset != 0 && name[0] != 0;
165     bool is_bss = offset == 0 && name[0] == 0 && prev_is_data;
166     if (g_data_start == 0 && is_data)
167       g_data_start = start;
168     if (is_bss)
169       g_data_end = end;
170     prev_is_data = is_data;
171   }
172   DPrintf("guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
173   CHECK_LT(g_data_start, g_data_end);
174   CHECK_GE((uptr)&g_data_start, g_data_start);
175   CHECK_LT((uptr)&g_data_start, g_data_end);
176 }
177 
178 #ifdef __i386__
179 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
180 #else
181 # define INTERNAL_FUNCTION
182 #endif
183 extern "C" void _dl_get_tls_static_info(size_t*, size_t*)
184     __attribute__((weak)) INTERNAL_FUNCTION;
185 
InitTlsSize()186 static int InitTlsSize() {
187   typedef void (*get_tls_func)(size_t*, size_t*) INTERNAL_FUNCTION;
188   get_tls_func get_tls = &_dl_get_tls_static_info;
189   if (get_tls == 0)
190     get_tls = (get_tls_func)dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
191   CHECK_NE(get_tls, 0);
192   size_t tls_size = 0;
193   size_t tls_align = 0;
194   get_tls(&tls_size, &tls_align);
195   return tls_size;
196 }
197 #endif  // #ifndef TSAN_GO
198 
InitializePlatform()199 const char *InitializePlatform() {
200   void *p = 0;
201   if (sizeof(p) == 8) {
202     // Disable core dumps, dumping of 16TB usually takes a bit long.
203     // The following magic is to prevent clang from replacing it with memset.
204     volatile rlimit lim;
205     lim.rlim_cur = 0;
206     lim.rlim_max = 0;
207     setrlimit(RLIMIT_CORE, (rlimit*)&lim);
208   }
209 
210 #ifndef TSAN_GO
211   CheckPIE();
212   g_tls_size = (uptr)InitTlsSize();
213   InitDataSeg();
214 #endif
215   return getenv("TSAN_OPTIONS");
216 }
217 
FinalizePlatform()218 void FinalizePlatform() {
219   fflush(0);
220 }
221 
GetTlsSize()222 uptr GetTlsSize() {
223 #ifndef TSAN_GO
224   return g_tls_size;
225 #else
226   return 0;
227 #endif
228 }
229 
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)230 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
231                           uptr *tls_addr, uptr *tls_size) {
232 #ifndef TSAN_GO
233   arch_prctl(ARCH_GET_FS, tls_addr);
234   *tls_addr -= g_tls_size;
235   *tls_size = g_tls_size;
236 
237   uptr stack_top, stack_bottom;
238   GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
239   *stk_addr = stack_bottom;
240   *stk_size = stack_top - stack_bottom;
241 
242   if (!main) {
243     // If stack and tls intersect, make them non-intersecting.
244     if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
245       CHECK_GT(*tls_addr + *tls_size, *stk_addr);
246       CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
247       *stk_size -= *tls_size;
248       *tls_addr = *stk_addr + *stk_size;
249     }
250   }
251 #else
252   *stk_addr = 0;
253   *stk_size = 0;
254   *tls_addr = 0;
255   *tls_size = 0;
256 #endif
257 }
258 
IsGlobalVar(uptr addr)259 bool IsGlobalVar(uptr addr) {
260   return g_data_start && addr >= g_data_start && addr < g_data_end;
261 }
262 
263 }  // namespace __tsan
264 
265 #endif  // #ifdef __linux__
266