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

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

Issue 2289123003: Fixing OOM crash in base::ProcessMetrics::GetWorkingSetKBytes (Closed)
Patch Set: 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 #include <memory>
14 15
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/memory/ptr_util.h" 17 #include "base/memory/ptr_util.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;
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 } 142 }
142 143
143 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const { 144 bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
144 size_t ws_private = 0; 145 size_t ws_private = 0;
145 size_t ws_shareable = 0; 146 size_t ws_shareable = 0;
146 size_t ws_shared = 0; 147 size_t ws_shared = 0;
147 148
148 DCHECK(ws_usage); 149 DCHECK(ws_usage);
149 memset(ws_usage, 0, sizeof(*ws_usage)); 150 memset(ws_usage, 0, sizeof(*ws_usage));
150 151
151 DWORD number_of_entries = 4096; // Just a guess. 152 // Call QueryWorkingSet once to get number of items.
152 PSAPI_WORKING_SET_INFORMATION* buffer = NULL; 153 PSAPI_WORKING_SET_INFORMATION initial_buffer;
154 QueryWorkingSet(process_, &initial_buffer, sizeof(initial_buffer));
155 if (GetLastError() != ERROR_BAD_LENGTH)
156 return false;
157
158 DWORD number_of_entries = static_cast<DWORD>(initial_buffer.NumberOfEntries);
159
160 std::unique_ptr<PSAPI_WORKING_SET_INFORMATION> buffer;
153 int retries = 5; 161 int retries = 5;
154 for (;;) { 162 for (;;) {
163 // Maybe some entries are being added right now. Increase the buffer to
164 // take that into account.
165 number_of_entries = static_cast<DWORD>(number_of_entries * 1.1);
166
155 DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) + 167 DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
156 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK)); 168 (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
157 169
158 // if we can't expand the buffer, don't leak the previous 170 // Allocate the buffer.
159 // contents or pass a NULL pointer to QueryWorkingSet 171 DCHECK(!buffer.get());
160 PSAPI_WORKING_SET_INFORMATION* new_buffer = 172 buffer.reset(reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
161 reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>( 173 new uint8_t[buffer_size]));
brucedawson 2016/09/07 00:41:12 This seems slightly dodgy, using unique_ptr to hol
162 realloc(buffer, buffer_size));
163 if (!new_buffer) {
164 free(buffer);
165 return false;
166 }
167 buffer = new_buffer;
168 174
169 // Call the function once to get number of items 175 // Call the function once to get number of items
170 if (QueryWorkingSet(process_, buffer, buffer_size)) 176 if (QueryWorkingSet(process_, buffer.get(), buffer_size))
171 break; // Success 177 break; // Success
172 178
173 if (GetLastError() != ERROR_BAD_LENGTH) { 179 if (GetLastError() != ERROR_BAD_LENGTH)
174 free(buffer);
175 return false; 180 return false;
176 }
177 181
182 // Need to grow the number of entries.
178 number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries); 183 number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
179 184 // Free the current buffer before allocating one with larger size.
180 // Maybe some entries are being added right now. Increase the buffer to 185 buffer.reset();
181 // take that into account.
182 number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
183 186
184 if (--retries == 0) { 187 if (--retries == 0) {
185 free(buffer); // If we're looping, eventually fail. 188 // If we're looping, eventually fail.
186 return false; 189 return false;
187 } 190 }
188 } 191 }
189 192
190 // On windows 2000 the function returns 1 even when the buffer is too small. 193 // 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 194 // 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. 195 // size we allocated and the real number of entries.
193 number_of_entries = 196 number_of_entries =
194 std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries)); 197 std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
195 for (unsigned int i = 0; i < number_of_entries; i++) { 198 for (unsigned int i = 0; i < number_of_entries; i++) {
196 if (buffer->WorkingSetInfo[i].Shared) { 199 if (buffer->WorkingSetInfo[i].Shared) {
197 ws_shareable++; 200 ws_shareable++;
198 if (buffer->WorkingSetInfo[i].ShareCount > 1) 201 if (buffer->WorkingSetInfo[i].ShareCount > 1)
199 ws_shared++; 202 ws_shared++;
200 } else { 203 } else {
201 ws_private++; 204 ws_private++;
202 } 205 }
203 } 206 }
204 207
205 ws_usage->priv = ws_private * PAGESIZE_KB; 208 ws_usage->priv = ws_private * PAGESIZE_KB;
206 ws_usage->shareable = ws_shareable * PAGESIZE_KB; 209 ws_usage->shareable = ws_shareable * PAGESIZE_KB;
207 ws_usage->shared = ws_shared * PAGESIZE_KB; 210 ws_usage->shared = ws_shared * PAGESIZE_KB;
208 free(buffer);
209 return true; 211 return true;
210 } 212 }
211 213
212 static uint64_t FileTimeToUTC(const FILETIME& ftime) { 214 static uint64_t FileTimeToUTC(const FILETIME& ftime) {
213 LARGE_INTEGER li; 215 LARGE_INTEGER li;
214 li.LowPart = ftime.dwLowDateTime; 216 li.LowPart = ftime.dwLowDateTime;
215 li.HighPart = ftime.dwHighDateTime; 217 li.HighPart = ftime.dwHighDateTime;
216 return li.QuadPart; 218 return li.QuadPart;
217 } 219 }
218 220
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 297
296 meminfo->total = mem_status.ullTotalPhys / 1024; 298 meminfo->total = mem_status.ullTotalPhys / 1024;
297 meminfo->free = mem_status.ullAvailPhys / 1024; 299 meminfo->free = mem_status.ullAvailPhys / 1024;
298 meminfo->swap_total = mem_status.ullTotalPageFile / 1024; 300 meminfo->swap_total = mem_status.ullTotalPageFile / 1024;
299 meminfo->swap_free = mem_status.ullAvailPageFile / 1024; 301 meminfo->swap_free = mem_status.ullAvailPageFile / 1024;
300 302
301 return true; 303 return true;
302 } 304 }
303 305
304 } // namespace base 306 } // 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