llvm/compiler-rt/test/hwasan/TestCases/Linux/fixed-shadow.c

// Test fixed shadow base functionality.
//
// Default compiler instrumentation works with any shadow base (dynamic or fixed).
// RUN: %clang_hwasan %s -o %t
// RUN: %run %t
// RUN: HWASAN_OPTIONS=fixed_shadow_base=263878495698944 %run %t 2>%t.out || (cat %t.out | FileCheck %s)
// RUN: HWASAN_OPTIONS=fixed_shadow_base=4398046511104 %run %t
//
// If -hwasan-mapping-offset is set, then the fixed_shadow_base needs to match.
// RUN: %clang_hwasan %s -mllvm -hwasan-mapping-offset=263878495698944 -o %t
// RUN: HWASAN_OPTIONS=fixed_shadow_base=263878495698944 %run %t 2>%t.out || (cat %t.out | FileCheck %s)
// RUN: HWASAN_OPTIONS=fixed_shadow_base=4398046511104 not %run %t

// RUN: %clang_hwasan %s -mllvm -hwasan-mapping-offset=4398046511104 -o %t
// RUN: HWASAN_OPTIONS=fixed_shadow_base=4398046511104 %run %t
// RUN: HWASAN_OPTIONS=fixed_shadow_base=263878495698944 not %run %t
//
// Note: if fixed_shadow_base is not set, compiler-rt will dynamically choose a
// shadow base, which has a tiny but non-zero probability of matching the
// compiler instrumentation. To avoid test flake, we do not test this case.
//
// Assume 48-bit VMA
// REQUIRES: aarch64-target-arch
//
// REQUIRES: Clang
//
// UNSUPPORTED: android

// CHECK: FATAL: HWAddressSanitizer: Shadow range {{.*}} is not available

#include <assert.h>
#include <sanitizer/allocator_interface.h>
#include <sanitizer/hwasan_interface.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

int main() {
  __hwasan_enable_allocator_tagging();

  // We test that the compiler instrumentation is able to access shadow memory
  // for many different addresses. If we only test a small number of addresses,
  // it might work by chance even if the shadow base does not match between the
  // compiler instrumentation and compiler-rt.
  void **mmaps[256];
  // 48-bit VMA
  for (int i = 0; i < 256; i++) {
    unsigned long long addr = (i * (1ULL << 40));

    void *p = mmap((void *)addr, 4096, PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    // We don't use MAP_FIXED, to avoid overwriting critical memory.
    // However, if we don't get allocated the requested address, it
    // isn't a useful test.
    if ((unsigned long long)p != addr) {
      munmap(p, 4096);
      mmaps[i] = MAP_FAILED;
    } else {
      mmaps[i] = p;
    }
  }

  int failures = 0;
  for (int i = 0; i < 256; i++) {
    if (mmaps[i] == MAP_FAILED) {
      failures++;
    } else {
      printf("%d %p\n", i, mmaps[i]);
      munmap(mmaps[i], 4096);
    }
  }

  // We expect roughly 17 failures:
  // - the page at address zero
  // - 16 failures because the shadow memory takes up 1/16th of the address space
  // We could also get unlucky e.g., if libraries or binaries are loaded into the
  // exact addresses where we tried to map.
  // To avoid test flake, we allow some margin of error.
  printf("Failed: %d\n", failures);
  assert(failures < 48);
  return 0;
}