tsan_platform_linux.cc revision 4dc30820d34372c419fd44dda2bdb6383a480ce7
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 44extern "C" int arch_prctl(int code, __sanitizer::uptr *addr); 45 46namespace __tsan { 47 48#ifndef TSAN_GO 49ScopedInRtl::ScopedInRtl() 50 : thr_(cur_thread()) { 51 in_rtl_ = thr_->in_rtl; 52 thr_->in_rtl++; 53 errno_ = errno; 54} 55 56ScopedInRtl::~ScopedInRtl() { 57 thr_->in_rtl--; 58 errno = errno_; 59 CHECK_EQ(in_rtl_, thr_->in_rtl); 60} 61#else 62ScopedInRtl::ScopedInRtl() { 63} 64 65ScopedInRtl::~ScopedInRtl() { 66} 67#endif 68 69uptr GetShadowMemoryConsumption() { 70 return 0; 71} 72 73void FlushShadowMemory() { 74 madvise((void*)kLinuxShadowBeg, 75 kLinuxShadowEnd - kLinuxShadowBeg, 76 MADV_DONTNEED); 77} 78 79#ifndef TSAN_GO 80static void ProtectRange(uptr beg, uptr end) { 81 ScopedInRtl in_rtl; 82 CHECK_LE(beg, end); 83 if (beg == end) 84 return; 85 if (beg != (uptr)Mprotect(beg, end - beg)) { 86 Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end); 87 Printf("FATAL: Make sure you are not using unlimited stack\n"); 88 Die(); 89 } 90} 91#endif 92 93#ifndef TSAN_GO 94void InitializeShadowMemory() { 95 uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg, 96 kLinuxShadowEnd - kLinuxShadowBeg); 97 if (shadow != kLinuxShadowBeg) { 98 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); 99 Printf("FATAL: Make sure to compile with -fPIE and " 100 "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg); 101 Die(); 102 } 103 const uptr kClosedLowBeg = 0x200000; 104 const uptr kClosedLowEnd = kLinuxShadowBeg - 1; 105 const uptr kClosedMidBeg = kLinuxShadowEnd + 1; 106 const uptr kClosedMidEnd = min(kLinuxAppMemBeg, kTraceMemBegin); 107 ProtectRange(kClosedLowBeg, kClosedLowEnd); 108 ProtectRange(kClosedMidBeg, kClosedMidEnd); 109 DPrintf("kClosedLow %zx-%zx (%zuGB)\n", 110 kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30); 111 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n", 112 kLinuxShadowBeg, kLinuxShadowEnd, 113 (kLinuxShadowEnd - kLinuxShadowBeg) >> 30); 114 DPrintf("kClosedMid %zx-%zx (%zuGB)\n", 115 kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30); 116 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n", 117 kLinuxAppMemBeg, kLinuxAppMemEnd, 118 (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30); 119 DPrintf("stack %zx\n", (uptr)&shadow); 120} 121#endif 122 123static uptr g_data_start; 124static uptr g_data_end; 125 126#ifndef TSAN_GO 127static void CheckPIE() { 128 // Ensure that the binary is indeed compiled with -pie. 129 MemoryMappingLayout proc_maps; 130 uptr start, end; 131 if (proc_maps.Next(&start, &end, 132 /*offset*/0, /*filename*/0, /*filename_size*/0)) { 133 if ((u64)start < kLinuxAppMemBeg) { 134 Printf("FATAL: ThreadSanitizer can not mmap the shadow memory (" 135 "something is mapped at 0x%zx < 0x%zx)\n", 136 start, kLinuxAppMemBeg); 137 Printf("FATAL: Make sure to compile with -fPIE" 138 " and to link with -pie.\n"); 139 Die(); 140 } 141 } 142} 143 144static void InitDataSeg() { 145 MemoryMappingLayout proc_maps; 146 uptr start, end, offset; 147 char name[128]; 148 bool prev_is_data = false; 149 while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name))) { 150 DPrintf("%p-%p %p %s\n", start, end, offset, name); 151 bool is_data = offset != 0 && name[0] != 0; 152 // BSS may get merged with [heap] in /proc/self/maps. This is not very 153 // reliable. 154 bool is_bss = offset == 0 && 155 (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data; 156 if (g_data_start == 0 && is_data) 157 g_data_start = start; 158 if (is_bss) 159 g_data_end = end; 160 prev_is_data = is_data; 161 } 162 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); 163 CHECK_LT(g_data_start, g_data_end); 164 CHECK_GE((uptr)&g_data_start, g_data_start); 165 CHECK_LT((uptr)&g_data_start, g_data_end); 166} 167 168static uptr g_tls_size; 169 170#ifdef __i386__ 171# define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall)) 172#else 173# define INTERNAL_FUNCTION 174#endif 175extern "C" void _dl_get_tls_static_info(size_t*, size_t*) 176 __attribute__((weak)) INTERNAL_FUNCTION; 177 178static int InitTlsSize() { 179 typedef void (*get_tls_func)(size_t*, size_t*) INTERNAL_FUNCTION; 180 get_tls_func get_tls = &_dl_get_tls_static_info; 181 if (get_tls == 0) { 182 void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); 183 CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr)); 184 internal_memcpy(&get_tls, &get_tls_static_info_ptr, 185 sizeof(get_tls_static_info_ptr)); 186 } 187 CHECK_NE(get_tls, 0); 188 size_t tls_size = 0; 189 size_t tls_align = 0; 190 get_tls(&tls_size, &tls_align); 191 return tls_size; 192} 193#endif // #ifndef TSAN_GO 194 195static rlim_t getlim(int res) { 196 rlimit rlim; 197 CHECK_EQ(0, getrlimit(res, &rlim)); 198 return rlim.rlim_cur; 199} 200 201static void setlim(int res, rlim_t lim) { 202 // The following magic is to prevent clang from replacing it with memset. 203 volatile rlimit rlim; 204 rlim.rlim_cur = lim; 205 rlim.rlim_max = lim; 206 setrlimit(res, (rlimit*)&rlim); 207} 208 209const char *InitializePlatform() { 210 void *p = 0; 211 if (sizeof(p) == 8) { 212 // Disable core dumps, dumping of 16TB usually takes a bit long. 213 setlim(RLIMIT_CORE, 0); 214 } 215 216 // Go maps shadow memory lazily and works fine with limited address space. 217 // Unlimited stack is not a problem as well, because the executable 218 // is not compiled with -pie. 219 if (kCppMode) { 220 bool reexec = false; 221 // TSan doesn't play well with unlimited stack size (as stack 222 // overlaps with shadow memory). If we detect unlimited stack size, 223 // we re-exec the program with limited stack size as a best effort. 224 if (getlim(RLIMIT_STACK) == (rlim_t)-1) { 225 const uptr kMaxStackSize = 32 * 1024 * 1024; 226 Report("WARNING: Program is run with unlimited stack size, which " 227 "wouldn't work with ThreadSanitizer.\n"); 228 Report("Re-execing with stack size limited to %zd bytes.\n", 229 kMaxStackSize); 230 SetStackSizeLimitInBytes(kMaxStackSize); 231 reexec = true; 232 } 233 234 if (getlim(RLIMIT_AS) != (rlim_t)-1) { 235 Report("WARNING: Program is run with limited virtual address space," 236 " which wouldn't work with ThreadSanitizer.\n"); 237 Report("Re-execing with unlimited virtual address space.\n"); 238 setlim(RLIMIT_AS, -1); 239 reexec = true; 240 } 241 if (reexec) 242 ReExec(); 243 } 244 245#ifndef TSAN_GO 246 CheckPIE(); 247 g_tls_size = (uptr)InitTlsSize(); 248 InitDataSeg(); 249#endif 250 return getenv(kTsanOptionsEnv); 251} 252 253void FinalizePlatform() { 254 fflush(0); 255} 256 257uptr GetTlsSize() { 258#ifndef TSAN_GO 259 return g_tls_size; 260#else 261 return 0; 262#endif 263} 264 265void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 266 uptr *tls_addr, uptr *tls_size) { 267#ifndef TSAN_GO 268 arch_prctl(ARCH_GET_FS, tls_addr); 269 *tls_addr -= g_tls_size; 270 *tls_size = g_tls_size; 271 272 uptr stack_top, stack_bottom; 273 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 274 *stk_addr = stack_bottom; 275 *stk_size = stack_top - stack_bottom; 276 277 if (!main) { 278 // If stack and tls intersect, make them non-intersecting. 279 if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) { 280 CHECK_GT(*tls_addr + *tls_size, *stk_addr); 281 CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size); 282 *stk_size -= *tls_size; 283 *tls_addr = *stk_addr + *stk_size; 284 } 285 } 286#else 287 *stk_addr = 0; 288 *stk_size = 0; 289 *tls_addr = 0; 290 *tls_size = 0; 291#endif 292} 293 294bool IsGlobalVar(uptr addr) { 295 return g_data_start && addr >= g_data_start && addr < g_data_end; 296} 297 298} // namespace __tsan 299 300#endif // #ifdef __linux__ 301