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