• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_
6 #define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_
7 
8 #include "third_party/base/allocator/partition_allocator/oom.h"
9 #include "third_party/base/allocator/partition_allocator/page_allocator_internal.h"
10 
11 namespace pdfium {
12 namespace base {
13 
14 // |VirtualAlloc| will fail if allocation at the hint address is blocked.
15 constexpr bool kHintIsAdvisory = false;
16 std::atomic<int32_t> s_allocPageErrorCode{ERROR_SUCCESS};
17 
GetAccessFlags(PageAccessibilityConfiguration accessibility)18 int GetAccessFlags(PageAccessibilityConfiguration accessibility) {
19   switch (accessibility) {
20     case PageRead:
21       return PAGE_READONLY;
22     case PageReadWrite:
23       return PAGE_READWRITE;
24     case PageReadExecute:
25       return PAGE_EXECUTE_READ;
26     case PageReadWriteExecute:
27       return PAGE_EXECUTE_READWRITE;
28     default:
29       NOTREACHED();
30       FALLTHROUGH;
31     case PageInaccessible:
32       return PAGE_NOACCESS;
33   }
34 }
35 
SystemAllocPagesInternal(void * hint,size_t length,PageAccessibilityConfiguration accessibility,PageTag page_tag,bool commit)36 void* SystemAllocPagesInternal(void* hint,
37                                size_t length,
38                                PageAccessibilityConfiguration accessibility,
39                                PageTag page_tag,
40                                bool commit) {
41   DWORD access_flag = GetAccessFlags(accessibility);
42   const DWORD type_flags = commit ? (MEM_RESERVE | MEM_COMMIT) : MEM_RESERVE;
43   void* ret = VirtualAlloc(hint, length, type_flags, access_flag);
44   if (ret == nullptr) {
45     s_allocPageErrorCode = GetLastError();
46   }
47   return ret;
48 }
49 
TrimMappingInternal(void * base,size_t base_length,size_t trim_length,PageAccessibilityConfiguration accessibility,bool commit,size_t pre_slack,size_t post_slack)50 void* TrimMappingInternal(void* base,
51                           size_t base_length,
52                           size_t trim_length,
53                           PageAccessibilityConfiguration accessibility,
54                           bool commit,
55                           size_t pre_slack,
56                           size_t post_slack) {
57   void* ret = base;
58   if (pre_slack || post_slack) {
59     // We cannot resize the allocation run. Free it and retry at the aligned
60     // address within the freed range.
61     ret = reinterpret_cast<char*>(base) + pre_slack;
62     FreePages(base, base_length);
63     ret = SystemAllocPages(ret, trim_length, accessibility, PageTag::kChromium,
64                            commit);
65   }
66   return ret;
67 }
68 
TrySetSystemPagesAccessInternal(void * address,size_t length,PageAccessibilityConfiguration accessibility)69 bool TrySetSystemPagesAccessInternal(
70     void* address,
71     size_t length,
72     PageAccessibilityConfiguration accessibility) {
73   if (accessibility == PageInaccessible)
74     return VirtualFree(address, length, MEM_DECOMMIT) != 0;
75   return nullptr != VirtualAlloc(address, length, MEM_COMMIT,
76                                  GetAccessFlags(accessibility));
77 }
78 
SetSystemPagesAccessInternal(void * address,size_t length,PageAccessibilityConfiguration accessibility)79 void SetSystemPagesAccessInternal(
80     void* address,
81     size_t length,
82     PageAccessibilityConfiguration accessibility) {
83   if (accessibility == PageInaccessible) {
84     if (!VirtualFree(address, length, MEM_DECOMMIT)) {
85       // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
86       // report we get the error number.
87       CHECK_EQ(static_cast<uint32_t>(ERROR_SUCCESS), GetLastError());
88     }
89   } else {
90     if (!VirtualAlloc(address, length, MEM_COMMIT,
91                       GetAccessFlags(accessibility))) {
92       int32_t error = GetLastError();
93       if (error == ERROR_COMMITMENT_LIMIT)
94         OOM_CRASH();
95       // We check `GetLastError` for `ERROR_SUCCESS` here so that in a crash
96       // report we get the error number.
97       CHECK_EQ(ERROR_SUCCESS, error);
98     }
99   }
100 }
101 
FreePagesInternal(void * address,size_t length)102 void FreePagesInternal(void* address, size_t length) {
103   CHECK(VirtualFree(address, 0, MEM_RELEASE));
104 }
105 
DecommitSystemPagesInternal(void * address,size_t length)106 void DecommitSystemPagesInternal(void* address, size_t length) {
107   SetSystemPagesAccess(address, length, PageInaccessible);
108 }
109 
RecommitSystemPagesInternal(void * address,size_t length,PageAccessibilityConfiguration accessibility)110 bool RecommitSystemPagesInternal(void* address,
111                                  size_t length,
112                                  PageAccessibilityConfiguration accessibility) {
113   return TrySetSystemPagesAccess(address, length, accessibility);
114 }
115 
DiscardSystemPagesInternal(void * address,size_t length)116 void DiscardSystemPagesInternal(void* address, size_t length) {
117   // On Windows, discarded pages are not returned to the system immediately and
118   // not guaranteed to be zeroed when returned to the application.
119   using DiscardVirtualMemoryFunction =
120       DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size);
121   static DiscardVirtualMemoryFunction discard_virtual_memory =
122       reinterpret_cast<DiscardVirtualMemoryFunction>(-1);
123   if (discard_virtual_memory ==
124       reinterpret_cast<DiscardVirtualMemoryFunction>(-1))
125     discard_virtual_memory =
126         reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress(
127             GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory"));
128   // Use DiscardVirtualMemory when available because it releases faster than
129   // MEM_RESET.
130   DWORD ret = 1;
131   if (discard_virtual_memory) {
132     ret = discard_virtual_memory(address, length);
133   }
134   // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on
135   // failure.
136   if (ret) {
137     void* ptr = VirtualAlloc(address, length, MEM_RESET, PAGE_READWRITE);
138     CHECK(ptr);
139   }
140 }
141 
142 }  // namespace base
143 }  // namespace pdfium
144 
145 #endif  // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_
146