Home | History | Annotate | Download | only in Linux
      1 // Regression test for
      2 // https://code.google.com/p/chromium/issues/detail?id=446692
      3 // where asan consumed too much RAM due to transparent hugetables.
      4 //
      5 // RUN: %clangxx_asan -g %s -o %t
      6 // RUN: %env_asan_opts=no_huge_pages_for_shadow=1 %run %t 2>&1 | FileCheck %s
      7 // RUN: %run %t 2>&1 | FileCheck %s
      8 //
      9 // Would be great to run the test with no_huge_pages_for_shadow=0, but
     10 // the result will depend on the OS version and settings...
     11 //
     12 // REQUIRES: x86_64-supported-target, asan-64-bits
     13 //
     14 // WARNING: this test is very subtle and may nto work on some systems.
     15 // If this is the case we'll need to futher improve it or disable it.
     16 #include <assert.h>
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <sys/mman.h>
     21 #include <sys/types.h>
     22 #include <sys/stat.h>
     23 #include <fcntl.h>
     24 #include <unistd.h>
     25 #include <errno.h>
     26 #include <sanitizer/asan_interface.h>
     27 
     28 char FileContents[1 << 16];
     29 
     30 void FileToString(const char *path) {
     31   FileContents[0] = 0;
     32   int fd = open(path, 0);
     33   if (fd < 0) return;
     34   char *p = FileContents;
     35   ssize_t size = sizeof(FileContents) - 1;
     36   ssize_t res = 0;
     37   do {
     38     ssize_t got = read (fd, p, size);
     39     if (got == 0)
     40       break;
     41     else if (got > 0)
     42       {
     43         p += got;
     44         res += got;
     45         size -= got;
     46       }
     47     else if (errno != EINTR)
     48       break;
     49   } while (size > 0 && res < sizeof(FileContents));
     50   if (res >= 0)
     51     FileContents[res] = 0;
     52 }
     53 
     54 long ReadShadowRss() {
     55   const char *path = "/proc/self/smaps";
     56   FileToString(path);
     57   char *s = strstr(FileContents, "2008fff7000-10007fff8000");
     58   if (!s) return 0;
     59 
     60   s = strstr(s, "Rss:");
     61   if (!s) return 0;
     62   s = s + 4;
     63   return atol(s);
     64 }
     65 
     66 const int kAllocSize = 1 << 28;  // 256Mb
     67 const int kTwoMb = 1 << 21;
     68 const int kAsanShadowGranularity = 8;
     69 
     70 char *x;
     71 
     72 __attribute__((no_sanitize_address)) void TouchNoAsan(size_t i) { x[i] = 0; }
     73 
     74 int main() {
     75   long rss[5];
     76   rss[0] = ReadShadowRss();
     77   // use mmap directly to avoid asan touching the shadow.
     78   x = (char *)mmap(0, kAllocSize, PROT_READ | PROT_WRITE,
     79                    MAP_PRIVATE | MAP_ANON, 0, 0);
     80   fprintf(stderr, "X: %p-%p\n", x, x + kAllocSize);
     81   rss[1] = ReadShadowRss();
     82 
     83   // Touch the allocated region, but not the shadow.
     84   for (size_t i = 0; i < kAllocSize; i += kTwoMb * kAsanShadowGranularity)
     85     TouchNoAsan(i);
     86   rss[2] = ReadShadowRss();
     87 
     88   // Touch the shadow just a bit, in 2Mb*Granularity steps.
     89   for (size_t i = 0; i < kAllocSize; i += kTwoMb * kAsanShadowGranularity)
     90     __asan_poison_memory_region(x + i, kAsanShadowGranularity);
     91   rss[3] = ReadShadowRss();
     92 
     93   // Touch all the shadow.
     94   __asan_poison_memory_region(x, kAllocSize);
     95   rss[4] = ReadShadowRss();
     96 
     97   // Print the differences.
     98   for (int i = 0; i < 4; i++) {
     99     assert(rss[i] > 0);
    100     assert(rss[i+1] >= rss[i]);
    101     long diff = rss[i+1] / rss[i];
    102     fprintf(stderr, "RSS CHANGE IS %d => %d: %s (%ld vs %ld)\n", i, i + 1,
    103             diff < 10 ? "SMALL" : "LARGE", rss[i], rss[i + 1]);
    104   }
    105 }
    106 // CHECK: RSS CHANGE IS 2 => 3: SMALL
    107 // CHECK: RSS CHANGE IS 3 => 4: LARGE
    108