aboutsummaryrefslogtreecommitdiff
path: root/src/client/windows/crash_generation/client_info.cc
diff options
context:
space:
mode:
authorivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-08-15 22:09:42 +0000
committerivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-08-15 22:09:42 +0000
commitd7de392b05e015f669012db65395f26daaa53f14 (patch)
treecb4e3b3c63a4fb71c26b5611bd8db89e984968a3 /src/client/windows/crash_generation/client_info.cc
parentFix narrowing conversion from -1 to size_t (diff)
downloadbreakpad-d7de392b05e015f669012db65395f26daaa53f14.tar.xz
Fixing a race condition in the Crash Generation Server which has to
do with simultaneous handling of dump requests and client process termination events. http://breakpad.appspot.com/430002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1013 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/windows/crash_generation/client_info.cc')
-rw-r--r--src/client/windows/crash_generation/client_info.cc40
1 files changed, 25 insertions, 15 deletions
diff --git a/src/client/windows/crash_generation/client_info.cc b/src/client/windows/crash_generation/client_info.cc
index 60bbac82..ca10caa4 100644
--- a/src/client/windows/crash_generation/client_info.cc
+++ b/src/client/windows/crash_generation/client_info.cc
@@ -85,16 +85,38 @@ bool ClientInfo::Initialize() {
return dump_generated_handle_ != NULL;
}
-ClientInfo::~ClientInfo() {
+void ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() {
if (dump_request_wait_handle_) {
// Wait for callbacks that might already be running to finish.
UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
+ dump_request_wait_handle_ = NULL;
}
+}
+void ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) {
if (process_exit_wait_handle_) {
- // Wait for the callback that might already be running to finish.
- UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
+ if (block_until_no_pending) {
+ // Wait for the callback that might already be running to finish.
+ UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
+ } else {
+ UnregisterWait(process_exit_wait_handle_);
+ }
+ process_exit_wait_handle_ = NULL;
}
+}
+
+ClientInfo::~ClientInfo() {
+ // Waiting for the callback to finish here is safe because ClientInfo's are
+ // never destroyed from the dump request handling callback.
+ UnregisterDumpRequestWaitAndBlockUntilNoPending();
+
+ // This is a little tricky because ClientInfo's may be destroyed by the same
+ // callback (OnClientEnd) and waiting for it to finish will cause a deadlock.
+ // Regardless of this complication, wait for any running callbacks to finish
+ // so that the common case is properly handled. In order to avoid deadlocks,
+ // the OnClientEnd callback must call UnregisterProcessExitWait(false)
+ // before deleting the ClientInfo.
+ UnregisterProcessExitWait(true);
if (process_handle_) {
CloseHandle(process_handle_);
@@ -109,18 +131,6 @@ ClientInfo::~ClientInfo() {
}
}
-void ClientInfo::UnregisterWaits() {
- if (dump_request_wait_handle_) {
- UnregisterWait(dump_request_wait_handle_);
- dump_request_wait_handle_ = NULL;
- }
-
- if (process_exit_wait_handle_) {
- UnregisterWait(process_exit_wait_handle_);
- process_exit_wait_handle_ = NULL;
- }
-}
-
bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
SIZE_T bytes_count = 0;
if (!ReadProcessMemory(process_handle_,