// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Static class for hooking Win32 API routines. For now, // we only add one watcher at a time. // // TODO(mbelshe): Support multiple watchers. #ifndef MEMORY_WATCHER_MEMORY_HOOK_ #define MEMORY_WATCHER_MEMORY_HOOK_ #include "base/logging.h" // When allocating memory for internal use with the MemoryHook, // we must always use the MemoryHook's heap; otherwise, the memory // gets tracked, and it becomes an infinite loop (allocation() calls // MemoryHook() which calls allocation(), etc). // // PrivateHookAllocator is an STL-friendly Allocator so that STL lists, // maps, etc can be used on the global MemoryHook's heap. template class PrivateHookAllocator { public: // These type definitions are needed for stl allocators. typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; PrivateHookAllocator() {} // Allocate memory for STL. pointer allocate(size_type n, const void * = 0) { return reinterpret_cast(MemoryHook::Alloc(n * sizeof(T))); } // Deallocate memory for STL. void deallocate(void* p, size_type) { if (p) MemoryHook::Free(p); } // Construct the object void construct(pointer p, const T& val) { new (reinterpret_cast(p))T(val); } // Destruct an object void destroy(pointer p) { p->~T(); } size_type max_size() const { return size_t(-1); } template struct rebind { typedef PrivateHookAllocator other; }; template PrivateHookAllocator(const PrivateHookAllocator&) {} }; template inline bool operator==(const PrivateHookAllocator&, const PrivateHookAllocator&) { return (true); } template inline bool operator!=(const PrivateHookAllocator& left, const PrivateHookAllocator& right) { return (!(left == right)); } // Classes which monitor memory from these hooks implement // the MemoryObserver interface. class MemoryObserver { public: virtual ~MemoryObserver() {} // Track a pointer. Will capture the current StackTrace. virtual void OnTrack(HANDLE heap, int32 id, int32 size) = 0; // Untrack a pointer, removing it from our list. virtual void OnUntrack(HANDLE heap, int32 id, int32 size) = 0; }; class MemoryHook : MemoryObserver { public: // Initialize the MemoryHook. Must be called before // registering watchers. This can be called repeatedly, // but is not thread safe. static bool Initialize(); // Returns true is memory allocations and deallocations // are being traced. static bool hooked() { return hooked_ != NULL; } // Register a class to receive memory allocation & deallocation // callbacks. If we haven't hooked memory yet, this call will // force memory hooking to start. static bool RegisterWatcher(MemoryObserver* watcher); // Register a class to stop receiving callbacks. If there are // no more watchers, this call will unhook memory. static bool UnregisterWatcher(MemoryObserver* watcher); // MemoryHook provides a private heap for allocating // unwatched memory. static void* Alloc(size_t size) { DCHECK(global_hook_ && global_hook_->heap_); return HeapAlloc(global_hook_->heap_, 0, size); } static void Free(void* ptr) { DCHECK(global_hook_ && global_hook_->heap_); HeapFree(global_hook_->heap_, 0, ptr); } // Access the global hook. For internal use only from static "C" // hooks. static MemoryHook* hook() { return global_hook_; } // MemoryObserver interface. virtual void OnTrack(HANDLE hHeap, int32 id, int32 size); virtual void OnUntrack(HANDLE hHeap, int32 id, int32 size); private: MemoryHook(); ~MemoryHook(); // Enable memory tracing. When memory is 'hooked', // MemoryWatchers which have registered will be called // as memory is allocated and deallocated. static bool Hook(); // Disables memory tracing. static bool Unhook(); // Create our private heap bool CreateHeap(); // Close our private heap. bool CloseHeap(); MemoryObserver* watcher_; HANDLE heap_; // An internal accounting heap. static bool hooked_; static MemoryHook* global_hook_; }; #endif // MEMORY_WATCHER_MEMORY_HOOK_