diff options
author | ivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2012-08-15 22:09:42 +0000 |
---|---|---|
committer | ivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2012-08-15 22:09:42 +0000 |
commit | d7de392b05e015f669012db65395f26daaa53f14 (patch) | |
tree | cb4e3b3c63a4fb71c26b5611bd8db89e984968a3 /src/client/windows/crash_generation/client_info.cc | |
parent | Fix narrowing conversion from -1 to size_t (diff) | |
download | breakpad-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.cc | 40 |
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_, |