From 20045d38679c35f3b5886c665706dac4cbb003b4 Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Thu, 5 Nov 2015 13:48:27 -0500
Subject: [PATCH 01/12] Add buildtools to make depot_tools-wrapped clang-format
 work

Crashpad is mostly friendly with clang-format and has its own
.clang-format file. Adding buildtools makes it possible to use the
depot_tools clang-format wrapper.

R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1414903006 .
---
 DEPS | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/DEPS b/DEPS
index 34313f8e..b5e38f1b 100644
--- a/DEPS
+++ b/DEPS
@@ -29,9 +29,40 @@ deps = {
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
       '8e12d3df2f1c0fcd84d649f4619323558db63a85',
+  'buildtools':
+      Var('chromium_git') + '/chromium/buildtools.git@' +
+      'c2f259809d5ede3275df5ea0842f0431990c4f98',
 }
 
 hooks = [
+  {
+    'name': 'clang_format_mac',
+    'pattern': '.',
+    'action': [
+      'download_from_google_storage',
+      '--platform=^darwin$',
+      '--no_resume',
+      '--no_auth',
+      '--bucket=chromium-clang-format',
+      '--output=buildtools/mac/clang-format',
+      '--sha1_file',
+      'buildtools/mac/clang-format.sha1',
+    ],
+  },
+  {
+    'name': 'clang_format_win',
+    'pattern': '.',
+    'action': [
+      'download_from_google_storage',
+      '--platform=^win32$',
+      '--no_resume',
+      '--no_auth',
+      '--bucket=chromium-clang-format',
+      '--output=buildtools/win/clang-format.exe',
+      '--sha1_file',
+      'buildtools/win/clang-format.exe.sha1',
+    ],
+  },
   {
     'name': 'gyp',
     'pattern': '\.gypi?$',

From 2eeaa3ac549a6646031cac05f8d1424ff4946157 Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Thu, 5 Nov 2015 14:00:26 -0500
Subject: [PATCH 02/12] win: Add HandleToInt() and IntToHandle()

This consolidates all of the twisted casts and comments that discuss how
HANDLEs are really only 32 bits wide even in 64-bit processes on 64-bit
operating systems into a single location.

R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1422503015 .
---
 client/crashpad_client_win.cc        | 19 ++++----
 handler/main.cc                      | 13 +++---
 test/win/win_child_process.cc        |  9 ++--
 util/util.gyp                        |  2 +
 util/util_test.gyp                   |  1 +
 util/win/exception_handler_server.cc | 13 +++---
 util/win/handle.cc                   | 36 +++++++++++++++
 util/win/handle.h                    | 65 ++++++++++++++++++++++++++++
 util/win/handle_test.cc              | 53 +++++++++++++++++++++++
 util/win/process_info.cc             | 12 +++--
 util/win/process_info.h              |  3 --
 util/win/process_info_test.cc        | 11 +++--
 util/win/registration_protocol_win.h |  5 ---
 13 files changed, 194 insertions(+), 48 deletions(-)
 create mode 100644 util/win/handle.cc
 create mode 100644 util/win/handle.h
 create mode 100644 util/win/handle_test.cc

diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc
index a2506cb7..46b61372 100644
--- a/client/crashpad_client_win.cc
+++ b/client/crashpad_client_win.cc
@@ -26,6 +26,7 @@
 #include "util/file/file_io.h"
 #include "util/win/command_line.h"
 #include "util/win/critical_section_with_debug_info.h"
+#include "util/win/handle.h"
 #include "util/win/registration_protocol_win.h"
 #include "util/win/scoped_handle.h"
 
@@ -166,13 +167,9 @@ bool CrashpadClient::StartHandler(
                              base::UTF8ToUTF16(kv.first + '=' + kv.second)),
         &command_line);
   }
-
-  // According to
-  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203, HANDLEs
-  // are always 32 bits.
   AppendCommandLineArgument(
       base::UTF8ToUTF16(base::StringPrintf("--handshake-handle=0x%x",
-                                           pipe_write)),
+                                           HandleToInt(pipe_write))),
       &command_line);
 
   STARTUPINFO startup_info = {};
@@ -271,12 +268,12 @@ bool CrashpadClient::UseHandler() {
   }
 
   // The server returns these already duplicated to be valid in this process.
-  g_signal_exception = reinterpret_cast<HANDLE>(
-      static_cast<uintptr_t>(response.registration.request_crash_dump_event));
-  g_signal_non_crash_dump = reinterpret_cast<HANDLE>(static_cast<uintptr_t>(
-      response.registration.request_non_crash_dump_event));
-  g_non_crash_dump_done = reinterpret_cast<HANDLE>(static_cast<uintptr_t>(
-      response.registration.non_crash_dump_completed_event));
+  g_signal_exception =
+      IntToHandle(response.registration.request_crash_dump_event);
+  g_signal_non_crash_dump =
+      IntToHandle(response.registration.request_non_crash_dump_event);
+  g_non_crash_dump_done =
+      IntToHandle(response.registration.non_crash_dump_completed_event);
 
   g_non_crash_dump_lock = new base::Lock();
 
diff --git a/handler/main.cc b/handler/main.cc
index 7b1f7304..fcc3f71c 100644
--- a/handler/main.cc
+++ b/handler/main.cc
@@ -46,6 +46,7 @@
 #include <windows.h>
 #include "handler/win/crash_report_exception_handler.h"
 #include "util/win/exception_handler_server.h"
+#include "util/win/handle.h"
 #endif  // OS_MACOSX
 
 namespace crashpad {
@@ -181,18 +182,14 @@ int HandlerMain(int argc, char* argv[]) {
       }
 #elif defined(OS_WIN)
       case kOptionHandshakeHandle: {
-        // According to
-        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203,
-        // HANDLEs are always 32 bits. This construction is used to read a full
-        // 32-bit number presented by the client, which uses 0x%x format, and
-        // sign-extend it.
+        // Use unsigned int, because the handle was presented by the client in
+        // 0x%x format.
         unsigned int handle_uint;
         if (!StringToNumber(optarg, &handle_uint) ||
-            (options.handshake_handle = reinterpret_cast<HANDLE>(
-                 static_cast<int>(handle_uint))) == INVALID_HANDLE_VALUE) {
+            (options.handshake_handle = IntToHandle(handle_uint)) ==
+                INVALID_HANDLE_VALUE) {
           ToolSupport::UsageHint(me, "--handshake-handle requires a HANDLE");
           return EXIT_FAILURE;
-        }
         break;
       }
       case kOptionPipeName: {
diff --git a/test/win/win_child_process.cc b/test/win/win_child_process.cc
index 577b6b63..7d179337 100644
--- a/test/win/win_child_process.cc
+++ b/test/win/win_child_process.cc
@@ -25,6 +25,7 @@
 #include "gtest/gtest.h"
 #include "util/stdlib/string_number_conversion.h"
 #include "util/string/split_string.h"
+#include "util/win/handle.h"
 #include "test/paths.h"
 
 namespace crashpad {
@@ -152,8 +153,8 @@ WinChildProcess::WinChildProcess() {
   unsigned int write, read;
   CHECK(StringToNumber(left, &write));
   CHECK(StringToNumber(right, &read));
-  pipe_write_.reset(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(write)));
-  pipe_read_.reset(reinterpret_cast<HANDLE>(static_cast<uintptr_t>(read)));
+  pipe_write_.reset(IntToHandle(write));
+  pipe_read_.reset(IntToHandle(read));
 
   // Notify the parent that it's OK to proceed. We only need to wait to get to
   // the process entry point, but this is the easiest place we can notify.
@@ -193,8 +194,8 @@ scoped_ptr<WinChildProcess::Handles> WinChildProcess::Launch() {
                                            test_info->test_case_name(),
                                            test_info->name(),
                                            kIsMultiprocessChild,
-                                           write_for_child,
-                                           read_for_child.get()));
+                                           HandleToInt(write_for_child.get()),
+                                           HandleToInt(read_for_child.get())));
 
   // Command-line buffer cannot be constant, per CreateProcess signature.
   handles_for_parent->process = LaunchCommandLine(&command_line[0]);
diff --git a/util/util.gyp b/util/util.gyp
index 65791b5a..685032c7 100644
--- a/util/util.gyp
+++ b/util/util.gyp
@@ -160,6 +160,8 @@
         'win/exception_handler_server.h',
         'win/get_function.cc',
         'win/get_function.h',
+        'win/handle.cc',
+        'win/handle.h',
         'win/module_version.cc',
         'win/module_version.h',
         'win/nt_internals.cc',
diff --git a/util/util_test.gyp b/util/util_test.gyp
index 40bb64fd..9d235fa3 100644
--- a/util/util_test.gyp
+++ b/util/util_test.gyp
@@ -84,6 +84,7 @@
         'win/critical_section_with_debug_info_test.cc',
         'win/exception_handler_server_test.cc',
         'win/get_function_test.cc',
+        'win/handle_test.cc',
         'win/process_info_test.cc',
         'win/scoped_process_suspend_test.cc',
         'win/time_test.cc',
diff --git a/util/win/exception_handler_server.cc b/util/win/exception_handler_server.cc
index 2035c578..ce5687d7 100644
--- a/util/win/exception_handler_server.cc
+++ b/util/win/exception_handler_server.cc
@@ -28,6 +28,7 @@
 #include "util/misc/tri_state.h"
 #include "util/misc/uuid.h"
 #include "util/win/get_function.h"
+#include "util/win/handle.h"
 #include "util/win/registration_protocol_win.h"
 #include "util/win/xp_compat.h"
 
@@ -489,14 +490,14 @@ bool ExceptionHandlerServer::ServiceClientConnection(
   // Duplicate the events back to the client so they can request a dump.
   ServerToClientMessage response;
   response.registration.request_crash_dump_event =
-      base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent(
-          client->process(), client->crash_dump_requested_event())));
+      HandleToInt(DuplicateEvent(
+          client->process(), client->crash_dump_requested_event()));
   response.registration.request_non_crash_dump_event =
-      base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent(
-          client->process(), client->non_crash_dump_requested_event())));
+      HandleToInt(DuplicateEvent(
+          client->process(), client->non_crash_dump_requested_event()));
   response.registration.non_crash_dump_completed_event =
