1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/base/page_allocator.h"
18
19#include <stdint.h>
20#include <sys/mman.h>
21#include <sys/types.h>
22
23#include "gtest/gtest.h"
24#include "perfetto/base/build_config.h"
25#include "src/base/test/vm_test_utils.h"
26
27#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
28#include <sys/resource.h>
29#endif
30
31namespace perfetto {
32namespace base {
33namespace {
34
35TEST(PageAllocatorTest, Basic) {
36  const size_t kNumPages = 10;
37  const size_t kSize = 4096 * kNumPages;
38  void* ptr_raw = nullptr;
39  {
40    PageAllocator::UniquePtr ptr = PageAllocator::Allocate(kSize);
41    ASSERT_TRUE(ptr);
42    ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(ptr.get()) % 4096);
43    ptr_raw = ptr.get();
44    for (size_t i = 0; i < kSize / sizeof(uint64_t); i++)
45      ASSERT_EQ(0u, *(reinterpret_cast<uint64_t*>(ptr.get()) + i));
46
47    ASSERT_TRUE(vm_test_utils::IsMapped(ptr_raw, kSize));
48  }
49
50  ASSERT_FALSE(vm_test_utils::IsMapped(ptr_raw, kSize));
51}
52
53TEST(PageAllocatorTest, GuardRegions) {
54  const size_t kSize = 4096;
55  PageAllocator::UniquePtr ptr = PageAllocator::Allocate(kSize);
56  ASSERT_TRUE(ptr);
57  volatile char* raw = reinterpret_cast<char*>(ptr.get());
58  EXPECT_DEATH({ raw[-1] = 'x'; }, ".*");
59  EXPECT_DEATH({ raw[kSize] = 'x'; }, ".*");
60}
61
62// Disable this on:
63// MacOS: because it doesn't seem to have an equivalent rlimit to bound mmap().
64// Sanitizers: they seem to try to shadow mmaped memory and fail due to OOMs.
65#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) && !defined(ADDRESS_SANITIZER) && \
66    !defined(LEAK_SANITIZER) && !defined(THREAD_SANITIZER) &&                 \
67    !defined(MEMORY_SANITIZER)
68// Glibc headers hit this on RLIMIT_ macros.
69#pragma GCC diagnostic push
70#if defined(__clang__)
71#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
72#endif
73TEST(PageAllocatorTest, Unchecked) {
74  const size_t kMemLimit = 256 * 1024 * 1024l;
75  struct rlimit limit {
76    kMemLimit, kMemLimit
77  };
78  // ASSERT_EXIT here is to spawn the test in a sub-process and avoid
79  // propagating the setrlimit() to other test units in case of failure.
80  ASSERT_EXIT(
81      {
82        ASSERT_EQ(0, setrlimit(RLIMIT_AS, &limit));
83        auto ptr = PageAllocator::AllocateMayFail(kMemLimit * 2);
84        ASSERT_FALSE(ptr);
85        exit(0);
86      },
87      ::testing::ExitedWithCode(0), "");
88}
89#pragma GCC diagnostic pop
90#endif
91
92}  // namespace
93}  // namespace base
94}  // namespace perfetto
95