Home | History | Annotate | Download | only in rtl
      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 
     47 extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
     48 extern "C" struct mallinfo __libc_mallinfo();
     49 
     50 namespace __tsan {
     51 
     52 #ifndef TSAN_GO
     53 ScopedInRtl::ScopedInRtl()
     54     : thr_(cur_thread()) {
     55   in_rtl_ = thr_->in_rtl;
     56   thr_->in_rtl++;
     57   errno_ = errno;
     58 }
     59 
     60 ScopedInRtl::~ScopedInRtl() {
     61   thr_->in_rtl--;
     62   errno = errno_;
     63   CHECK_EQ(in_rtl_, thr_->in_rtl);
     64 }
     65 #else
     66 ScopedInRtl::ScopedInRtl() {
     67 }
     68 
     69 ScopedInRtl::~ScopedInRtl() {
     70 }
     71 #endif
     72 
     73 static bool ishex(char c) {
     74   return (c >= '0' && c <= '9')
     75       || (c >= 'a' && c <= 'f');
     76 }
     77 
     78 static 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 
     89 static 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 
     96 void 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 
    144 void FlushShadowMemory() {
    145   FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
    146 }
    147 
    148 #ifndef TSAN_GO
    149 static 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
    163 void 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 
    192 static uptr g_data_start;
    193 static uptr g_data_end;
    194 
    195 #ifndef TSAN_GO
    196 static 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 
    214 static 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 
    241 static rlim_t getlim(int res) {
    242   rlimit rlim;
    243   CHECK_EQ(0, getrlimit(res, &rlim));
    244   return rlim.rlim_cur;
    245 }
    246 
    247 static 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 
    255 const 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 
    299 void FinalizePlatform() {
    300   fflush(0);
    301 }
    302 
    303 void 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 
    332 bool IsGlobalVar(uptr addr) {
    333   return g_data_start && addr >= g_data_start && addr < g_data_end;
    334 }
    335 
    336 #ifndef TSAN_GO
    337 int 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