// Copyright (c) 2012 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. #include "base/win/scoped_handle.h" #include #include #include "base/debug/alias.h" #include "base/hash.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" #include "base/synchronization/lock_impl.h" extern "C" { __declspec(dllexport) void* GetHandleVerifier(); typedef void* (*GetHandleVerifierFn)(); } namespace { struct HandleHash { size_t operator()(const HANDLE& handle) const { char buffer[sizeof(handle)]; memcpy(buffer, &handle, sizeof(handle)); return base::Hash(buffer, sizeof(buffer)); } }; struct Info { const void* owner; const void* pc1; const void* pc2; DWORD thread_id; }; typedef std::unordered_map HandleMap; // g_lock protects the handle map and setting g_active_verifier. typedef base::internal::LockImpl NativeLock; base::LazyInstance::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; bool CloseHandleWrapper(HANDLE handle) { if (!::CloseHandle(handle)) CHECK(false); return true; } // Simple automatic locking using a native critical section so it supports // recursive locking. class AutoNativeLock { public: explicit AutoNativeLock(NativeLock& lock) : lock_(lock) { lock_.Lock(); } ~AutoNativeLock() { lock_.Unlock(); } private: NativeLock& lock_; DISALLOW_COPY_AND_ASSIGN(AutoNativeLock); }; // Implements the actual object that is verifying handles for this process. // The active instance is shared across the module boundary but there is no // way to delete this object from the wrong side of it (or any side, actually). class ActiveVerifier { public: explicit ActiveVerifier(bool enabled) : enabled_(enabled), closing_(false), lock_(g_lock.Pointer()) { } // Retrieves the current verifier. static ActiveVerifier* Get(); // The methods required by HandleTraits. They are virtual because we need to // forward the call execution to another module, instead of letting the // compiler call the version that is linked in the current module. virtual bool CloseHandle(HANDLE handle); virtual void StartTracking(HANDLE handle, const void* owner, const void* pc1, const void* pc2); virtual void StopTracking(HANDLE handle, const void* owner, const void* pc1, const void* pc2); virtual void Disable(); virtual void OnHandleBeingClosed(HANDLE handle); private: ~ActiveVerifier(); // Not implemented. static void InstallVerifier(); bool enabled_; bool closing_; NativeLock* lock_; HandleMap map_; DISALLOW_COPY_AND_ASSIGN(ActiveVerifier); }; ActiveVerifier* g_active_verifier = NULL; // static ActiveVerifier* ActiveVerifier::Get() { if (!g_active_verifier) ActiveVerifier::InstallVerifier(); return g_active_verifier; } // static void ActiveVerifier::InstallVerifier() { #if defined(COMPONENT_BUILD) AutoNativeLock lock(g_lock.Get()); g_active_verifier = new ActiveVerifier(true); #else // If you are reading this, wondering why your process seems deadlocked, take // a look at your DllMain code and remove things that should not be done // there, like doing whatever gave you that nice windows handle you are trying // to store in a ScopedHandle. HMODULE main_module = ::GetModuleHandle(NULL); GetHandleVerifierFn get_handle_verifier = reinterpret_cast(::GetProcAddress( main_module, "GetHandleVerifier")); if (!get_handle_verifier) { g_active_verifier = new ActiveVerifier(false); return; } ActiveVerifier* verifier = reinterpret_cast(get_handle_verifier()); // This lock only protects against races in this module, which is fine. AutoNativeLock lock(g_lock.Get()); g_active_verifier = verifier ? verifier : new ActiveVerifier(true); #endif } bool ActiveVerifier::CloseHandle(HANDLE handle) { if (!enabled_) return CloseHandleWrapper(handle); AutoNativeLock lock(*lock_); closing_ = true; CloseHandleWrapper(handle); closing_ = false; return true; } void ActiveVerifier::StartTracking(HANDLE handle, const void* owner, const void* pc1, const void* pc2) { if (!enabled_) return; // Grab the thread id before the lock. DWORD thread_id = GetCurrentThreadId(); AutoNativeLock lock(*lock_); Info handle_info = { owner, pc1, pc2, thread_id }; std::pair item(handle, handle_info); std::pair result = map_.insert(item); if (!result.second) { Info other = result.first->second; base::debug::Alias(&other); CHECK(false); } } void ActiveVerifier::StopTracking(HANDLE handle, const void* owner, const void* pc1, const void* pc2) { if (!enabled_) return; AutoNativeLock lock(*lock_); HandleMap::iterator i = map_.find(handle); if (i == map_.end()) CHECK(false); Info other = i->second; if (other.owner != owner) { base::debug::Alias(&other); CHECK(false); } map_.erase(i); } void ActiveVerifier::Disable() { enabled_ = false; } void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) { if (!enabled_) return; AutoNativeLock lock(*lock_); if (closing_) return; HandleMap::iterator i = map_.find(handle); if (i == map_.end()) return; Info other = i->second; base::debug::Alias(&other); CHECK(false); } } // namespace void* GetHandleVerifier() { return g_active_verifier; } namespace base { namespace win { // Static. bool HandleTraits::CloseHandle(HANDLE handle) { return ActiveVerifier::Get()->CloseHandle(handle); } // Static. void VerifierTraits::StartTracking(HANDLE handle, const void* owner, const void* pc1, const void* pc2) { return ActiveVerifier::Get()->StartTracking(handle, owner, pc1, pc2); } // Static. void VerifierTraits::StopTracking(HANDLE handle, const void* owner, const void* pc1, const void* pc2) { return ActiveVerifier::Get()->StopTracking(handle, owner, pc1, pc2); } void DisableHandleVerifier() { return ActiveVerifier::Get()->Disable(); } void OnHandleBeingClosed(HANDLE handle) { return ActiveVerifier::Get()->OnHandleBeingClosed(handle); } } // namespace win } // namespace base