• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace perfetto {
32 namespace base {
33 namespace {
34 
TEST(PageAllocatorTest,Basic)35 TEST(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 
TEST(PageAllocatorTest,GuardRegions)53 TEST(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
TEST(PageAllocatorTest,Unchecked)73 TEST(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