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-target-arch, shadow-scale-3
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 
FileToString(const char * path)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 
ReadShadowRss()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 
TouchNoAsan(size_t i)72 __attribute__((no_sanitize_address)) void TouchNoAsan(size_t i) { x[i] = 0; }
73 
main()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