aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--googletest/src/gtest-death-test.cc65
1 files changed, 50 insertions, 15 deletions
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc
index 2f772f6f..8ae9968d 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 @@ class FuchsiaDeathTest : public DeathTestImpl {
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 @@ class FuchsiaDeathTest : public DeathTestImpl {
// 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 @@ int FuchsiaDeathTest::Wait() {
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 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
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 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
&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;
}