Commit 8545e0e7 authored by rvargas's avatar rvargas Committed by Commit bot

Integrate the handle verifier from multiple modules (DLLs)

This allows handles created on the exe (or any other module) to be properly tracked.

BUG=472362

Review URL: https://codereview.chromium.org/1045513004

Cr-Commit-Position: refs/heads/master@{#324335}
parent 025c6ccc
......@@ -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,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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment