Merge pull request #1699 from drwez/suppressDefault

Suppress default exception handling
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc
index 2f772f6..8ae9968 100644
--- a/googletest/src/gtest-death-test.cc
+++ b/googletest/src/gtest-death-test.cc
@@ -67,6 +67,7 @@
 #  include <lib/fdio/spawn.h>
 #  include <zircon/processargs.h>
 #  include <zircon/syscalls.h>
+#  include <zircon/syscalls/port.h>
 # endif  // GTEST_OS_FUCHSIA
 
 #endif  // GTEST_HAS_DEATH_TEST
@@ -805,6 +806,12 @@
                    const char* file,
                    int line)
       : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+  virtual ~FuchsiaDeathTest() {
+    zx_status_t status = zx_handle_close(child_process_);
+    GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+    status = zx_handle_close(port_);
+    GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+  }
 
   // All of these virtual functions are inherited from DeathTest.
   virtual int Wait();
@@ -816,7 +823,8 @@
   // The line number on which the death test is located.
   const int line_;
 
-  zx_handle_t child_process_;
+  zx_handle_t child_process_ = ZX_HANDLE_INVALID;
+  zx_handle_t port_ = ZX_HANDLE_INVALID;
 };
 
 // Utility class for accumulating command-line arguments.
@@ -863,16 +871,38 @@
   if (!spawned())
     return 0;
 
-  // Wait for child process to terminate.
+  // Register to wait for the child process to terminate.
   zx_status_t status_zx;
-  zx_signals_t signals;
-  status_zx = zx_object_wait_one(
-      child_process_,
-      ZX_PROCESS_TERMINATED,
-      ZX_TIME_INFINITE,
-      &signals);
+  status_zx = zx_object_wait_async(child_process_,
+                                   port_,
+                                   0 /* key */,
+                                   ZX_PROCESS_TERMINATED,
+                                   ZX_WAIT_ASYNC_ONCE);
   GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
 
+  // Wait for it to terminate, or an exception to be received.
+  zx_port_packet_t packet;
+  status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet);
+  GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+  if (ZX_PKT_IS_EXCEPTION(packet.type)) {
+    // Process encountered an exception. Kill it directly rather than letting
+    // other handlers process the event.
+    status_zx = zx_task_kill(child_process_);
+    GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+    // Now wait for |child_process_| to terminate.
+    zx_signals_t signals = 0;
+    status_zx = zx_object_wait_one(
+        child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals);
+    GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+    GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED);
+  } else {
+    // Process terminated.
+    GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+    GTEST_DEATH_TEST_CHECK_(packet.observed & ZX_PROCESS_TERMINATED);
+  }
+
   ReadAndInterpretStatusByte();
 
   zx_info_process_t buffer;
@@ -936,13 +966,10 @@
   set_read_fd(status);
 
   // Set the pipe handle for the child.
-  fdio_spawn_action_t add_handle_action = {
-    .action = FDIO_SPAWN_ACTION_ADD_HANDLE,
-    .h = {
-      .id = PA_HND(type, kFuchsiaReadPipeFd),
-      .handle = child_pipe_handle
-    }
-  };
+  fdio_spawn_action_t add_handle_action = {};
+  add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE;
+  add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd);
+  add_handle_action.h.handle = child_pipe_handle;
 
   // Spawn the child process.
   status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL,
@@ -950,6 +977,14 @@
                           &add_handle_action, &child_process_, nullptr);
   GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
 
+  // Create an exception port and attach it to the |child_process_|, to allow
+  // us to suppress the system default exception handler from firing.
+  status = zx_port_create(0, &port_);
+  GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+  status = zx_task_bind_exception_port(
+      child_process_, port_, 0 /* key */, 0 /*options */);
+  GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
   set_spawned(true);
   return OVERSEE_TEST;
 }