Index: sandbox/win/src/handle_closer_agent.cc |
diff --git a/sandbox/win/src/handle_closer_agent.cc b/sandbox/win/src/handle_closer_agent.cc |
index 07c6a09854d2d5355a84f30f782ec57f1a04f3ab..1fa82553bb05c4677903702162a43e01e1ff2529 100644 |
--- a/sandbox/win/src/handle_closer_agent.cc |
+++ b/sandbox/win/src/handle_closer_agent.cc |
@@ -41,6 +41,50 @@ bool HandleCloserAgent::NeedsHandlesClosed() { |
return g_handles_to_close != NULL; |
} |
+HandleCloserAgent::HandleCloserAgent() |
+ : dummy_handle_(::CreateEvent(NULL, FALSE, FALSE, NULL)) { |
+} |
+ |
+// Attempts to stuff |closed_handle| with a duplicated handle for a dummy Event |
+// with no access. This should allow the handle to be closed, to avoid |
+// generating EXCEPTION_INVALID_HANDLE on shutdown, but nothing else. For now |
+// the only supported |type| is Event or File. |
+bool HandleCloserAgent::AttemptToStuffHandleSlot(HANDLE closed_handle, |
+ const base::string16& type) { |
+ // Only attempt to stuff Files and Events at the moment. |
+ if (type != L"Event" && type != L"File") { |
+ return true; |
+ } |
+ |
+ if (!dummy_handle_.IsValid()) |
+ return false; |
+ |
+ // This should never happen, as g_dummy is created before closing to_stuff. |
+ DCHECK(dummy_handle_.Get() != closed_handle); |
+ |
+ std::vector<HANDLE> to_close; |
+ HANDLE dup_dummy = NULL; |
+ size_t count = 16; |
+ |
+ do { |
+ if (!::DuplicateHandle(::GetCurrentProcess(), dummy_handle_.Get(), |
+ ::GetCurrentProcess(), &dup_dummy, 0, FALSE, 0)) |
+ break; |
+ if (dup_dummy != closed_handle) |
+ to_close.push_back(dup_dummy); |
+ } while (count-- && |
+ reinterpret_cast<uintptr_t>(dup_dummy) < |
+ reinterpret_cast<uintptr_t>(closed_handle)); |
+ |
+ for (auto h : to_close) |
+ ::CloseHandle(h); |
+ |
+ // Useful to know when we're not able to stuff handles. |
+ DCHECK(dup_dummy == closed_handle); |
+ |
+ return dup_dummy == closed_handle; |
+} |
+ |
// Reads g_handles_to_close and creates the lookup map. |
void HandleCloserAgent::InitializeHandlesToClose() { |
CHECK(g_handles_to_close != NULL); |
@@ -136,6 +180,8 @@ bool HandleCloserAgent::CloseHandles() { |
return false; |
if (!::CloseHandle(handle)) |
return false; |
+ // Attempt to stuff this handle with a new dummy Event. |
+ AttemptToStuffHandleSlot(handle, result->first); |
} |
} |