1d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Use of this source code is governed by a BSD-style license that can be 3d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// found in the LICENSE file. 4d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 5d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/base/allocator/partition_allocator/page_allocator.h" 6d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 7d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <limits.h> 8d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 9d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <atomic> 10d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 11d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/base/allocator/partition_allocator/address_space_randomization.h" 12d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/base/base_export.h" 13d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/base/logging.h" 14d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/build/build_config.h" 15d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 16d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 17d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 18d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <errno.h> 19d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <sys/mman.h> 20d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 21d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifndef MADV_FREE 22d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#define MADV_FREE MADV_DONTNEED 23d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 24d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 25d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#ifndef MAP_ANONYMOUS 26d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#define MAP_ANONYMOUS MAP_ANON 27d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 28d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 29d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// On POSIX |mmap| uses a nearby address if the hint address is blocked. 30d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstatic const bool kHintIsAdvisory = true; 31d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstatic std::atomic<int32_t> s_allocPageErrorCode{0}; 32d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 33d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#elif defined(OS_WIN) 34d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 35d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <windows.h> 36d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 37d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// |VirtualAlloc| will fail if allocation at the hint address is blocked. 38d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstatic const bool kHintIsAdvisory = false; 39d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstatic std::atomic<int32_t> s_allocPageErrorCode{ERROR_SUCCESS}; 40d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 41d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 42d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#error Unknown OS 43d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif // defined(OS_POSIX) 44d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 45d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannnamespace pdfium { 46d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannnamespace base { 47d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 48d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// This internal function wraps the OS-specific page allocation call: 49d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// |VirtualAlloc| on Windows, and |mmap| on POSIX. 50d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstatic void* SystemAllocPages( 51d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann void* hint, 52d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t length, 53d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann PageAccessibilityConfiguration page_accessibility) { 54d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kPageAllocationGranularityOffsetMask)); 55d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(reinterpret_cast<uintptr_t>(hint) & 56d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann kPageAllocationGranularityOffsetMask)); 57d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann void* ret; 58d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_WIN) 59d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DWORD access_flag = 60d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann page_accessibility == PageAccessible ? PAGE_READWRITE : PAGE_NOACCESS; 61d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = VirtualAlloc(hint, length, MEM_RESERVE | MEM_COMMIT, access_flag); 62d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (!ret) 63d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann s_allocPageErrorCode = GetLastError(); 64d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 65d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann int access_flag = page_accessibility == PageAccessible 66d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ? (PROT_READ | PROT_WRITE) 67d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann : PROT_NONE; 68d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = mmap(hint, length, access_flag, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 69d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (ret == MAP_FAILED) { 70d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann s_allocPageErrorCode = errno; 71d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = 0; 72d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 73d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 74d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return ret; 75d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 76d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 77d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// Trims base to given length and alignment. Windows returns null on failure and 78d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann// frees base. 79d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstatic void* TrimMapping(void* base, 80d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t base_length, 81d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t trim_length, 82d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann uintptr_t align, 83d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann PageAccessibilityConfiguration page_accessibility) { 84d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t pre_slack = reinterpret_cast<uintptr_t>(base) & (align - 1); 85d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (pre_slack) 86d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann pre_slack = align - pre_slack; 87d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t post_slack = base_length - pre_slack - trim_length; 88d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(base_length >= trim_length || pre_slack || post_slack); 89d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(pre_slack < base_length); 90d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(post_slack < base_length); 91d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann void* ret = base; 92d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 93d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) // On POSIX we can resize the allocation run. 94d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann (void)page_accessibility; 95d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (pre_slack) { 96d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann int res = munmap(base, pre_slack); 97d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(!res); 98d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = reinterpret_cast<char*>(base) + pre_slack; 99d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 100d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (post_slack) { 101d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann int res = munmap(reinterpret_cast<char*>(ret) + trim_length, post_slack); 102d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(!res); 103d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 104d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else // On Windows we can't resize the allocation run. 105d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (pre_slack || post_slack) { 106d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = reinterpret_cast<char*>(base) + pre_slack; 107d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann FreePages(base, base_length); 108d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = SystemAllocPages(ret, trim_length, page_accessibility); 109d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 110d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 111d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 112d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return ret; 113d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 114d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 115d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid* AllocPages(void* address, 116d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t length, 117d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t align, 118d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann PageAccessibilityConfiguration page_accessibility) { 119d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(length >= kPageAllocationGranularity); 120d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kPageAllocationGranularityOffsetMask)); 121d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(align >= kPageAllocationGranularity); 122d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(align & kPageAllocationGranularityOffsetMask)); 123d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(reinterpret_cast<uintptr_t>(address) & 124d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann kPageAllocationGranularityOffsetMask)); 125d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann uintptr_t align_offset_mask = align - 1; 126d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann uintptr_t align_base_mask = ~align_offset_mask; 127d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(reinterpret_cast<uintptr_t>(address) & align_offset_mask)); 128d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 129d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // If the client passed null as the address, choose a good one. 130d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (!address) { 131d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = GetRandomPageBase(); 132d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) & 133d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann align_base_mask); 134d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 135d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 136d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // First try to force an exact-size, aligned allocation from our random base. 137d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann for (int count = 0; count < 3; ++count) { 138d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann void* ret = SystemAllocPages(address, length, page_accessibility); 139d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (kHintIsAdvisory || ret) { 140d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // If the alignment is to our liking, we're done. 141d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (!(reinterpret_cast<uintptr_t>(ret) & align_offset_mask)) 142d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return ret; 143d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann FreePages(ret, length); 144d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(ARCH_CPU_32_BITS) 145d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = reinterpret_cast<void*>( 146d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann (reinterpret_cast<uintptr_t>(ret) + align) & align_base_mask); 147d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 148d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } else if (!address) { // We know we're OOM when an unhinted allocation 149d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // fails. 150d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return nullptr; 151d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } else { 152d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(ARCH_CPU_32_BITS) 153d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = reinterpret_cast<char*>(address) + align; 154d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 155d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 156d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 157d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if !defined(ARCH_CPU_32_BITS) 158d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // Keep trying random addresses on systems that have a large address space. 159d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = GetRandomPageBase(); 160d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) & 161d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann align_base_mask); 162d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 163d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 164d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 165d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // Map a larger allocation so we can force alignment, but continue randomizing 166d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // only on 64-bit POSIX. 167d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann size_t try_length = length + (align - kPageAllocationGranularity); 168d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(try_length >= length); 169d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann void* ret; 170d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 171d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann do { 172d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // Don't continue to burn cycles on mandatory hints (Windows). 173d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann address = kHintIsAdvisory ? GetRandomPageBase() : nullptr; 174d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = SystemAllocPages(address, try_length, page_accessibility); 175d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // The retries are for Windows, where a race can steal our mapping on 176d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // resize. 177d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } while (ret && 178d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann (ret = TrimMapping(ret, try_length, length, align, 179d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann page_accessibility)) == nullptr); 180d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 181d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return ret; 182d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 183d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 184d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid FreePages(void* address, size_t length) { 185d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(reinterpret_cast<uintptr_t>(address) & 186d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann kPageAllocationGranularityOffsetMask)); 187d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kPageAllocationGranularityOffsetMask)); 188d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 189d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann int ret = munmap(address, length); 190d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(!ret); 191d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 192d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann BOOL ret = VirtualFree(address, 0, MEM_RELEASE); 193d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(ret); 194d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 195d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 196d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 197d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid SetSystemPagesInaccessible(void* address, size_t length) { 198d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kSystemPageOffsetMask)); 199d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 200d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann int ret = mprotect(address, length, PROT_NONE); 201d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(!ret); 202d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 203d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann BOOL ret = VirtualFree(address, length, MEM_DECOMMIT); 204d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(ret); 205d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 206d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 207d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 208d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannbool SetSystemPagesAccessible(void* address, size_t length) { 209d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kSystemPageOffsetMask)); 210d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 211d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return !mprotect(address, length, PROT_READ | PROT_WRITE); 212d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 213d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return !!VirtualAlloc(address, length, MEM_COMMIT, PAGE_READWRITE); 214d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 215d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 216d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 217d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid DecommitSystemPages(void* address, size_t length) { 218d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kSystemPageOffsetMask)); 219d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 220d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann int ret = madvise(address, length, MADV_FREE); 221d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (ret != 0 && errno == EINVAL) { 222d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // MADV_FREE only works on Linux 4.5+ . If request failed, 223d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // retry with older MADV_DONTNEED . Note that MADV_FREE 224d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // being defined at compile time doesn't imply runtime support. 225d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = madvise(address, length, MADV_DONTNEED); 226d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 227d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(!ret); 228d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 229d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann SetSystemPagesInaccessible(address, length); 230d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 231d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 232d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 233d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid RecommitSystemPages(void* address, size_t length) { 234d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kSystemPageOffsetMask)); 235d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 236d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann (void)address; 237d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 238d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(SetSystemPagesAccessible(address, length)); 239d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 240d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 241d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 242d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid DiscardSystemPages(void* address, size_t length) { 243d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DCHECK(!(length & kSystemPageOffsetMask)); 244d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if defined(OS_POSIX) 245d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // On POSIX, the implementation detail is that discard and decommit are the 246d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // same, and lead to pages that are returned to the system immediately and 247d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // get replaced with zeroed pages when touched. So we just call 248d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // DecommitSystemPages() here to avoid code duplication. 249d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DecommitSystemPages(address, length); 250d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#else 251d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // On Windows discarded pages are not returned to the system immediately and 252d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // not guaranteed to be zeroed when returned to the application. 253d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann using DiscardVirtualMemoryFunction = 254d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size); 255d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann static DiscardVirtualMemoryFunction discard_virtual_memory = 256d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann reinterpret_cast<DiscardVirtualMemoryFunction>(-1); 257d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (discard_virtual_memory == 258d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann reinterpret_cast<DiscardVirtualMemoryFunction>(-1)) 259d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann discard_virtual_memory = 260d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress( 261d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory")); 262d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // Use DiscardVirtualMemory when available because it releases faster than 263d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // MEM_RESET. 264d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann DWORD ret = 1; 265d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (discard_virtual_memory) 266d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann ret = discard_virtual_memory(address, length); 267d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on 268d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann // failure. 269d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann if (ret) { 270d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann void* ret = VirtualAlloc(address, length, MEM_RESET, PAGE_READWRITE); 271d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann CHECK(ret); 272d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann } 273d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif 274d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 275d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 276d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannuint32_t GetAllocPageErrorCode() { 277d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann return s_allocPageErrorCode; 278d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} 279d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann 280d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} // namespace base 281d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann} // namespace pdfium 282