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
28char FileContents[1 << 16];
29
30void FileToString(const char *path) {
31 FileContents[0] = 0;
32 int fd = open(file: path, oflag: 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: fd, buf: p, nbytes: 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
54long ReadShadowRss() {
55 const char *path = "/proc/self/smaps";
56 FileToString(path);
57 char *s = strstr(haystack: FileContents, needle: "2008fff7000-10007fff8000");
58 if (!s) return 0;
59
60 s = strstr(haystack: s, needle: "Rss:");
61 if (!s) return 0;
62 s = s + 4;
63 return atol(nptr: s);
64}
65
66const int kAllocSize = 1 << 28; // 256Mb
67const int kTwoMb = 1 << 21;
68const int kAsanShadowGranularity = 8;
69
70char *x;
71
72__attribute__((no_sanitize_address)) void TouchNoAsan(size_t i) { x[i] = 0; }
73
74int main() {
75 long rss[5];
76 rss[0] = ReadShadowRss();
77 // use mmap directly to avoid asan touching the shadow.
78 x = (char *)mmap(addr: 0, len: kAllocSize, PROT_READ | PROT_WRITE,
79 MAP_PRIVATE | MAP_ANON, fd: 0, offset: 0);
80 fprintf(stderr, format: "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(addr: x + i, size: kAsanShadowGranularity);
91 rss[3] = ReadShadowRss();
92
93 // Touch all the shadow.
94 __asan_poison_memory_region(addr: x, size: 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, format: "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

source code of compiler-rt/test/asan/TestCases/Linux/nohugepage_test.cpp