186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// Regression test for
286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// https://code.google.com/p/chromium/issues/detail?id=446692
386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// where asan consumed too much RAM due to transparent hugetables.
486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//
586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// RUN: %clangxx_asan -g %s -o %t
63d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar// RUN: %env_asan_opts=no_huge_pages_for_shadow=1 %run %t 2>&1 | FileCheck %s
73d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar// RUN: %run %t 2>&1 | FileCheck %s
886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//
986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// Would be great to run the test with no_huge_pages_for_shadow=0, but
1086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// the result will depend on the OS version and settings...
1186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//
1286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// REQUIRES: x86_64-supported-target, asan-64-bits
1386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines//
1486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// WARNING: this test is very subtle and may nto work on some systems.
1586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// If this is the case we'll need to futher improve it or disable it.
1686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <assert.h>
1786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <stdio.h>
1886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <stdlib.h>
1986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <string.h>
2086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <sys/mman.h>
2186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <sys/types.h>
2286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <sys/stat.h>
2386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <fcntl.h>
2486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <unistd.h>
257c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#include <errno.h>
2686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include <sanitizer/asan_interface.h>
2786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
287c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarchar FileContents[1 << 16];
2986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
3086277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid FileToString(const char *path) {
3186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  FileContents[0] = 0;
3286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  int fd = open(path, 0);
3386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (fd < 0) return;
347c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  char *p = FileContents;
357c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  ssize_t size = sizeof(FileContents) - 1;
367c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  ssize_t res = 0;
377c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  do {
387c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    ssize_t got = read (fd, p, size);
397c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    if (got == 0)
407c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar      break;
417c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    else if (got > 0)
427c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar      {
437c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar        p += got;
447c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar        res += got;
457c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar        size -= got;
467c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar      }
477c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    else if (errno != EINTR)
487c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar      break;
497c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  } while (size > 0 && res < sizeof(FileContents));
5086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (res >= 0)
5186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    FileContents[res] = 0;
5286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
5386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
5486277eb844c4983c81de62d7c050e92fe7155788Stephen Hineslong ReadShadowRss() {
5586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  const char *path = "/proc/self/smaps";
5686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  FileToString(path);
5786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  char *s = strstr(FileContents, "2008fff7000-10007fff8000");
5886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (!s) return 0;
5986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
6086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  s = strstr(s, "Rss:");
6186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (!s) return 0;
6286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  s = s + 4;
6386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  return atol(s);
6486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
6586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
6686277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesconst int kAllocSize = 1 << 28;  // 256Mb
6786277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesconst int kTwoMb = 1 << 21;
6886277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesconst int kAsanShadowGranularity = 8;
6986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
7086277eb844c4983c81de62d7c050e92fe7155788Stephen Hineschar *x;
7186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
7286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines__attribute__((no_sanitize_address)) void TouchNoAsan(size_t i) { x[i] = 0; }
7386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesint main() {
7586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  long rss[5];
7686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  rss[0] = ReadShadowRss();
7786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // use mmap directly to avoid asan touching the shadow.
7886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  x = (char *)mmap(0, kAllocSize, PROT_READ | PROT_WRITE,
7986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines                   MAP_PRIVATE | MAP_ANON, 0, 0);
8086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  fprintf(stderr, "X: %p-%p\n", x, x + kAllocSize);
8186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  rss[1] = ReadShadowRss();
8286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
8386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // Touch the allocated region, but not the shadow.
8486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  for (size_t i = 0; i < kAllocSize; i += kTwoMb * kAsanShadowGranularity)
8586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    TouchNoAsan(i);
8686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  rss[2] = ReadShadowRss();
8786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
8886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // Touch the shadow just a bit, in 2Mb*Granularity steps.
8986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  for (size_t i = 0; i < kAllocSize; i += kTwoMb * kAsanShadowGranularity)
9086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    __asan_poison_memory_region(x + i, kAsanShadowGranularity);
9186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  rss[3] = ReadShadowRss();
9286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
9386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // Touch all the shadow.
9486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  __asan_poison_memory_region(x, kAllocSize);
9586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  rss[4] = ReadShadowRss();
9686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
9786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // Print the differences.
9886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  for (int i = 0; i < 4; i++) {
9986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    assert(rss[i] > 0);
10086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    assert(rss[i+1] >= rss[i]);
10186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    long diff = rss[i+1] / rss[i];
10286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    fprintf(stderr, "RSS CHANGE IS %d => %d: %s (%ld vs %ld)\n", i, i + 1,
10386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines            diff < 10 ? "SMALL" : "LARGE", rss[i], rss[i + 1]);
10486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  }
10586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
10686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// CHECK: RSS CHANGE IS 2 => 3: SMALL
10786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// CHECK: RSS CHANGE IS 3 => 4: LARGE
108