-      base::checked_cast<uint32_t>(reinterpret_cast<uintptr_t>(DuplicateEvent(
-          client->process(), client->non_crash_dump_completed_event())));
+      HandleToInt(DuplicateEvent(
+          client->process(), client->non_crash_dump_completed_event()));
 
   if (!LoggingWriteFile(service_context.pipe(), &response, sizeof(response)))
     return false;
diff --git a/util/win/handle.cc b/util/win/handle.cc
new file mode 100644
index 00000000..c53f5438
--- /dev/null
+++ b/util/win/handle.cc
@@ -0,0 +1,36 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/win/handle.h"
+
+#include <stdint.h>
+
+#include "base/numerics/safe_conversions.h"
+
+namespace crashpad {
+
+// These functions use “int” for the 32-bit integer handle type because
+// sign-extension needs to work correctly. INVALID_HANDLE_VALUE is defined as
+// ((HANDLE)(LONG_PTR)-1), and this needs to round-trip through an integer and
+// back to the same HANDLE value.
+
+int HandleToInt(HANDLE handle) {
+  return base::checked_cast<int>(reinterpret_cast<intptr_t>(handle));
+}
+
+HANDLE IntToHandle(int handle_int) {
+  return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle_int));
+}
+
+}  // namespace crashpad
diff --git a/util/win/handle.h b/util/win/handle.h
new file mode 100644
index 00000000..c5a96cae
--- /dev/null
+++ b/util/win/handle.h
@@ -0,0 +1,65 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_WIN_HANDLE_TO_INT_H_
+#define CRASHPAD_UTIL_WIN_HANDLE_TO_INT_H_
+
+#include <windows.h>
+
+namespace crashpad {
+
+//! \brief Converts a `HANDLE` to an `int`.
+//!
+//! `HANDLE` is a `typedef` for `void *`, but `HANDLE` values aren’t necessarily
+//! pointers to anything. Only 32 bits of shareable `HANDLE`s are significant,
+//! even in 64-bit processes on 64-bit operating systems. See <a
+//! href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203">Interprocess
+//! Communication Between 32-bit and 64-bit Applications</a>.
+//!
+//! This function safely converts a shareable `HANDLE` to an `int` similarly to
+//! a cast operation. It checks that the operation can be performed safely, and
+//! aborts execution if it cannot.
+//!
+//! \param[in] handle The shareable `HANDLE` to convert.
+//!
+//! \return An equivalent `int`, truncated (if necessary) from \a handle. If
+//!     truncation would have resulted in an `int` that could not be converted
+//!     back to \a handle, aborts execution.
+//!
+//! \sa IntToHandle()
+int HandleToInt(HANDLE handle);
+
+//! \brief Converts an `int` to an `HANDLE`.
+//!
+//! `HANDLE` is a `typedef` for `void *`, but `HANDLE` values aren’t necessarily
+//! pointers to anything. Only 32 bits of shareable `HANDLE`s are significant,
+//! even in 64-bit processes on 64-bit operating systems. See <a
+//! href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203">Interprocess
+//! Communication Between 32-bit and 64-bit Applications</a>.
+//!
+//! This function safely convert an `int` to a shareable `HANDLE` similarly to a
+//! cast operation.
+//!
+//! \param[in] handle_int The `int` to convert. This must have been produced by
+//!     HandleToInt(), possibly in a different process.
+//!
+//! \return An equivalent shareable `HANDLE`, sign-extended (if necessary) from
+//!     \a handle_int.
+//!
+//! \sa HandleToInt()
+HANDLE IntToHandle(int handle_int);
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_UTIL_WIN_HANDLE_TO_INT_H_
diff --git a/util/win/handle_test.cc b/util/win/handle_test.cc
new file mode 100644
index 00000000..60e5037b
--- /dev/null
+++ b/util/win/handle_test.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/win/handle.h"
+
+#include <stdint.h>
+
+#include <limits>
+
+#include "gtest/gtest.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+TEST(Handle, HandleToInt) {
+  EXPECT_EQ(0, HandleToInt(nullptr));
+  EXPECT_EQ(-1, HandleToInt(INVALID_HANDLE_VALUE));
+  EXPECT_EQ(1, HandleToInt(reinterpret_cast<HANDLE>(1)));
+  EXPECT_EQ(std::numeric_limits<int>::max(),
+            HandleToInt(reinterpret_cast<HANDLE>(
+                static_cast<intptr_t>(std::numeric_limits<int>::max()))));
+  EXPECT_EQ(std::numeric_limits<int>::min(),
+            HandleToInt(reinterpret_cast<HANDLE>(
+                static_cast<intptr_t>(std::numeric_limits<int>::min()))));
+}
+
+TEST(Handle, IntToHandle) {
+  EXPECT_EQ(nullptr, IntToHandle(0));
+  EXPECT_EQ(INVALID_HANDLE_VALUE, IntToHandle(-1));
+  EXPECT_EQ(reinterpret_cast<HANDLE>(1), IntToHandle(1));
+  EXPECT_EQ(reinterpret_cast<HANDLE>(
+                static_cast<intptr_t>(std::numeric_limits<int>::max())),
+            IntToHandle(std::numeric_limits<int>::max()));
+  EXPECT_EQ(reinterpret_cast<HANDLE>(
+                static_cast<intptr_t>(std::numeric_limits<int>::min())),
+            IntToHandle(std::numeric_limits<int>::min()));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/util/win/process_info.cc b/util/win/process_info.cc
index d5316590..50f947ce 100644
--- a/util/win/process_info.cc
+++ b/util/win/process_info.cc
@@ -26,6 +26,7 @@
 #include "build/build_config.h"
 #include "util/numeric/safe_assignment.h"
 #include "util/win/get_function.h"
+#include "util/win/handle.h"
 #include "util/win/nt_internals.h"
 #include "util/win/ntstatus_logging.h"
 #include "util/win/process_structs.h"
@@ -181,10 +182,8 @@ bool GetProcessBasicInformation(HANDLE process,
     return false;
   }
 
-  // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on
-  // 32 bit being the correct size for HANDLEs for proceses, even on Windows
-  // x64. API functions (e.g. OpenProcess) take only a DWORD, so there's no
-  // sense in maintaining the top bits.
+  // API functions (e.g. OpenProcess) take only a DWORD, so there's no sense in
+  // maintaining the top bits.
   process_info->process_id_ =
       static_cast<DWORD>(process_basic_information.UniqueProcessId);
   process_info->inherited_from_process_id_ = static_cast<DWORD>(
@@ -390,15 +389,14 @@ std::vector<ProcessInfo::Handle> ProcessInfo::BuildHandleVector(
       continue;
 
     Handle result_handle;
-    result_handle.handle =
-        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(handle.HandleValue));
+    result_handle.handle = HandleToInt(handle.HandleValue);
     result_handle.attributes = handle.HandleAttributes;
     result_handle.granted_access = handle.GrantedAccess;
 
     // TODO(scottmg): Could special case for self.
     HANDLE dup_handle;
     if (DuplicateHandle(process,
-                        reinterpret_cast<HANDLE>(handle.HandleValue),
+                        handle.HandleValue,
                         GetCurrentProcess(),
                         &dup_handle,
                         0,
diff --git a/util/win/process_info.h b/util/win/process_info.h
index ca1935bb..49a6f354 100644
--- a/util/win/process_info.h
+++ b/util/win/process_info.h
@@ -58,9 +58,6 @@ class ProcessInfo {
     std::wstring type_name;
 
     //! \brief The handle's value.
-    //!
-    //! See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on
-    //! 32 bits being the correct size for `HANDLE`s, even on Windows x64.
     uint32_t handle;
 
     //! \brief The attributes for the handle, e.g. `OBJ_INHERIT`,
diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc
index 0fc52a58..a6f9dc1c 100644
--- a/util/win/process_info_test.cc
+++ b/util/win/process_info_test.cc
@@ -33,6 +33,7 @@
 #include "util/misc/uuid.h"
 #include "util/win/command_line.h"
 #include "util/win/get_function.h"
+#include "util/win/handle.h"
 #include "util/win/scoped_handle.h"
 
 namespace crashpad {
@@ -573,7 +574,8 @@ TEST(ProcessInfo, Handles) {
   bool found_key_handle = false;
   bool found_mapping_handle = false;
   for (auto handle : info.Handles()) {
-    if (reinterpret_cast<uint32_t>(file.get()) == handle.handle) {
+    const int handle_int = implicit_cast<int>(handle.handle);
+    if (handle_int == HandleToInt(file.get())) {
       EXPECT_FALSE(found_file_handle);
       found_file_handle = true;
       EXPECT_EQ(L"File", handle.type_name);
@@ -583,7 +585,7 @@ TEST(ProcessInfo, Handles) {
                 handle.granted_access & STANDARD_RIGHTS_ALL);
       EXPECT_EQ(0, handle.attributes);
     }
-    if (reinterpret_cast<uint32_t>(inherited_file.get()) == handle.handle) {
+    if (handle_int == HandleToInt(inherited_file.get())) {
       EXPECT_FALSE(found_inherited_file_handle);
       found_inherited_file_handle = true;
       EXPECT_EQ(L"File", handle.type_name);
@@ -597,7 +599,7 @@ TEST(ProcessInfo, Handles) {
       const int kObjInherit = 0x2;
       EXPECT_EQ(kObjInherit, handle.attributes);
     }
-    if (reinterpret_cast<uint32_t>(scoped_key.get()) == handle.handle) {
+    if (handle_int == HandleToInt(scoped_key.get())) {
       EXPECT_FALSE(found_key_handle);
       found_key_handle = true;
       EXPECT_EQ(L"Key", handle.type_name);
@@ -607,7 +609,7 @@ TEST(ProcessInfo, Handles) {
                 handle.granted_access & STANDARD_RIGHTS_ALL);
       EXPECT_EQ(0, handle.attributes);
     }
-    if (reinterpret_cast<uint32_t>(mapping.get()) == handle.handle) {
+    if (handle_int == HandleToInt(mapping.get())) {
       EXPECT_FALSE(found_mapping_handle);
       found_mapping_handle = true;
       EXPECT_EQ(L"Section", handle.type_name);
@@ -620,6 +622,7 @@ TEST(ProcessInfo, Handles) {
     }
   }
   EXPECT_TRUE(found_file_handle);
+  EXPECT_TRUE(found_inherited_file_handle);
   EXPECT_TRUE(found_key_handle);
   EXPECT_TRUE(found_mapping_handle);
 }
diff --git a/util/win/registration_protocol_win.h b/util/win/registration_protocol_win.h
index a691931d..f2d9e29c 100644
--- a/util/win/registration_protocol_win.h
+++ b/util/win/registration_protocol_win.h
@@ -93,11 +93,6 @@ struct ClientToServerMessage {
 };
 
 //! \brief  A client registration response.
-//!
-//! See <a
-//! href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203">Interprocess
-//! Communication Between 32-bit and 64-bit Applications</a> for details on
-//! communicating handle values between processes of varying bitness.
 struct RegistrationResponse {
   //! \brief An event `HANDLE`, valid in the client process, that should be
   //!     signaled to request a crash report. 64-bit clients should convert the

From 827e045279e15429ac5753e3e97ad2c0d53dc84a Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Thu, 5 Nov 2015 14:06:18 -0500
Subject: [PATCH 03/12] win: Fix build after 2eeaa3ac549a

Review URL: https://codereview.chromium.org/1424713008 .
---
 handler/main.cc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/handler/main.cc b/handler/main.cc
index fcc3f71c..0ec6e7f2 100644
--- a/handler/main.cc
+++ b/handler/main.cc
@@ -190,6 +190,7 @@ int HandlerMain(int argc, char* argv[]) {
                 INVALID_HANDLE_VALUE) {
           ToolSupport::UsageHint(me, "--handshake-handle requires a HANDLE");
           return EXIT_FAILURE;
+        }
         break;
       }
       case kOptionPipeName: {

From 82ffeaa0f0866e04e9e3b4f36fe27143cc2f233e Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Thu, 5 Nov 2015 15:08:28 -0500
Subject: [PATCH 04/12] win: crashpad_util_test ProcessInfo.Handles doesn't
 work with CONOUT$

In 2eeaa3ac549a, I added a check to make sure that the expected CONOUT$
handle was found. Its omission seemed to be unintentional. The tests
passed for me on Windows 10, but failed on the bots. I can reproduce
the failures locally on Windows 7.

Doing the inheritance test with a file other than CONOUT$ fixes the
immediate problem, but we should find out why this CONOUT$ handle isn't
showing up in the handles list on Windows 7, fix it, and add back a
test.

R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1428753009 .
---
 util/win/process_info_test.cc | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc
index a6f9dc1c..7bf0f4ef 100644
--- a/util/win/process_info_test.cc
+++ b/util/win/process_info_test.cc
@@ -538,14 +538,16 @@ TEST(ProcessInfo, Handles) {
   ASSERT_TRUE(file.is_valid());
 
   SECURITY_ATTRIBUTES security_attributes = {0};
+  security_attributes.nLength = sizeof(security_attributes);
   security_attributes.bInheritHandle = true;
-  ScopedFileHandle inherited_file(CreateFile(L"CONOUT$",
-                                             GENERIC_WRITE,
-                                             0,
-                                             &security_attributes,
-                                             OPEN_EXISTING,
-                                             FILE_ATTRIBUTE_NORMAL,
-                                             nullptr));
+  ScopedFileHandle inherited_file(CreateFile(
+      temp_dir.path().Append(FILE_PATH_LITERAL("inheritable")).value().c_str(),
+      GENERIC_WRITE,
+      0,
+      &security_attributes,
+      CREATE_NEW,
+      FILE_ATTRIBUTE_NORMAL,
+      nullptr));
   ASSERT_TRUE(inherited_file.is_valid());
 
   HKEY key;

From 9a9076656fc499044a8ed2c570b7cd523afd380d Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Fri, 6 Nov 2015 10:15:58 -0500
Subject: [PATCH 05/12] win: Fix ClockMonotonicNanoseconds()

R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1419533014 .
---
 util/misc/clock_win.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/util/misc/clock_win.cc b/util/misc/clock_win.cc
index 731e98d4..7231205d 100644
--- a/util/misc/clock_win.cc
+++ b/util/misc/clock_win.cc
@@ -39,7 +39,7 @@ uint64_t ClockMonotonicNanoseconds() {
   QueryPerformanceCounter(&time);
   int64_t frequency = QpcFrequency();
   int64_t whole_seconds = time.QuadPart / frequency;
-  int64_t leftover_ticks = time.QuadPart / (whole_seconds * frequency);
+  int64_t leftover_ticks = time.QuadPart % frequency;
   const int64_t kNanosecondsPerSecond = static_cast<const int64_t>(1E9);
   return (whole_seconds * kNanosecondsPerSecond) +
          ((leftover_ticks * kNanosecondsPerSecond) / frequency);

From e75e8c800f3f2f9ca1b131b2a0599a2fb5ca80f9 Mon Sep 17 00:00:00 2001
From: Scott Graham <scottmg@chromium.org>
Date: Fri, 6 Nov 2015 10:43:39 -0800
Subject: [PATCH 06/12] win: Lower integrity level of connection pipe

This is necessary to be able to connect to crashpad_handler from a
Chrome renderer.

R=jschuh@chromium.org, mark@chromium.org
BUG=chromium:546288

Review URL: https://codereview.chromium.org/1405093013 .
---
 test/win/win_child_process.cc        | 12 +-----
 util/util.gyp                        |  3 ++
 util/win/command_line_test.cc        | 12 +-----
 util/win/exception_handler_server.cc | 57 ++++++++++++++++++++++------
 util/win/scoped_local_alloc.cc       | 26 +++++++++++++
 util/win/scoped_local_alloc.h        | 33 ++++++++++++++++
 6 files changed, 110 insertions(+), 33 deletions(-)
 create mode 100644 util/win/scoped_local_alloc.cc
 create mode 100644 util/win/scoped_local_alloc.h

diff --git a/test/win/win_child_process.cc b/test/win/win_child_process.cc
index 7d179337..b6cbbbd2 100644
--- a/test/win/win_child_process.cc
+++ b/test/win/win_child_process.cc
@@ -26,6 +26,7 @@
 #include "util/stdlib/string_number_conversion.h"
 #include "util/string/split_string.h"
 #include "util/win/handle.h"
+#include "util/win/scoped_local_alloc.h"
 #include "test/paths.h"
 
 namespace crashpad {
@@ -34,20 +35,11 @@ namespace test {
 namespace {
 
 const char kIsMultiprocessChild[] = "--is-multiprocess-child";
-struct LocalFreeTraits {
-  static HLOCAL InvalidValue() { return nullptr; }
-  static void Free(HLOCAL mem) {
-    if (LocalFree(mem) != nullptr)
-      PLOG(ERROR) << "LocalFree";
-  }
-};
-
-using ScopedLocalFree = base::ScopedGeneric<HLOCAL, LocalFreeTraits>;
 
 bool GetSwitch(const char* switch_name, std::string* value) {
   int num_args;
   wchar_t** args = CommandLineToArgvW(GetCommandLine(), &num_args);
-  ScopedLocalFree scoped_args(args);  // Take ownership.
+  ScopedLocalAlloc scoped_args(args);  // Take ownership.
   if (!args) {
     PLOG(FATAL) << "CommandLineToArgvW";
     return false;
diff --git a/util/util.gyp b/util/util.gyp
index 685032c7..5f4064a1 100644
--- a/util/util.gyp
+++ b/util/util.gyp
@@ -175,6 +175,8 @@
         'win/registration_protocol_win.h',
         'win/scoped_handle.cc',
         'win/scoped_handle.h',
+        'win/scoped_local_alloc.cc',
+        'win/scoped_local_alloc.h',
         'win/scoped_process_suspend.cc',
         'win/scoped_process_suspend.h',
         'win/time.cc',
@@ -246,6 +248,7 @@
         ['OS=="win"', {
           'link_settings': {
             'libraries': [
+              '-ladvapi32.lib',
               '-lrpcrt4.lib',
               '-lwinhttp.lib',
             ],
diff --git a/util/win/command_line_test.cc b/util/win/command_line_test.cc
index f3955697..d3179275 100644
--- a/util/win/command_line_test.cc
+++ b/util/win/command_line_test.cc
@@ -22,22 +22,12 @@
 #include "base/scoped_generic.h"
 #include "gtest/gtest.h"
 #include "test/errors.h"
+#include "util/win/scoped_local_alloc.h"
 
 namespace crashpad {
 namespace test {
 namespace {
 
-struct LocalAllocTraits {
-  static HLOCAL InvalidValue() {
-    return nullptr;
-  }
-
-  static void Free(HLOCAL memory) {
-    PLOG_IF(ERROR, LocalFree(memory) != nullptr) << "LocalFree";
-  }
-};
-using ScopedLocalAlloc = base::ScopedGeneric<HLOCAL, LocalAllocTraits>;
-
 // Calls AppendCommandLineArgument() for every argument in argv, then calls
 // CommandLineToArgvW() to decode the string into a vector again, and compares
 // the input and output.
diff --git a/util/win/exception_handler_server.cc b/util/win/exception_handler_server.cc
index ce5687d7..3a41a1de 100644
--- a/util/win/exception_handler_server.cc
+++ b/util/win/exception_handler_server.cc
@@ -14,6 +14,7 @@
 
 #include "util/win/exception_handler_server.h"
 
+#include <sddl.h>
 #include <string.h>
 
 #include "base/logging.h"
@@ -30,6 +31,7 @@
 #include "util/win/get_function.h"
 #include "util/win/handle.h"
 #include "util/win/registration_protocol_win.h"
+#include "util/win/scoped_local_alloc.h"
 #include "util/win/xp_compat.h"
 
 namespace crashpad {
@@ -44,19 +46,50 @@ const size_t kPipeInstances = 2;
 //
 // If first_instance is true, the named pipe instance will be created with
 // FILE_FLAG_FIRST_PIPE_INSTANCE. This ensures that the the pipe name is not
-// already in use when created.
+// already in use when created. The first instance will be created with an
+// untrusted integrity SACL so instances of this pipe can be connected to by
+// processes of any integrity level.
 HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name,
                                bool first_instance) {
-  return CreateNamedPipe(pipe_name.c_str(),
-                         PIPE_ACCESS_DUPLEX |
-                             (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE
-                                             : 0),
-                         PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-                         kPipeInstances,
-                         512,
-                         512,
-                         0,
-                         nullptr);
+  SECURITY_ATTRIBUTES security_attributes;
+  SECURITY_ATTRIBUTES* security_attributes_pointer = nullptr;
+  ScopedLocalAlloc scoped_sec_desc;
+
+  if (first_instance) {
+    // Pre-Vista does not have integrity levels.
+    const DWORD version = GetVersion();
+    const DWORD major_version = LOBYTE(LOWORD(version));
+    const bool is_vista_or_later = major_version >= 6;
+    if (is_vista_or_later) {
+      // Mandatory Label, no ACE flags, no ObjectType, integrity level
+      // untrusted.
+      const wchar_t kSddl[] = L"S:(ML;;;;;S-1-16-0)";
+
+      PSECURITY_DESCRIPTOR sec_desc;
+      PCHECK(ConvertStringSecurityDescriptorToSecurityDescriptor(
+          kSddl, SDDL_REVISION_1, &sec_desc, nullptr))
+          << "ConvertStringSecurityDescriptorToSecurityDescriptor";
+
+      // Take ownership of the allocated SECURITY_DESCRIPTOR.
+      scoped_sec_desc.reset(sec_desc);
+
+      memset(&security_attributes, 0, sizeof(security_attributes));
+      security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+      security_attributes.lpSecurityDescriptor = sec_desc;
+      security_attributes.bInheritHandle = FALSE;
+      security_attributes_pointer = &security_attributes;
+    }
+  }
+
+  return CreateNamedPipe(
+      pipe_name.c_str(),
+      PIPE_ACCESS_DUPLEX | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
+      PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+      kPipeInstances,
+      512,
+      512,
+      0,
+      security_attributes_pointer);
 }
 
 decltype(GetNamedPipeClientProcessId)* GetNamedPipeClientProcessIdFunction() {
@@ -320,7 +353,7 @@ void ExceptionHandlerServer::Run(Delegate* delegate) {
     if (first_pipe_instance_.is_valid()) {
       pipe = first_pipe_instance_.release();
     } else {
-      pipe = CreateNamedPipeInstance(pipe_name_, false);
+      pipe = CreateNamedPipeInstance(pipe_name_, i == 0);
       PCHECK(pipe != INVALID_HANDLE_VALUE) << "CreateNamedPipe";
     }
 
diff --git a/util/win/scoped_local_alloc.cc b/util/win/scoped_local_alloc.cc
new file mode 100644
index 00000000..e9388ee1
--- /dev/null
+++ b/util/win/scoped_local_alloc.cc
@@ -0,0 +1,26 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/win/scoped_local_alloc.h"
+
+#include "base/logging.h"
+
+namespace crashpad {
+
+// static
+void LocalAllocTraits::Free(HLOCAL memory) {
+  PLOG_IF(ERROR, LocalFree(memory) != nullptr) << "LocalFree";
+}
+
+}  // namespace crashpad
diff --git a/util/win/scoped_local_alloc.h b/util/win/scoped_local_alloc.h
new file mode 100644
index 00000000..26a59ed8
--- /dev/null
+++ b/util/win/scoped_local_alloc.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_WIN_SCOPED_LOCAL_ALLOC_H_
+#define CRASHPAD_UTIL_WIN_SCOPED_LOCAL_ALLOC_H_
+
+#include <windows.h>
+
+#include "base/scoped_generic.h"
+
+namespace crashpad {
+
+struct LocalAllocTraits {
+  static HLOCAL InvalidValue() { return nullptr; }
+  static void Free(HLOCAL mem);
+};
+
+using ScopedLocalAlloc = base::ScopedGeneric<HLOCAL, LocalAllocTraits>;
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_UTIL_WIN_SCOPED_LOCAL_ALLOC_H_

From 20869d94682cb72b3e4544b47cc27059aa0af3ad Mon Sep 17 00:00:00 2001
From: Scott Graham <scottmg@chromium.org>
Date: Fri, 6 Nov 2015 10:52:09 -0800
Subject: [PATCH 07/12] Break crashpad_handler into lib and exe for Windows

I've heard/lived enough horror stories about AV, outbound-blocking
firewalls, etc. on Windows, that I think the best approach is to have
chrome.exe embed the majority of crashpad_handler and jump to it as
early as possible when running in that mode.

So, move most of crashpad_handler into a static_library with just main()
in the executable target.

R=mark@chromium.org
BUG=chromium:546288, crashpad:27

Review URL: https://codereview.chromium.org/1416873016 .
---
 handler/handler.gyp     |  24 ++-
 handler/handler_main.cc | 331 ++++++++++++++++++++++++++++++++++++++++
 handler/handler_main.h  |  28 ++++
 handler/main.cc         | 313 +------------------------------------
 4 files changed, 382 insertions(+), 314 deletions(-)
 create mode 100644 handler/handler_main.cc
 create mode 100644 handler/handler_main.h

diff --git a/handler/handler.gyp b/handler/handler.gyp
index 20df3d73..e7f54c82 100644
--- a/handler/handler.gyp
+++ b/handler/handler.gyp
@@ -19,8 +19,10 @@
   ],
   'targets': [
     {
-      'target_name': 'crashpad_handler',
-      'type': 'executable',
+      # This target exists so that the crashpad_handler can be embedded into
+      # another binary.
+      'target_name': 'crashpad_handler_lib',
+      'type': 'static_library',
       'dependencies': [
         '../client/client.gyp:crashpad_client',
         '../compat/compat.gyp:crashpad_compat',
@@ -40,10 +42,26 @@
         'mac/crash_report_exception_handler.h',
         'mac/exception_handler_server.cc',
         'mac/exception_handler_server.h',
-        'main.cc',
+        'handler_main.cc',
+        'handler_main.h',
         'win/crash_report_exception_handler.cc',
         'win/crash_report_exception_handler.h',
       ],
+    },
+    {
+      'target_name': 'crashpad_handler',
+      'type': 'executable',
+      'dependencies': [
+        '../third_party/mini_chromium/mini_chromium.gyp:base',
+        '../tools/tools.gyp:crashpad_tool_support',
+        'crashpad_handler_lib',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'sources': [
+        'main.cc',
+      ],
 
       'conditions': [
         ['OS=="mac"', {
diff --git a/handler/handler_main.cc b/handler/handler_main.cc
new file mode 100644
index 00000000..11f14ef1
--- /dev/null
+++ b/handler/handler_main.cc
@@ -0,0 +1,331 @@
+// Copyright 2014 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "handler/handler_main.h"
+
+#include <getopt.h>
+#include <stdlib.h>
+
+#include <map>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "client/crash_report_database.h"
+#include "client/crashpad_client.h"
+#include "tools/tool_support.h"
+#include "handler/crash_report_upload_thread.h"
+#include "util/file/file_io.h"
+#include "util/stdlib/map_insert.h"
+#include "util/stdlib/string_number_conversion.h"
+#include "util/string/split_string.h"
+#include "util/synchronization/semaphore.h"
+
+#if defined(OS_MACOSX)
+#include <libgen.h>
+#include "base/mac/scoped_mach_port.h"
+#include "handler/mac/crash_report_exception_handler.h"
+#include "handler/mac/exception_handler_server.h"
+#include "util/mach/child_port_handshake.h"
+#include "util/mach/mach_extensions.h"
+#include "util/posix/close_stdio.h"
+#elif defined(OS_WIN)
+#include <windows.h>
+#include "handler/win/crash_report_exception_handler.h"
+#include "util/win/exception_handler_server.h"
+#include "util/win/handle.h"
+#endif  // OS_MACOSX
+
+namespace crashpad {
+
+namespace {
+
+void Usage(const base::FilePath& me) {
+  fprintf(stderr,
+"Usage: %" PRFilePath " [OPTION]...\n"
+"Crashpad's exception handler server.\n"
+"\n"
+"      --annotation=KEY=VALUE  set a process annotation in each crash report\n"
+"      --database=PATH         store the crash report database at PATH\n"
+#if defined(OS_MACOSX)
+"      --handshake-fd=FD       establish communication with the client over FD\n"
+"      --mach-service=SERVICE  register SERVICE with the bootstrap server\n"
+"      --reset-own-crash-exception-port-to-system-default\n"
+"                              reset the server's exception handler to default\n"
+#elif defined(OS_WIN)
+"      --handshake-handle=HANDLE\n"
+"                              create a new pipe and send its name via HANDLE\n"
+"      --pipe-name=PIPE        communicate with the client over PIPE\n"
+#endif  // OS_MACOSX
+"      --url=URL               send crash reports to this Breakpad server URL,\n"
+"                              only if uploads are enabled for the database\n"
+"      --help                  display this help and exit\n"
+"      --version               output version information and exit\n",
+          me.value().c_str());
+  ToolSupport::UsageTail(me);
+}
+
+}  // namespace
+
+int HandlerMain(int argc, char* argv[]) {
+  const base::FilePath argv0(
+      ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
+  const base::FilePath me(argv0.BaseName());
+
+  enum OptionFlags {
+    // Long options without short equivalents.
+    kOptionLastChar = 255,
+    kOptionAnnotation,
+    kOptionDatabase,
+#if defined(OS_MACOSX)
+    kOptionHandshakeFD,
+    kOptionMachService,
+    kOptionResetOwnCrashExceptionPortToSystemDefault,
+#elif defined(OS_WIN)
+    kOptionHandshakeHandle,
+    kOptionPipeName,
+#endif  // OS_MACOSX
+    kOptionURL,
+
+    // Standard options.
+    kOptionHelp = -2,
+    kOptionVersion = -3,
+  };
+
+  struct {
+    std::map<std::string, std::string> annotations;
+    std::string url;
+    const char* database;
+#if defined(OS_MACOSX)
+    int handshake_fd;
+    std::string mach_service;
+    bool reset_own_crash_exception_port_to_system_default;
+#elif defined(OS_WIN)
+    HANDLE handshake_handle;
+    std::string pipe_name;
+#endif  // OS_MACOSX
+  } options = {};
+#if defined(OS_MACOSX)
+  options.handshake_fd = -1;
+#elif defined(OS_WIN)
+  options.handshake_handle = INVALID_HANDLE_VALUE;
+#endif
+
+  const option long_options[] = {
+      {"annotation", required_argument, nullptr, kOptionAnnotation},
+      {"database", required_argument, nullptr, kOptionDatabase},
+#if defined(OS_MACOSX)
+      {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
+      {"mach-service", required_argument, nullptr, kOptionMachService},
+      {"reset-own-crash-exception-port-to-system-default",
+       no_argument,
+       nullptr,
+       kOptionResetOwnCrashExceptionPortToSystemDefault},
+#elif defined(OS_WIN)
+      {"handshake-handle", required_argument, nullptr, kOptionHandshakeHandle},
+      {"pipe-name", required_argument, nullptr, kOptionPipeName},
+#endif  // OS_MACOSX
+      {"url", required_argument, nullptr, kOptionURL},
+      {"help", no_argument, nullptr, kOptionHelp},
+      {"version", no_argument, nullptr, kOptionVersion},
+      {nullptr, 0, nullptr, 0},
+  };
+
+  int opt;
+  while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
+    switch (opt) {
+      case kOptionAnnotation: {
+        std::string key;
+        std::string value;
+        if (!SplitString(optarg, '=', &key, &value)) {
+          ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE");
+          return EXIT_FAILURE;
+        }
+        std::string old_value;
+        if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) {
+          LOG(WARNING) << "duplicate key " << key << ", discarding value "
+                       << old_value;
+        }
+        break;
+      }
+      case kOptionDatabase: {
+        options.database = optarg;
+        break;
+      }
+#if defined(OS_MACOSX)
+      case kOptionHandshakeFD: {
+        if (!StringToNumber(optarg, &options.handshake_fd) ||
+            options.handshake_fd < 0) {
+          ToolSupport::UsageHint(me,
+                                 "--handshake-fd requires a file descriptor");
+          return EXIT_FAILURE;
+        }
+        break;
+      }
+      case kOptionMachService: {
+        options.mach_service = optarg;
+        break;
+      }
+      case kOptionResetOwnCrashExceptionPortToSystemDefault: {
+        options.reset_own_crash_exception_port_to_system_default = true;
+        break;
+      }
+#elif defined(OS_WIN)
+      case kOptionHandshakeHandle: {
+        // Use unsigned int, because the handle was presented by the client in
+        // 0x%x format.
+        unsigned int handle_uint;
+        if (!StringToNumber(optarg, &handle_uint) ||
+            (options.handshake_handle = IntToHandle(handle_uint)) ==
+                INVALID_HANDLE_VALUE) {
+          ToolSupport::UsageHint(me, "--handshake-handle requires a HANDLE");
+          return EXIT_FAILURE;
+        }
+        break;
+      }
+      case kOptionPipeName: {
+        options.pipe_name = optarg;
+        break;
+      }
+#endif  // OS_MACOSX
+      case kOptionURL: {
+        options.url = optarg;
+        break;
+      }
+      case kOptionHelp: {
+        Usage(me);
+        return EXIT_SUCCESS;
+      }
+      case kOptionVersion: {
+        ToolSupport::Version(me);
+        return EXIT_SUCCESS;
+      }
+      default: {
+        ToolSupport::UsageHint(me, nullptr);
+        return EXIT_FAILURE;
+      }
+    }
+  }
+  argc -= optind;
+  argv += optind;
+
+#if defined(OS_MACOSX)
+  if (options.handshake_fd < 0 && options.mach_service.empty()) {
+    ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required");
+    return EXIT_FAILURE;
+  }
+  if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
+    ToolSupport::UsageHint(
+        me, "--handshake-fd and --mach-service are incompatible");
+    return EXIT_FAILURE;
+  }
+#elif defined(OS_WIN)
+  if (options.handshake_handle == INVALID_HANDLE_VALUE &&
+      options.pipe_name.empty()) {
+    ToolSupport::UsageHint(me, "--handshake-handle or --pipe-name is required");
+    return EXIT_FAILURE;
+  }
+  if (options.handshake_handle != INVALID_HANDLE_VALUE &&
+      !options.pipe_name.empty()) {
+    ToolSupport::UsageHint(
+        me, "--handshake-handle and --pipe-name are incompatible");
+    return EXIT_FAILURE;
+  }
+#endif  // OS_MACOSX
+
+  if (!options.database) {
+    ToolSupport::UsageHint(me, "--database is required");
+    return EXIT_FAILURE;
+  }
+
+  if (argc) {
+    ToolSupport::UsageHint(me, nullptr);
+    return EXIT_FAILURE;
+  }
+
+#if defined(OS_MACOSX)
+  if (options.mach_service.empty()) {
+    // Don’t do this when being run by launchd. See launchd.plist(5).
+    CloseStdinAndStdout();
+  }
+
+  if (options.reset_own_crash_exception_port_to_system_default) {
+    CrashpadClient::UseSystemDefaultHandler();
+  }
+
+  base::mac::ScopedMachReceiveRight receive_right;
+
+  if (options.handshake_fd >= 0) {
+    receive_right.reset(
+        ChildPortHandshake::RunServerForFD(
+            base::ScopedFD(options.handshake_fd),
+            ChildPortHandshake::PortRightType::kReceiveRight));
+  } else if (!options.mach_service.empty()) {
+    receive_right = BootstrapCheckIn(options.mach_service);
+  }
+
+  if (!receive_right.is_valid()) {
+    return EXIT_FAILURE;
+  }
+
+  ExceptionHandlerServer exception_handler_server(
+      receive_right.Pass(), !options.mach_service.empty());
+#elif defined(OS_WIN)
+  ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty());
+
+  std::string pipe_name;
+  if (!options.pipe_name.empty()) {
+    exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
+  } else if (options.handshake_handle != INVALID_HANDLE_VALUE) {
+    std::wstring pipe_name = exception_handler_server.CreatePipe();
+
+    uint32_t pipe_name_length = static_cast<uint32_t>(pipe_name.size());
+    if (!LoggingWriteFile(options.handshake_handle,
+                          &pipe_name_length,
+                          sizeof(pipe_name_length))) {
+      return EXIT_FAILURE;
+    }
+    if (!LoggingWriteFile(options.handshake_handle,
+                          pipe_name.c_str(),
+                          pipe_name.size() * sizeof(pipe_name[0]))) {
+      return EXIT_FAILURE;
+    }
+  }
+#endif  // OS_MACOSX
+
+  scoped_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize(
+      base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType(
+          options.database))));
+  if (!database) {
+    return EXIT_FAILURE;
+  }
+
+  CrashReportUploadThread upload_thread(database.get(), options.url);
+  upload_thread.Start();
+
+  CrashReportExceptionHandler exception_handler(
+      database.get(), &upload_thread, &options.annotations);
+
+  exception_handler_server.Run(&exception_handler);
+
+  upload_thread.Stop();
+
+  return EXIT_SUCCESS;
+}
+
+}  // namespace crashpad
diff --git a/handler/handler_main.h b/handler/handler_main.h
new file mode 100644
index 00000000..5b5568ec
--- /dev/null
+++ b/handler/handler_main.h
@@ -0,0 +1,28 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_HANDLER_HANDLER_MAIN_H_
+#define CRASHPAD_HANDLER_HANDLER_MAIN_H_
+
+namespace crashpad {
+
+//! \brief The `main()` of the `crashpad_handler` binary.
+//!
+//! This is exposed so that `crashpad_handler` can be embedded into another
+//! binary, but called and used as if it were a standalone executable.
+int HandlerMain(int argc, char* argv[]);
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_HANDLER_HANDLER_MAIN_H_
diff --git a/handler/main.cc b/handler/main.cc
index 0ec6e7f2..03ee87fb 100644
--- a/handler/main.cc
+++ b/handler/main.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Crashpad Authors. All rights reserved.
+// Copyright 2015 The Crashpad Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -12,319 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <getopt.h>
-#include <stdlib.h>
+#include "handler/main.h"
 
-#include <map>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/files/scoped_file.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "client/crash_report_database.h"
-#include "client/crashpad_client.h"
 #include "tools/tool_support.h"
-#include "handler/crash_report_upload_thread.h"
-#include "util/file/file_io.h"
-#include "util/stdlib/map_insert.h"
-#include "util/stdlib/string_number_conversion.h"
-#include "util/string/split_string.h"
-#include "util/synchronization/semaphore.h"
-
-#if defined(OS_MACOSX)
-#include <libgen.h>
-#include "base/mac/scoped_mach_port.h"
-#include "handler/mac/crash_report_exception_handler.h"
-#include "handler/mac/exception_handler_server.h"
-#include "util/mach/child_port_handshake.h"
-#include "util/mach/mach_extensions.h"
-#include "util/posix/close_stdio.h"
-#elif defined(OS_WIN)
-#include <windows.h>
-#include "handler/win/crash_report_exception_handler.h"
-#include "util/win/exception_handler_server.h"
-#include "util/win/handle.h"
-#endif  // OS_MACOSX
-
-namespace crashpad {
-namespace {
-
-void Usage(const base::FilePath& me) {
-  fprintf(stderr,
-"Usage: %" PRFilePath " [OPTION]...\n"
-"Crashpad's exception handler server.\n"
-"\n"
-"      --annotation=KEY=VALUE  set a process annotation in each crash report\n"
-"      --database=PATH         store the crash report database at PATH\n"
-#if defined(OS_MACOSX)
-"      --handshake-fd=FD       establish communication with the client over FD\n"
-"      --mach-service=SERVICE  register SERVICE with the bootstrap server\n"
-"      --reset-own-crash-exception-port-to-system-default\n"
-"                              reset the server's exception handler to default\n"
-#elif defined(OS_WIN)
-"      --handshake-handle=HANDLE\n"
-"                              create a new pipe and send its name via HANDLE\n"
-"      --pipe-name=PIPE        communicate with the client over PIPE\n"
-#endif  // OS_MACOSX
-"      --url=URL               send crash reports to this Breakpad server URL,\n"
-"                              only if uploads are enabled for the database\n"
-"      --help                  display this help and exit\n"
-"      --version               output version information and exit\n",
-          me.value().c_str());
-  ToolSupport::UsageTail(me);
-}
-
-int HandlerMain(int argc, char* argv[]) {
-  const base::FilePath argv0(
-      ToolSupport::CommandLineArgumentToFilePathStringType(argv[0]));
-  const base::FilePath me(argv0.BaseName());
-
-  enum OptionFlags {
-    // Long options without short equivalents.
-    kOptionLastChar = 255,
-    kOptionAnnotation,
-    kOptionDatabase,
-#if defined(OS_MACOSX)
-    kOptionHandshakeFD,
-    kOptionMachService,
-    kOptionResetOwnCrashExceptionPortToSystemDefault,
-#elif defined(OS_WIN)
-    kOptionHandshakeHandle,
-    kOptionPipeName,
-#endif  // OS_MACOSX
-    kOptionURL,
-
-    // Standard options.
-    kOptionHelp = -2,
-    kOptionVersion = -3,
-  };
-
-  struct {
-    std::map<std::string, std::string> annotations;
-    std::string url;
-    const char* database;
-#if defined(OS_MACOSX)
-    int handshake_fd;
-    std::string mach_service;
-    bool reset_own_crash_exception_port_to_system_default;
-#elif defined(OS_WIN)
-    HANDLE handshake_handle;
-    std::string pipe_name;
-#endif  // OS_MACOSX
-  } options = {};
-#if defined(OS_MACOSX)
-  options.handshake_fd = -1;
-#elif defined(OS_WIN)
-  options.handshake_handle = INVALID_HANDLE_VALUE;
-#endif
-
-  const option long_options[] = {
-      {"annotation", required_argument, nullptr, kOptionAnnotation},
-      {"database", required_argument, nullptr, kOptionDatabase},
-#if defined(OS_MACOSX)
-      {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD},
-      {"mach-service", required_argument, nullptr, kOptionMachService},
-      {"reset-own-crash-exception-port-to-system-default",
-       no_argument,
-       nullptr,
-       kOptionResetOwnCrashExceptionPortToSystemDefault},
-#elif defined(OS_WIN)
-      {"handshake-handle", required_argument, nullptr, kOptionHandshakeHandle},
-      {"pipe-name", required_argument, nullptr, kOptionPipeName},
-#endif  // OS_MACOSX
-      {"url", required_argument, nullptr, kOptionURL},
-      {"help", no_argument, nullptr, kOptionHelp},
-      {"version", no_argument, nullptr, kOptionVersion},
-      {nullptr, 0, nullptr, 0},
-  };
-
-  int opt;
-  while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
-    switch (opt) {
-      case kOptionAnnotation: {
-        std::string key;
-        std::string value;
-        if (!SplitString(optarg, '=', &key, &value)) {
-          ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE");
-          return EXIT_FAILURE;
-        }
-        std::string old_value;
-        if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) {
-          LOG(WARNING) << "duplicate key " << key << ", discarding value "
-                       << old_value;
-        }
-        break;
-      }
-      case kOptionDatabase: {
-        options.database = optarg;
-        break;
-      }
-#if defined(OS_MACOSX)
-      case kOptionHandshakeFD: {
-        if (!StringToNumber(optarg, &options.handshake_fd) ||
-            options.handshake_fd < 0) {
-          ToolSupport::UsageHint(me,
-                                 "--handshake-fd requires a file descriptor");
-          return EXIT_FAILURE;
-        }
-        break;
-      }
-      case kOptionMachService: {
-        options.mach_service = optarg;
-        break;
-      }
-      case kOptionResetOwnCrashExceptionPortToSystemDefault: {
-        options.reset_own_crash_exception_port_to_system_default = true;
-        break;
-      }
-#elif defined(OS_WIN)
-      case kOptionHandshakeHandle: {
-        // Use unsigned int, because the handle was presented by the client in
-        // 0x%x format.
-        unsigned int handle_uint;
-        if (!StringToNumber(optarg, &handle_uint) ||
-            (options.handshake_handle = IntToHandle(handle_uint)) ==
-                INVALID_HANDLE_VALUE) {
-          ToolSupport::UsageHint(me, "--handshake-handle requires a HANDLE");
-          return EXIT_FAILURE;
-        }
-        break;
-      }
-      case kOptionPipeName: {
-        options.pipe_name = optarg;
-        break;
-      }
-#endif  // OS_MACOSX
-      case kOptionURL: {
-        options.url = optarg;
-        break;
-      }
-      case kOptionHelp: {
-        Usage(me);
-        return EXIT_SUCCESS;
-      }
-      case kOptionVersion: {
-        ToolSupport::Version(me);
-        return EXIT_SUCCESS;
-      }
-      default: {
-        ToolSupport::UsageHint(me, nullptr);
-        return EXIT_FAILURE;
-      }
-    }
-  }
-  argc -= optind;
-  argv += optind;
-
-#if defined(OS_MACOSX)
-  if (options.handshake_fd < 0 && options.mach_service.empty()) {
-    ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required");
-    return EXIT_FAILURE;
-  }
-  if (options.handshake_fd >= 0 && !options.mach_service.empty()) {
-    ToolSupport::UsageHint(
-        me, "--handshake-fd and --mach-service are incompatible");
-    return EXIT_FAILURE;
-  }
-#elif defined(OS_WIN)
-  if (options.handshake_handle == INVALID_HANDLE_VALUE &&
-      options.pipe_name.empty()) {
-    ToolSupport::UsageHint(me, "--handshake-handle or --pipe-name is required");
-    return EXIT_FAILURE;
-  }
-  if (options.handshake_handle != INVALID_HANDLE_VALUE &&
-      !options.pipe_name.empty()) {
-    ToolSupport::UsageHint(
-        me, "--handshake-handle and --pipe-name are incompatible");
-    return EXIT_FAILURE;
-  }
-#endif  // OS_MACOSX
-
-  if (!options.database) {
-    ToolSupport::UsageHint(me, "--database is required");
-    return EXIT_FAILURE;
-  }
-
-  if (argc) {
-    ToolSupport::UsageHint(me, nullptr);
-    return EXIT_FAILURE;
-  }
-
-#if defined(OS_MACOSX)
-  if (options.mach_service.empty()) {
-    // Don’t do this when being run by launchd. See launchd.plist(5).
-    CloseStdinAndStdout();
-  }
-
-  if (options.reset_own_crash_exception_port_to_system_default) {
-    CrashpadClient::UseSystemDefaultHandler();
-  }
-
-  base::mac::ScopedMachReceiveRight receive_right;
-
-  if (options.handshake_fd >= 0) {
-    receive_right.reset(
-        ChildPortHandshake::RunServerForFD(
-            base::ScopedFD(options.handshake_fd),
-            ChildPortHandshake::PortRightType::kReceiveRight));
-  } else if (!options.mach_service.empty()) {
-    receive_right = BootstrapCheckIn(options.mach_service);
-  }
-
-  if (!receive_right.is_valid()) {
-    return EXIT_FAILURE;
-  }
-
-  ExceptionHandlerServer exception_handler_server(
-      receive_right.Pass(), !options.mach_service.empty());
-#elif defined(OS_WIN)
-  ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty());
-
-  std::string pipe_name;
-  if (!options.pipe_name.empty()) {
-    exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
-  } else if (options.handshake_handle != INVALID_HANDLE_VALUE) {
-    std::wstring pipe_name = exception_handler_server.CreatePipe();
-
-    uint32_t pipe_name_length = static_cast<uint32_t>(pipe_name.size());
-    if (!LoggingWriteFile(options.handshake_handle,
-                          &pipe_name_length,
-                          sizeof(pipe_name_length))) {
-      return EXIT_FAILURE;
-    }
-    if (!LoggingWriteFile(options.handshake_handle,
-                          pipe_name.c_str(),
-                          pipe_name.size() * sizeof(pipe_name[0]))) {
-      return EXIT_FAILURE;
-    }
-  }
-#endif  // OS_MACOSX
-
-  scoped_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize(
-      base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType(
-          options.database))));
-  if (!database) {
-    return EXIT_FAILURE;
-  }
-
-  CrashReportUploadThread upload_thread(database.get(), options.url);
-  upload_thread.Start();
-
-  CrashReportExceptionHandler exception_handler(
-      database.get(), &upload_thread, &options.annotations);
-
-  exception_handler_server.Run(&exception_handler);
-
-  upload_thread.Stop();
-
-  return EXIT_SUCCESS;
-}
-
-}  // namespace
-}  // namespace crashpad
 
 #if defined(OS_MACOSX)
 int main(int argc, char* argv[]) {

From 6c1bd97df0a2f3a483ed4f36b63569485ca8b07e Mon Sep 17 00:00:00 2001
From: Scott Graham <scottmg@chromium.org>
Date: Fri, 6 Nov 2015 10:59:33 -0800
Subject: [PATCH 08/12] Fix compile after 20869d9

TBR=mark@chromium.org
BUG=chromium:546288

Review URL: https://codereview.chromium.org/1431813003 .
---
 handler/main.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/handler/main.cc b/handler/main.cc
index 03ee87fb..f326bd7c 100644
--- a/handler/main.cc
+++ b/handler/main.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "handler/main.h"
+#include "handler/handler_main.h"
 
 #include "build/build_config.h"
 #include "tools/tool_support.h"

From b666bcbe98c67256a64418313755a40fea2992d6 Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Fri, 6 Nov 2015 15:03:13 -0500
Subject: [PATCH 09/12] win: Use signed int as the integer representation of
 HANDLEs

HandleToInt() and IntToHandle() use int, a signed type, for the 32-bit
integer representation of HANDLE values. For opaque values, an unsigned
type would normally be used, but in this case, signed was chosen for
sign extension to work correctly. INVALID_HANDLE_VALUE is defined as
((HANDLE)(LONG_PTR)-1), and this needs to round-trip through the chosen
integer representation back to the same HANDLE value. Sign extension is
also recommended by
https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203.

As suggested in
https://codereview.chromium.org/1422503015/diff/1/util/win/handle.cc#newcode24

R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1422023010 .
---
 test/win/win_child_process.cc        |  4 ++++
 util/win/handle.h                    | 24 ++++++++++++------------
 util/win/process_info.h              |  2 +-
 util/win/process_info_test.cc        |  9 ++++-----
 util/win/registration_protocol_win.h | 20 ++++++++++----------
 5 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/test/win/win_child_process.cc b/test/win/win_child_process.cc
index b6cbbbd2..6b7a1a07 100644
--- a/test/win/win_child_process.cc
+++ b/test/win/win_child_process.cc
@@ -142,9 +142,13 @@ WinChildProcess::WinChildProcess() {
   // values are passed to the child on the command line.
   std::string left, right;
   CHECK(SplitString(switch_value, '|', &left, &right));
+
+  // left and right were formatted as 0x%x, so they need to be converted as
+  // unsigned ints.
   unsigned int write, read;
   CHECK(StringToNumber(left, &write));
   CHECK(StringToNumber(right, &read));
+
   pipe_write_.reset(IntToHandle(write));
   pipe_read_.reset(IntToHandle(read));
 
diff --git a/util/win/handle.h b/util/win/handle.h
index c5a96cae..8a630690 100644
--- a/util/win/handle.h
+++ b/util/win/handle.h
@@ -21,17 +21,17 @@ namespace crashpad {
 
 //! \brief Converts a `HANDLE` to an `int`.
 //!
-//! `HANDLE` is a `typedef` for `void *`, but `HANDLE` values aren’t necessarily
-//! pointers to anything. Only 32 bits of shareable `HANDLE`s are significant,
-//! even in 64-bit processes on 64-bit operating systems. See <a
+//! `HANDLE` is a `typedef` for `void *`, but kernel `HANDLE` values aren’t
+//! pointers to anything. Only 32 bits of kernel `HANDLE`s are significant, even
+//! in 64-bit processes on 64-bit operating systems. See <a
 //! href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203">Interprocess
 //! Communication Between 32-bit and 64-bit Applications</a>.
 //!
-//! This function safely converts a shareable `HANDLE` to an `int` similarly to
-//! a cast operation. It checks that the operation can be performed safely, and
+//! This function safely converts a kernel `HANDLE` to an `int` similarly to a
+//! cast operation. It checks that the operation can be performed safely, and
 //! aborts execution if it cannot.
 //!
-//! \param[in] handle The shareable `HANDLE` to convert.
+//! \param[in] handle The kernel `HANDLE` to convert.
 //!
 //! \return An equivalent `int`, truncated (if necessary) from \a handle. If
 //!     truncation would have resulted in an `int` that could not be converted
@@ -42,20 +42,20 @@ int HandleToInt(HANDLE handle);
 
 //! \brief Converts an `int` to an `HANDLE`.
 //!
-//! `HANDLE` is a `typedef` for `void *`, but `HANDLE` values aren’t necessarily
-//! pointers to anything. Only 32 bits of shareable `HANDLE`s are significant,
-//! even in 64-bit processes on 64-bit operating systems. See <a
+//! `HANDLE` is a `typedef` for `void *`, but kernel `HANDLE` values aren’t
+//! pointers to anything. Only 32 bits of kernel `HANDLE`s are significant, even
+//! in 64-bit processes on 64-bit operating systems. See <a
 //! href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203">Interprocess
 //! Communication Between 32-bit and 64-bit Applications</a>.
 //!
-//! This function safely convert an `int` to a shareable `HANDLE` similarly to a
+//! This function safely convert an `int` to a kernel `HANDLE` similarly to a
 //! cast operation.
 //!
 //! \param[in] handle_int The `int` to convert. This must have been produced by
 //!     HandleToInt(), possibly in a different process.
 //!
-//! \return An equivalent shareable `HANDLE`, sign-extended (if necessary) from
-//!     \a handle_int.
+//! \return An equivalent kernel `HANDLE`, sign-extended (if necessary) from \a
+//!     handle_int.
 //!
 //! \sa HandleToInt()
 HANDLE IntToHandle(int handle_int);
diff --git a/util/win/process_info.h b/util/win/process_info.h
index 49a6f354..fb1b8b3e 100644
--- a/util/win/process_info.h
+++ b/util/win/process_info.h
@@ -58,7 +58,7 @@ class ProcessInfo {
     std::wstring type_name;
 
     //! \brief The handle's value.
-    uint32_t handle;
+    int handle;
 
     //! \brief The attributes for the handle, e.g. `OBJ_INHERIT`,
     //!     `OBJ_CASE_INSENSITIVE`, etc.
diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc
index 7bf0f4ef..74f086db 100644
--- a/util/win/process_info_test.cc
+++ b/util/win/process_info_test.cc
@@ -576,8 +576,7 @@ TEST(ProcessInfo, Handles) {
   bool found_key_handle = false;
   bool found_mapping_handle = false;
   for (auto handle : info.Handles()) {
-    const int handle_int = implicit_cast<int>(handle.handle);
-    if (handle_int == HandleToInt(file.get())) {
+    if (handle.handle == HandleToInt(file.get())) {
       EXPECT_FALSE(found_file_handle);
       found_file_handle = true;
       EXPECT_EQ(L"File", handle.type_name);
@@ -587,7 +586,7 @@ TEST(ProcessInfo, Handles) {
                 handle.granted_access & STANDARD_RIGHTS_ALL);
       EXPECT_EQ(0, handle.attributes);
     }
-    if (handle_int == HandleToInt(inherited_file.get())) {
+    if (handle.handle == HandleToInt(inherited_file.get())) {
       EXPECT_FALSE(found_inherited_file_handle);
       found_inherited_file_handle = true;
       EXPECT_EQ(L"File", handle.type_name);
@@ -601,7 +600,7 @@ TEST(ProcessInfo, Handles) {
       const int kObjInherit = 0x2;
       EXPECT_EQ(kObjInherit, handle.attributes);
     }
-    if (handle_int == HandleToInt(scoped_key.get())) {
+    if (handle.handle == HandleToInt(scoped_key.get())) {
       EXPECT_FALSE(found_key_handle);
       found_key_handle = true;
       EXPECT_EQ(L"Key", handle.type_name);
@@ -611,7 +610,7 @@ TEST(ProcessInfo, Handles) {
                 handle.granted_access & STANDARD_RIGHTS_ALL);
       EXPECT_EQ(0, handle.attributes);
     }
-    if (handle_int == HandleToInt(mapping.get())) {
+    if (handle.handle == HandleToInt(mapping.get())) {
       EXPECT_FALSE(found_mapping_handle);
       found_mapping_handle = true;
       EXPECT_EQ(L"Section", handle.type_name);
diff --git a/util/win/registration_protocol_win.h b/util/win/registration_protocol_win.h
index f2d9e29c..c57c6e20 100644
--- a/util/win/registration_protocol_win.h
+++ b/util/win/registration_protocol_win.h
@@ -92,22 +92,22 @@ struct ClientToServerMessage {
   };
 };
 
-//! \brief  A client registration response.
+//! \brief A client registration response.
 struct RegistrationResponse {
   //! \brief An event `HANDLE`, valid in the client process, that should be
-  //!     signaled to request a crash report. 64-bit clients should convert the
-  //!     value to a `HANDLE` using sign-extension.
-  uint32_t request_crash_dump_event;
+  //!     signaled to request a crash report. Clients should convert the value
+  //!     to a `HANDLE` by calling IntToHandle().
+  int request_crash_dump_event;
 
   //! \brief An event `HANDLE`, valid in the client process, that should be
-  //!     signaled to request a non-crashing dump be taken. 64-bit clients
-  //!     should convert the value to `HANDLEEE` using sign-extension.
-  uint32_t request_non_crash_dump_event;
+  //!     signaled to request a non-crashing dump be taken. Clients should
+  //!     convert the value to a `HANDLE` by calling IntToHandle().
+  int request_non_crash_dump_event;
 
   //! \brief An event `HANDLE`, valid in the client process, that will be
-  //!     signaled by the server when the non-crashing dump is complete. 64-bit
-  //!     clients should convert the value to `HANDLEEE` using sign-extension.
-  uint32_t non_crash_dump_completed_event;
+  //!     signaled by the server when the non-crashing dump is complete. Clients
+  //!     should convert the value to a `HANDLE` by calling IntToHandle().
+  int non_crash_dump_completed_event;
 };
 
 //! \brief The response sent back to the client via SendToCrashHandlerServer().

From d3825afb25a02aaeae466d37debcf2a9935b7266 Mon Sep 17 00:00:00 2001
From: Mark Mentovai <mark@chromium.org>
Date: Fri, 6 Nov 2015 16:55:31 -0500
Subject: [PATCH 10/12] win: Make StartHandler() restrict HANDLES inherited by
 crashpad_handler

This requires Windows NT 6.0 (Vista and Server 2008). On earlier
operating system versions, the existing behavior of inheriting all
inheritable handles is retained.

BUG=crashpad:69
R=scottmg@chromium.org

Review URL: https://codereview.chromium.org/1427273003 .
---
 client/crashpad_client_win.cc | 116 +++++++++++++++++++++++++++++++---
 1 file changed, 108 insertions(+), 8 deletions(-)

diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc
index 46b61372..13ef3d62 100644
--- a/client/crashpad_client_win.cc
+++ b/client/crashpad_client_win.cc
@@ -19,6 +19,8 @@
 
 #include "base/atomicops.h"
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/scoped_generic.h"
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
@@ -26,6 +28,7 @@
 #include "util/file/file_io.h"
 #include "util/win/command_line.h"
 #include "util/win/critical_section_with_debug_info.h"
+#include "util/win/get_function.h"
 #include "util/win/handle.h"
 #include "util/win/registration_protocol_win.h"
 #include "util/win/scoped_handle.h"
@@ -110,6 +113,40 @@ std::wstring FormatArgumentString(const std::string& name,
   return std::wstring(L"--") + base::UTF8ToUTF16(name) + L"=" + value;
 }
 
+struct ScopedProcThreadAttributeListTraits {
+  static PPROC_THREAD_ATTRIBUTE_LIST InvalidValue() {
+    return nullptr;
+  }
+
+  static void Free(PPROC_THREAD_ATTRIBUTE_LIST proc_thread_attribute_list) {
+    // This is able to use GET_FUNCTION_REQUIRED() instead of GET_FUNCTION()
+    // because it will only be called if InitializeProcThreadAttributeList() and
+    // UpdateProcThreadAttribute() are present.
+    static const auto delete_proc_thread_attribute_list =
+        GET_FUNCTION_REQUIRED(L"kernel32.dll", ::DeleteProcThreadAttributeList);
+    delete_proc_thread_attribute_list(proc_thread_attribute_list);
+  }
+};
+
+using ScopedProcThreadAttributeList =
+    base::ScopedGeneric<PPROC_THREAD_ATTRIBUTE_LIST,
+                        ScopedProcThreadAttributeListTraits>;
+
+// Adds |handle| to |handle_list| if it appears valid.
+//
+// Invalid handles (including INVALID_HANDLE_VALUE and null handles) cannot be
+// added to a PPROC_THREAD_ATTRIBUTE_LIST’s PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+// If INVALID_HANDLE_VALUE appears, CreateProcess() will fail with
+// ERROR_INVALID_PARAMETER. If a null handle appears, the child process will
+// silently not inherit any handles.
+//
+// Use this function to add handles with uncertain validities.
+void AddHandleToListIfValid(std::vector<HANDLE>* handle_list, HANDLE handle) {
+  if (handle && handle != INVALID_HANDLE_VALUE) {
+    handle_list->push_back(handle);
+  }
+}
+
 }  // namespace
 
 namespace crashpad {
@@ -172,22 +209,85 @@ bool CrashpadClient::StartHandler(
                                            HandleToInt(pipe_write))),
       &command_line);
 
-  STARTUPINFO startup_info = {};
-  startup_info.cb = sizeof(startup_info);
-  startup_info.dwFlags = STARTF_USESTDHANDLES;
-  startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
-  startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-  startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+  DWORD creation_flags;
+  STARTUPINFOEX startup_info = {};
+  startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+  startup_info.StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+  startup_info.StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+  startup_info.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+  std::vector<HANDLE> handle_list;
+  scoped_ptr<uint8_t[]> proc_thread_attribute_list_storage;
+  ScopedProcThreadAttributeList proc_thread_attribute_list_owner;
+
+  static const auto initialize_proc_thread_attribute_list =
+      GET_FUNCTION(L"kernel32.dll", ::InitializeProcThreadAttributeList);
+  static const auto update_proc_thread_attribute =
+      initialize_proc_thread_attribute_list
+          ? GET_FUNCTION(L"kernel32.dll", ::UpdateProcThreadAttribute)
+          : nullptr;
+  if (!initialize_proc_thread_attribute_list || !update_proc_thread_attribute) {
+    // The OS doesn’t allow handle inheritance to be restricted, so the handler
+    // will inherit every inheritable handle.
+    creation_flags = 0;
+    startup_info.StartupInfo.cb = sizeof(startup_info.StartupInfo);
+  } else {
+    // Restrict handle inheritance to just those needed in the handler.
+
+    creation_flags = EXTENDED_STARTUPINFO_PRESENT;
+    startup_info.StartupInfo.cb = sizeof(startup_info);
+    SIZE_T size;
+    rv = initialize_proc_thread_attribute_list(nullptr, 1, 0, &size);
+    if (rv) {
+      LOG(ERROR) << "InitializeProcThreadAttributeList (size) succeeded, "
+                    "expected failure";
+      return false;
+    } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+      PLOG(ERROR) << "InitializeProcThreadAttributeList (size)";
+      return false;
+    }
+
+    proc_thread_attribute_list_storage.reset(new uint8_t[size]);
+    startup_info.lpAttributeList =
+        reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(
+            proc_thread_attribute_list_storage.get());
+    rv = initialize_proc_thread_attribute_list(
+        startup_info.lpAttributeList, 1, 0, &size);
+    if (!rv) {
+      PLOG(ERROR) << "InitializeProcThreadAttributeList";
+      return false;
+    }
+    proc_thread_attribute_list_owner.reset(startup_info.lpAttributeList);
+
+    handle_list.reserve(4);
+    handle_list.push_back(pipe_write);
+    AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdInput);
+    AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdOutput);
+    AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdError);
+    rv = update_proc_thread_attribute(
+        startup_info.lpAttributeList,
+        0,
+        PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+        &handle_list[0],
+        handle_list.size() * sizeof(handle_list[0]),
+        nullptr,
+        nullptr);
+    if (!rv) {
+      PLOG(ERROR) << "UpdateProcThreadAttribute";
+      return false;
+    }
+  }
+
   PROCESS_INFORMATION process_info;
   rv = CreateProcess(handler.value().c_str(),
                      &command_line[0],
                      nullptr,
                      nullptr,
                      true,
-                     0,
+                     creation_flags,
                      nullptr,
                      nullptr,
-                     &startup_info,
+                     &startup_info.StartupInfo,
                      &process_info);
   if (!rv) {
     PLOG(ERROR) << "CreateProcess";

From 9e4cd8f07b107edf9cbba5c5760967d5aeb8e2bd Mon Sep 17 00:00:00 2001
From: Scott Graham <scottmg@chromium.org>
Date: Fri, 6 Nov 2015 14:08:13 -0800
Subject: [PATCH 11/12] win: Add DumpAndCrash to client

Something like this is required to implement something like
https://code.google.com/p/chromium/codesearch#chromium/src/components/crash/content/app/breakpad_win.cc&l=397
in Chrome (used by Syzygy and V8 in x64 it looks like).

I didn't want to expose UnhandledExceptionFilter() directly as it's
__stdcall so adding a forwarder to CrashpadClient seemed tidier, but the
functionality matches what is needed.

R=mark@chromium.org
BUG=chromium:546288

Review URL: https://codereview.chromium.org/1416603010 .
---
 client/crashpad_client.h      | 10 ++++++++++
 client/crashpad_client_win.cc |  5 +++++
 2 files changed, 15 insertions(+)

diff --git a/client/crashpad_client.h b/client/crashpad_client.h
index eb3fc6de..79a4900e 100644
--- a/client/crashpad_client.h
+++ b/client/crashpad_client.h
@@ -142,6 +142,16 @@ class CrashpadClient {
   //! \param[in] context A `CONTEXT`, generally captured by CaptureContext() or
   //!     similar.
   static void DumpWithoutCrash(const CONTEXT& context);
+
+  //! \brief Requests that the handler capture a dump using the given \a
+  //!     exception_pointers to get the `EXCEPTION_RECORD` and `CONTEXT`.
+  //!
+  //! This function is not necessary in general usage as an unhandled exception
+  //! filter is installed by UseHandler().
+  //!
+  //! \param[in] exception_pointers An `EXCEPTION_POINTERS`, as would generally
+  //!     passed to an unhandled exception filter.
+  static void DumpAndCrash(EXCEPTION_POINTERS* exception_pointers);
 #endif
 
   //! \brief Configures the process to direct its crashes to a Crashpad handler.
diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc
index 13ef3d62..8faebbf2 100644
--- a/client/crashpad_client_win.cc
+++ b/client/crashpad_client_win.cc
@@ -435,4 +435,9 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) {
   PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject";
 }
 
+// static
+void CrashpadClient::DumpAndCrash(EXCEPTION_POINTERS* exception_pointers) {
+  UnhandledExceptionHandler(exception_pointers);
+}
+
 }  // namespace crashpad

From ff274507dc30cb3b4273a04cd73f3ab5240d02e7 Mon Sep 17 00:00:00 2001
From: Scott Graham <scottmg@chromium.org>
Date: Fri, 6 Nov 2015 15:54:48 -0800
Subject: [PATCH 12/12] win: Only retry in UseHandler() loop on ERROR_PIPE_BUSY

This is better because now end_to_end_test.py fails immediately with

[1180:9020:20151106,145204.830:ERROR registration_protocol_win.cc:39] CreateFile: The system cannot find the file specified.  (0x2)

R=mark@chromium.org
BUG=crashpad:75

Review URL: https://codereview.chromium.org/1409693011 .
---
 snapshot/win/end_to_end_test.py       |  9 +++++++++
 util/win/registration_protocol_win.cc | 24 ++++++++++++++++--------
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/snapshot/win/end_to_end_test.py b/snapshot/win/end_to_end_test.py
index 3bbcdb98..ddf48ef2 100644
--- a/snapshot/win/end_to_end_test.py
+++ b/snapshot/win/end_to_end_test.py
@@ -21,6 +21,7 @@ import re
 import subprocess
 import sys
 import tempfile
+import time
 
 g_temp_dirs = []
 
@@ -101,6 +102,14 @@ def GetDumpFromProgram(out_dir, pipe_name, executable_name):
           '--database=' + test_database
       ])
 
+      # Wait until the server is ready.
+      printed = False
+      while not os.path.exists(pipe_name):
+        if not printed:
+          print 'Waiting for crashpad_handler to be ready...'
+          printed = True
+        time.sleep(0.1)
+
       subprocess.call([os.path.join(out_dir, executable_name), pipe_name])
     else:
       subprocess.call([os.path.join(out_dir, executable_name),
diff --git a/util/win/registration_protocol_win.cc b/util/win/registration_protocol_win.cc
index 3e0fdf21..38b1b451 100644
--- a/util/win/registration_protocol_win.cc
+++ b/util/win/registration_protocol_win.cc
@@ -24,8 +24,8 @@ namespace crashpad {
 bool SendToCrashHandlerServer(const base::string16& pipe_name,
                               const crashpad::ClientToServerMessage& message,
                               crashpad::ServerToClientMessage* response) {
-  int tries = 5;
-  while (tries > 0) {
+  int tries = 0;
+  for (;;) {
     ScopedFileHANDLE pipe(
         CreateFile(pipe_name.c_str(),
                    GENERIC_READ | GENERIC_WRITE,
@@ -35,10 +35,20 @@ bool SendToCrashHandlerServer(const base::string16& pipe_name,
                    SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION,
                    nullptr));
     if (!pipe.is_valid()) {
-      Sleep(10);
-      --tries;
+      if (++tries == 5 || GetLastError() != ERROR_PIPE_BUSY) {
+        PLOG(ERROR) << "CreateFile";
+        return false;
+      }
+
+      if (!WaitNamedPipe(pipe_name.c_str(), 1000) &&
+          GetLastError() != ERROR_SEM_TIMEOUT) {
+        PLOG(ERROR) << "WaitNamedPipe";
+        return false;
+      }
+
       continue;
     }
+
     DWORD mode = PIPE_READMODE_MESSAGE;
     if (!SetNamedPipeHandleState(pipe.get(), &mode, nullptr, nullptr)) {
       PLOG(ERROR) << "SetNamedPipeHandleState";
@@ -55,7 +65,8 @@ bool SendToCrashHandlerServer(const base::string16& pipe_name,
         &bytes_read,
         nullptr);
     if (!result) {
-      PLOG(ERROR) << "TransactNamedPipe";
+      LOG(ERROR) << "TransactNamedPipe: expected " << sizeof(*response)
+                 << ", observed " << bytes_read;
       return false;
     }
     if (bytes_read != sizeof(*response)) {
@@ -64,9 +75,6 @@ bool SendToCrashHandlerServer(const base::string16& pipe_name,
     }
     return true;
   }
-
-  LOG(ERROR) << "failed to connect after retrying";
-  return false;
 }
 
 }  // namespace crashpad