Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: base/process/process_metrics_win.cc

Issue 2289123003: Fixing OOM crash in base::ProcessMetrics::GetWorkingSetKBytes (Closed)
Patch Set: Switched to UncheckedMalloc to avoid OOM crash Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/process/process_metrics.h" 5 #include "base/process/process_metrics.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <psapi.h> 8 #include <psapi.h>
9 #include <stddef.h> 9 #include <stddef.h>
10 #include <stdint.h> 10 #include <stdint.h>
11 #include <winternl.h> 11 #include <winternl.h>
12 12
13 #include <algorithm> 13 #include <algorithm>
14 14
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h" 16 #include "base/memory/ptr_util.h"
17 #include "base/process/memory.h"
17 #include "base/sys_info.h" 18 #include "base/sys_info.h"
18 19
19 namespace base { 20 namespace base {
20 namespace { 21 namespace {
21 22
22 // System pagesize. This value remains constant on x86/64 architectures. 23 // System pagesize. This value remains constant on x86/64 architectures.
23 const int PAGESIZE_KB = 4; 24 const int PAGESIZE_KB = 4;
24 25
25 typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( 26 typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)(
26 SYSTEM_INFORMATION_CLASS SystemInformationClass, 27 SYSTEM_INFORMATION_CLASS SystemInformationClass,
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 usage->priv = 0; 134 usage->priv = 0;
134 return; 135 return;
135 } 136 }
136 base_address = new_base; 137 base_address = new_base;
137 } 138 }
138 usage->image = committed_image / 1024; 139 usage->image = committed_image / 1024;
139 usage->mapped = committed_mapped / 1024; 140 usage->mapped = committed_mapped / 1024;
140 usage->priv = committed_private / 1024; 141 usage->priv = committed_private / 1024;
141 } 142 }
142 143
144 namespace {
145
146 class WorkingSetInformationBuffer {
brucedawson 2016/09/08 20:25:27 Needs to be tagged as no copy/assign.
stanisc 2016/09/08 23:10:14 Done.
147 public:
148 WorkingSetInformationBuffer() {}
149 ~WorkingSetInformationBuffer() { Clear(); }
150
151 bool Reserve(size_t size) {
152 Clear();
153 // Use UncheckedMalloc here because this can be called from the code
154 // that handles low memory condition.
155 return base::UncheckedMalloc(size, &buffer_);
Lei Zhang 2016/09/08 21:19:56 You can omit base:: in namespace base.
stanisc 2016/09/08 23:10:14 Done.
156 }
157
158 PSAPI_WORKING_SET_INFORMATION* get() {
159 return reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(buffer_);
160 }
161
162 const PSAPI_WORKING_SET_INFORMATION* operator ->() const {
163 return reinterpret_cast<const PSAPI_WORKING_SET_INFORMATION*>(buffer_);
164 }
165
166 private:
167 void Clear() {
168 free(buffer_);
169 buffer_ = nullptr;
170 }
171
172 void* buffer_ = nullptr;
Lei Zhang 2016/09/08 21:19:56 If you'd like, you can also use a std::unique_ptr
Lei Zhang 2016/09/08 21:19:57 Can this be a PSAPI_WORKING_SET_INFORMATION* ?
stanisc 2016/09/08 23:10:14 Yeah, I thought about that and even initially impl
Lei Zhang 2016/09/08 23:12:48 Ack. Thanks for explaining.
173 };
174
175 } // namespace
176
143 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { 177 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
144 size_t ws_private = 0; 178 size_t ws_private = 0;
145 size_t ws_shareable = 0; 179 size_t ws_shareable = 0;
146 size_t ws_shared = 0; 180 size_t ws_shared = 0;
147 181
148 DCHECK(ws_usage); 182 DCHECK(ws_usage);
149 memset(ws_usage, 0, sizeof(*ws_usage)); 183 memset(ws_usage, 0, sizeof(*ws_usage));
150 184
151 DWORD number_of_entries = 4096; // Just a guess. 185 DWORD number_of_entries = 4096; // Just a guess.
152 PSAPI_WORKING_SET_INFORMATION* buffer = NULL; 186 WorkingSetInformationBuffer buffer;
153 int retries = 5; 187 int retries = 5;
154 for (;;) { 188 for (;;) {
189
stanisc 2016/09/07 21:41:05 Will remove this empty line.
stanisc 2016/09/08 23:10:14 Done.
155 DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) + 190 DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
156 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); 191 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
157 192
158 // if we can't expand the buffer, don't leak the previous 193 if (!buffer.Reserve(buffer_size))
159 // contents or pass a NULL pointer to QueryWorkingSet
160 PSAPI_WORKING_SET_INFORMATION* new_buffer =
161 reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
162 realloc(buffer, buffer_size));
163 if (!new_buffer) {
164 free(buffer);
165 return false; 194 return false;
166 }
167 buffer = new_buffer;
168 195
169 // Call the function once to get number of items 196 // Call the function once to get number of items
170 if (QueryWorkingSet(process_, buffer, buffer_size)) 197 if (QueryWorkingSet(process_, buffer.get(), buffer_size))
171 break; // Success 198 break; // Success
172 199
173 if (GetLastError() != ERROR_BAD_LENGTH) { 200 if (GetLastError() != ERROR_BAD_LENGTH)
174 free(buffer);
175 return false; 201 return false;
176 }
177 202
178 number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries); 203 number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
179 204
180 // Maybe some entries are being added right now. Increase the buffer to 205 // Maybe some entries are being added right now. Increase the buffer to
181 // take that into account. 206 // take that into account.
Lei Zhang 2016/09/08 21:19:56 Is it helpful to expand the comment to explain how
stanisc 2016/09/08 23:10:15 Done.
182 number_of_entries = static_cast<DWORD>(number_of_entries * 1.25); 207 number_of_entries = static_cast<DWORD>(number_of_entries * 1.1);
183 208
184 if (--retries == 0) { 209 if (--retries == 0) {
185 free(buffer); // If we're looping, eventually fail. 210 // If we're looping, eventually fail.
186 return false; 211 return false;
187 } 212 }
188 } 213 }
189 214
190 // On windows 2000 the function returns 1 even when the buffer is too small. 215 // On windows 2000 the function returns 1 even when the buffer is too small.
191 // The number of entries that we are going to parse is the minimum between the 216 // The number of entries that we are going to parse is the minimum between the
192 // size we allocated and the real number of entries. 217 // size we allocated and the real number of entries.
193 number_of_entries = 218 number_of_entries =
194 std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries)); 219 std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
195 for (unsigned int i = 0; i < number_of_entries; i++) { 220 for (unsigned int i = 0; i < number_of_entries; i++) {
196 if (buffer->WorkingSetInfo[i].Shared) { 221 if (buffer->WorkingSetInfo[i].Shared) {
197 ws_shareable++; 222 ws_shareable++;
198 if (buffer->WorkingSetInfo[i].ShareCount > 1) 223 if (buffer->WorkingSetInfo[i].ShareCount > 1)
199 ws_shared++; 224 ws_shared++;
200 } else { 225 } else {
201 ws_private++; 226 ws_private++;
202 } 227 }
203 } 228 }
204 229
205 ws_usage->priv = ws_private * PAGESIZE_KB; 230 ws_usage->priv = ws_private * PAGESIZE_KB;
206 ws_usage->shareable = ws_shareable * PAGESIZE_KB; 231 ws_usage->shareable = ws_shareable * PAGESIZE_KB;
207 ws_usage->shared = ws_shared * PAGESIZE_KB; 232 ws_usage->shared = ws_shared * PAGESIZE_KB;
208 free(buffer);
209 return true; 233 return true;
210 } 234 }
211 235
212 static uint64_t FileTimeToUTC(const FILETIME& ftime) { 236 static uint64_t FileTimeToUTC(const FILETIME& ftime) {
213 LARGE_INTEGER li; 237 LARGE_INTEGER li;
214 li.LowPart = ftime.dwLowDateTime; 238 li.LowPart = ftime.dwLowDateTime;
215 li.HighPart = ftime.dwHighDateTime; 239 li.HighPart = ftime.dwHighDateTime;
216 return li.QuadPart; 240 return li.QuadPart;
217 } 241 }
218 242
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 319
296 meminfo->total = mem_status.ullTotalPhys / 1024; 320 meminfo->total = mem_status.ullTotalPhys / 1024;
297 meminfo->free = mem_status.ullAvailPhys / 1024; 321 meminfo->free = mem_status.ullAvailPhys / 1024;
298 meminfo->swap_total = mem_status.ullTotalPageFile / 1024; 322 meminfo->swap_total = mem_status.ullTotalPageFile / 1024;
299 meminfo->swap_free = mem_status.ullAvailPageFile / 1024; 323 meminfo->swap_free = mem_status.ullAvailPageFile / 1024;
300 324
301 return true; 325 return true;
302 } 326 }
303 327
304 } // namespace base 328 } // namespace base
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698