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