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