OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 // Static class for hooking Win32 API routines. | 5 // Static class for hooking Win32 API routines. |
6 | 6 |
7 // Some notes about how to hook Memory Allocation Routines in Windows. | 7 // Some notes about how to hook Memory Allocation Routines in Windows. |
8 // | 8 // |
9 // For our purposes we do not hook the libc routines. There are two | 9 // For our purposes we do not hook the libc routines. There are two |
10 // reasons for this. First, the libc routines all go through HeapAlloc | 10 // reasons for this. First, the libc routines all go through HeapAlloc |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 } | 210 } |
211 | 211 |
212 static LPVOID WINAPI Perftools_HeapReAlloc(HANDLE hHeap, DWORD dwFlags, | 212 static LPVOID WINAPI Perftools_HeapReAlloc(HANDLE hHeap, DWORD dwFlags, |
213 LPVOID lpMem, SIZE_T dwBytes) { | 213 LPVOID lpMem, SIZE_T dwBytes) { |
214 // Don't call realloc, but instead do a free/malloc. The problem is that | 214 // Don't call realloc, but instead do a free/malloc. The problem is that |
215 // the builtin realloc may either expand a buffer, or it may simply | 215 // the builtin realloc may either expand a buffer, or it may simply |
216 // just call free/malloc. If so, we will already have tracked the new | 216 // just call free/malloc. If so, we will already have tracked the new |
217 // block via Perftools_HeapAlloc. | 217 // block via Perftools_HeapAlloc. |
218 | 218 |
219 LPVOID rv = Perftools_HeapAlloc(hHeap, dwFlags, dwBytes); | 219 LPVOID rv = Perftools_HeapAlloc(hHeap, dwFlags, dwBytes); |
| 220 DCHECK_EQ((HEAP_REALLOC_IN_PLACE_ONLY & dwFlags), 0); |
220 | 221 |
221 // If there was an old buffer, now copy the data to the new buffer. | 222 // If there was an old buffer, now copy the data to the new buffer. |
222 if (lpMem != 0) { | 223 if (lpMem != 0) { |
223 size_t size = HeapSize(hHeap, 0, lpMem); | 224 size_t size = HeapSize(hHeap, 0, lpMem); |
224 if (size > dwBytes) | 225 if (size > dwBytes) |
225 size = dwBytes; | 226 size = dwBytes; |
226 // Note: size could be 0; HeapAlloc does allocate 0 length buffers. | 227 // Note: size could be 0; HeapAlloc does allocate 0 length buffers. |
227 memcpy(rv, lpMem, size); | 228 memcpy(rv, lpMem, size); |
228 Perftools_HeapFree(hHeap, dwFlags, lpMem); | 229 Perftools_HeapFree(hHeap, dwFlags, lpMem); |
229 } | 230 } |
230 return rv; | 231 return rv; |
231 } | 232 } |
232 | 233 |
233 static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address, | 234 static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address, |
234 SIZE_T size, DWORD type, | 235 SIZE_T size, DWORD type, |
235 DWORD protect) { | 236 DWORD protect) { |
236 bool already_committed = false; | 237 bool already_committed = false; |
237 if (address != NULL) { | 238 if (address != NULL) { |
238 MEMORY_BASIC_INFORMATION info; | 239 MEMORY_BASIC_INFORMATION info; |
239 CHECK(VirtualQuery(address, &info, sizeof(info))); | 240 CHECK(VirtualQuery(address, &info, sizeof(info))); |
240 if (info.State & MEM_COMMIT) | 241 if (info.State & MEM_COMMIT) { |
241 already_committed = true; | 242 already_committed = true; |
| 243 CHECK(size >= info.RegionSize); |
| 244 } |
242 } | 245 } |
243 bool reserving = (address == NULL) || (type & MEM_RESERVE); | 246 bool reserving = (address == NULL) || (type & MEM_RESERVE); |
244 bool committing = !already_committed && (type & MEM_COMMIT); | 247 bool committing = !already_committed && (type & MEM_COMMIT); |
245 | 248 |
246 | 249 |
247 LPVOID result = patch_VirtualAllocEx()(process, address, size, type, | 250 LPVOID result = patch_VirtualAllocEx()(process, address, size, type, |
248 protect); | 251 protect); |
249 MEMORY_BASIC_INFORMATION info; | 252 MEMORY_BASIC_INFORMATION info; |
250 CHECK(VirtualQuery(result, &info, sizeof(info))); | 253 CHECK(VirtualQuery(result, &info, sizeof(info))); |
251 size = info.RegionSize; | 254 size = info.RegionSize; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 HGLOBAL rv = patch_GlobalAlloc()(uFlags, dwBytes); | 351 HGLOBAL rv = patch_GlobalAlloc()(uFlags, dwBytes); |
349 return rv; | 352 return rv; |
350 } | 353 } |
351 | 354 |
352 static HGLOBAL WINAPI Perftools_GlobalFree(HGLOBAL hMem) { | 355 static HGLOBAL WINAPI Perftools_GlobalFree(HGLOBAL hMem) { |
353 return patch_GlobalFree()(hMem); | 356 return patch_GlobalFree()(hMem); |
354 } | 357 } |
355 | 358 |
356 static HGLOBAL WINAPI Perftools_GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, | 359 static HGLOBAL WINAPI Perftools_GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, |
357 UINT uFlags) { | 360 UINT uFlags) { |
| 361 // TODO(jar): [The following looks like a copy/paste typo from LocalRealloc.] |
358 // GlobalDiscard is a macro which calls LocalReAlloc with size 0. | 362 // GlobalDiscard is a macro which calls LocalReAlloc with size 0. |
359 if (dwBytes == 0) { | 363 if (dwBytes == 0) { |
360 return patch_GlobalReAlloc()(hMem, dwBytes, uFlags); | 364 return patch_GlobalReAlloc()(hMem, dwBytes, uFlags); |
361 } | 365 } |
362 | 366 |
363 HGLOBAL rv = Perftools_GlobalAlloc(uFlags, dwBytes); | 367 HGLOBAL rv = Perftools_GlobalAlloc(uFlags, dwBytes); |
364 if (hMem != 0) { | 368 if (hMem != 0) { |
365 size_t size = GlobalSize(hMem); | 369 size_t size = GlobalSize(hMem); |
366 if (size > dwBytes) | 370 if (size > dwBytes) |
367 size = dwBytes; | 371 size = dwBytes; |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 Hook(); | 512 Hook(); |
509 | 513 |
510 DCHECK(global_hook_); | 514 DCHECK(global_hook_); |
511 global_hook_->watcher_ = watcher; | 515 global_hook_->watcher_ = watcher; |
512 return true; | 516 return true; |
513 } | 517 } |
514 | 518 |
515 bool MemoryHook::UnregisterWatcher(MemoryObserver* watcher) { | 519 bool MemoryHook::UnregisterWatcher(MemoryObserver* watcher) { |
516 DCHECK(hooked_); | 520 DCHECK(hooked_); |
517 DCHECK(global_hook_->watcher_ == watcher); | 521 DCHECK(global_hook_->watcher_ == watcher); |
| 522 // TODO(jar): changing watcher_ here is very racy. Other threads may (without |
| 523 // a lock) testing, and then calling through this value. We probably can't |
| 524 // remove this until we are single threaded. |
518 global_hook_->watcher_ = NULL; | 525 global_hook_->watcher_ = NULL; |
519 | 526 |
520 // For now, since there are no more watchers, unhook memory. | 527 // For now, since there are no more watchers, unhook memory. |
521 return Unhook(); | 528 return Unhook(); |
522 } | 529 } |
523 | 530 |
524 bool MemoryHook::CreateHeap() { | 531 bool MemoryHook::CreateHeap() { |
525 // Create a heap for our own memory. | 532 // Create a heap for our own memory. |
526 DCHECK(heap_ == NULL); | 533 DCHECK(heap_ == NULL); |
527 heap_ = HeapCreate(0, 0, 0); | 534 heap_ = HeapCreate(0, 0, 0); |
(...skipping 18 matching lines...) Expand all Loading... |
546 } | 553 } |
547 | 554 |
548 void MemoryHook::OnUntrack(HANDLE heap, int32 id, int32 size) { | 555 void MemoryHook::OnUntrack(HANDLE heap, int32 id, int32 size) { |
549 // Don't notify about allocations to our internal heap. | 556 // Don't notify about allocations to our internal heap. |
550 if (heap == heap_) | 557 if (heap == heap_) |
551 return; | 558 return; |
552 | 559 |
553 if (watcher_) | 560 if (watcher_) |
554 watcher_->OnUntrack(heap, id, size); | 561 watcher_->OnUntrack(heap, id, size); |
555 } | 562 } |
OLD | NEW |