| Index: base/win/scoped_handle.cc
|
| diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc
|
| index 280302169209b637129fe85e6cbbb15fc9854e23..33a8aa5c743b7b27eab6349fa1f0ee953dca6909 100644
|
| --- a/base/win/scoped_handle.cc
|
| +++ b/base/win/scoped_handle.cc
|
| @@ -12,6 +12,11 @@
|
| #include "base/logging.h"
|
| #include "base/synchronization/lock_impl.h"
|
|
|
| +extern "C" {
|
| +__declspec(dllexport) void* GetHandleVerifier();
|
| +typedef void* (*GetHandleVerifierFn)();
|
| +}
|
| +
|
| namespace {
|
|
|
| struct HandleHash {
|
| @@ -30,20 +35,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 +62,185 @@ 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);
|
| +
|
| + // TODO(shrikant): Enable handle verifier after figuring out
|
| + // AppContainer/DuplicateHandle error.
|
| + g_active_verifier->Disable();
|
| +#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
|
|
|