Index: base/win/scoped_handle.cc |
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc |
index 280302169209b637129fe85e6cbbb15fc9854e23..58c07682aa8bb1c2271520fe77a496a34e962775 100644 |
--- a/base/win/scoped_handle.cc |
+++ b/base/win/scoped_handle.cc |
@@ -7,11 +7,17 @@ |
#include <unordered_map> |
#include "base/debug/alias.h" |
+#include "base/environment.h" |
Will Harris
2015/04/04 19:17:48
nit: this include is no longer needed
|
#include "base/hash.h" |
#include "base/lazy_instance.h" |
#include "base/logging.h" |
#include "base/synchronization/lock_impl.h" |
+extern "C" { |
+__declspec(dllexport) void* GetHandleVerifier(); |
+typedef void* (*GetHandleVerifierFn)(); |
+} |
+ |
namespace { |
struct HandleHash { |
@@ -30,20 +36,9 @@ struct Info { |
}; |
typedef std::unordered_map<HANDLE, Info, HandleHash> HandleMap; |
-// g_lock protects g_handle_map and g_closing. |
+// g_lock protects the handle map and setting g_active_verifier. |
typedef base::internal::LockImpl NativeLock; |
base::LazyInstance<NativeLock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER; |
-base::LazyInstance<HandleMap>::Leaky g_handle_map = LAZY_INSTANCE_INITIALIZER; |
-bool g_closing = false; |
- |
-// g_verifier_enabled is not protected by g_lock because that would require |
-// using the lock (hence, synchornizing multiple threads) even when the |
-// verifier is not in use. Note that this variable is initialized to track all |
-// handles, and it should only move to the disabled state, and never back to |
-// enabled, because that would crash when seeing handles created while the |
-// verifier was disabled. This also implies that it is OK if the value change is |
-// not propagated immediately to all CPUs (as would happen with a lock). |
-bool g_verifier_enabled = true; |
bool CloseHandleWrapper(HANDLE handle) { |
if (!::CloseHandle(handle)) |
@@ -68,82 +63,181 @@ class AutoNativeLock { |
DISALLOW_COPY_AND_ASSIGN(AutoNativeLock); |
}; |
-} // namespace |
+// 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()) { |
+ } |
-namespace base { |
-namespace win { |
+ // Retrieves the current verifier. |
+ static ActiveVerifier* Get(); |
-// Static. |
-bool HandleTraits::CloseHandle(HANDLE handle) { |
- if (!g_verifier_enabled) |
- return CloseHandleWrapper(handle); |
+ // 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<GetHandleVerifierFn>(::GetProcAddress( |
+ main_module, "GetHandleVerifier")); |
+ |
+ if (!get_handle_verifier) { |
+ g_active_verifier = new ActiveVerifier(false); |
+ return; |
+ } |
+ |
+ ActiveVerifier* verifier = |
+ reinterpret_cast<ActiveVerifier*>(get_handle_verifier()); |
+ |
+ // This lock only protects against races in this module, which is fine. |
AutoNativeLock lock(g_lock.Get()); |
- g_closing = true; |
+ 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); |
- g_closing = false; |
+ closing_ = false; |
return true; |
} |
-// Static. |
-void VerifierTraits::StartTracking(HANDLE handle, const void* owner, |
+void ActiveVerifier::StartTracking(HANDLE handle, const void* owner, |
const void* pc1, const void* pc2) { |
- if (!g_verifier_enabled) |
+ if (!enabled_) |
return; |
// Grab the thread id before the lock. |
DWORD thread_id = GetCurrentThreadId(); |
- AutoNativeLock lock(g_lock.Get()); |
+ AutoNativeLock lock(*lock_); |
Info handle_info = { owner, pc1, pc2, thread_id }; |
std::pair<HANDLE, Info> item(handle, handle_info); |
- std::pair<HandleMap::iterator, bool> result = g_handle_map.Get().insert(item); |
+ std::pair<HandleMap::iterator, bool> result = map_.insert(item); |
if (!result.second) { |
Info other = result.first->second; |
- debug::Alias(&other); |
+ base::debug::Alias(&other); |
CHECK(false); |
} |
} |
-// Static. |
-void VerifierTraits::StopTracking(HANDLE handle, const void* owner, |
+void ActiveVerifier::StopTracking(HANDLE handle, const void* owner, |
const void* pc1, const void* pc2) { |
- if (!g_verifier_enabled) |
+ if (!enabled_) |
return; |
- AutoNativeLock lock(g_lock.Get()); |
- HandleMap::iterator i = g_handle_map.Get().find(handle); |
- if (i == g_handle_map.Get().end()) |
+ AutoNativeLock lock(*lock_); |
+ HandleMap::iterator i = map_.find(handle); |
+ if (i == map_.end()) |
CHECK(false); |
Info other = i->second; |
if (other.owner != owner) { |
- debug::Alias(&other); |
+ base::debug::Alias(&other); |
CHECK(false); |
} |
- g_handle_map.Get().erase(i); |
+ map_.erase(i); |
} |
-void DisableHandleVerifier() { |
- g_verifier_enabled = false; |
+void ActiveVerifier::Disable() { |
+ enabled_ = false; |
} |
-void OnHandleBeingClosed(HANDLE handle) { |
- AutoNativeLock lock(g_lock.Get()); |
- if (g_closing) |
+void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) { |
+ AutoNativeLock lock(*lock_); |
+ if (closing_) |
return; |
- HandleMap::iterator i = g_handle_map.Get().find(handle); |
- if (i == g_handle_map.Get().end()) |
+ HandleMap::iterator i = map_.find(handle); |
+ if (i == map_.end()) |
return; |
Info other = i->second; |
- debug::Alias(&other); |
+ 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 |