Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/gtest/src/gtest-death-test.cc')
-rw-r--r--extern/gtest/src/gtest-death-test.cc567
1 files changed, 439 insertions, 128 deletions
diff --git a/extern/gtest/src/gtest-death-test.cc b/extern/gtest/src/gtest-death-test.cc
index a01a3698308..da09a1cfc23 100644
--- a/extern/gtest/src/gtest-death-test.cc
+++ b/extern/gtest/src/gtest-death-test.cc
@@ -26,12 +26,14 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
+
//
// This file implements death tests.
#include "gtest/gtest-death-test.h"
+
+#include <utility>
+
#include "gtest/internal/gtest-port.h"
#include "gtest/internal/custom/gtest.h"
@@ -62,26 +64,36 @@
# include <spawn.h>
# endif // GTEST_OS_QNX
+# if GTEST_OS_FUCHSIA
+# include <lib/fdio/fd.h>
+# include <lib/fdio/io.h>
+# include <lib/fdio/spawn.h>
+# include <lib/zx/channel.h>
+# include <lib/zx/port.h>
+# include <lib/zx/process.h>
+# include <lib/zx/socket.h>
+# include <zircon/processargs.h>
+# include <zircon/syscalls.h>
+# include <zircon/syscalls/policy.h>
+# include <zircon/syscalls/port.h>
+# endif // GTEST_OS_FUCHSIA
+
#endif // GTEST_HAS_DEATH_TEST
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-string.h"
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick exists to
-// prevent the accidental inclusion of gtest-internal-inl.h in the
-// user's code.
-#define GTEST_IMPLEMENTATION_ 1
#include "src/gtest-internal-inl.h"
-#undef GTEST_IMPLEMENTATION_
namespace testing {
// Constants.
// The default death test style.
-static const char kDefaultDeathTestStyle[] = "fast";
+//
+// This is defined in internal/gtest-port.h as "fast", but can be overridden by
+// a definition in internal/custom/gtest-port.h. The recommended value, which is
+// used internally at Google, is "threadsafe".
+static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE;
GTEST_DEFINE_string_(
death_test_style,
@@ -110,8 +122,8 @@ GTEST_DEFINE_string_(
"Indicates the file, line number, temporal index of "
"the single death test to run, and a file descriptor to "
"which a success code may be sent, all separated by "
- "the '|' characters. This flag is specified if and only if the current "
- "process is a sub-process launched for running a thread-safe "
+ "the '|' characters. This flag is specified if and only if the "
+ "current process is a sub-process launched for running a thread-safe "
"death test. FOR INTERNAL USE ONLY.");
} // namespace internal
@@ -121,7 +133,7 @@ namespace internal {
// Valid only for fast death tests. Indicates the code is running in the
// child process of a fast style death test.
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
static bool g_in_fast_death_test_child = false;
# endif
@@ -131,10 +143,10 @@ static bool g_in_fast_death_test_child = false;
// tests. IMPORTANT: This is an internal utility. Using it may break the
// implementation of death tests. User code MUST NOT use it.
bool InDeathTestChild() {
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
- // On Windows, death tests are thread-safe regardless of the value of the
- // death_test_style flag.
+ // On Windows and Fuchsia, death tests are thread-safe regardless of the value
+ // of the death_test_style flag.
return !GTEST_FLAG(internal_run_death_test).empty();
# else
@@ -154,7 +166,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
// ExitedWithCode function-call operator.
bool ExitedWithCode::operator()(int exit_status) const {
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
return exit_status == exit_code_;
@@ -162,10 +174,10 @@ bool ExitedWithCode::operator()(int exit_status) const {
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
}
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// KilledBySignal constructor.
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
}
@@ -182,7 +194,7 @@ bool KilledBySignal::operator()(int exit_status) const {
# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
}
-# endif // !GTEST_OS_WINDOWS
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
namespace internal {
@@ -193,7 +205,7 @@ namespace internal {
static std::string ExitSummary(int exit_code) {
Message m;
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
m << "Exited with exit status " << exit_code;
@@ -209,7 +221,7 @@ static std::string ExitSummary(int exit_code) {
m << " (core dumped)";
}
# endif
-# endif // GTEST_OS_WINDOWS
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
return m.GetString();
}
@@ -220,7 +232,7 @@ bool ExitedUnsuccessfully(int exit_status) {
return !ExitedWithCode(0)(exit_status);
}
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Generates a textual failure message when a death test finds more than
// one thread running, or cannot determine the number of threads, prior
// to executing the given statement. It is the responsibility of the
@@ -229,13 +241,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) {
Message msg;
msg << "Death tests use fork(), which is unsafe particularly"
<< " in a threaded context. For this test, " << GTEST_NAME_ << " ";
- if (thread_count == 0)
+ if (thread_count == 0) {
msg << "couldn't detect the number of threads.";
- else
+ } else {
msg << "detected " << thread_count << " threads.";
+ }
+ msg << " See "
+ "https://github.com/google/googletest/blob/master/googletest/docs/"
+ "advanced.md#death-tests-and-threads"
+ << " for more explanation and suggested solutions, especially if"
+ << " this is the last message you see before your test times out.";
return msg.GetString();
}
-# endif // !GTEST_OS_WINDOWS
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Flag characters for reporting a death test that did not die.
static const char kDeathTestLived = 'L';
@@ -243,6 +261,13 @@ static const char kDeathTestReturned = 'R';
static const char kDeathTestThrew = 'T';
static const char kDeathTestInternalError = 'I';
+#if GTEST_OS_FUCHSIA
+
+// File descriptor used for the pipe in the child process.
+static const int kFuchsiaReadPipeFd = 3;
+
+#endif
+
// An enumeration describing all of the possible ways that a death test can
// conclude. DIED means that the process died while executing the test
// code; LIVED means that process lived beyond the end of the test code;
@@ -250,8 +275,6 @@ static const char kDeathTestInternalError = 'I';
// statement, which is not allowed; THREW means that the test statement
// returned control by throwing an exception. IN_PROGRESS means the test
// has not yet concluded.
-// TODO(vladl@google.com): Unify names and possibly values for
-// AbortReason, DeathTestOutcome, and flag characters above.
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
// Routine for aborting the program which is safe to call from an
@@ -259,13 +282,13 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
// message is propagated back to the parent process. Otherwise, the
// message is simply printed to stderr. In either case, the program
// then exits with status 1.
-void DeathTestAbort(const std::string& message) {
+static void DeathTestAbort(const std::string& message) {
// On a POSIX system, this function may be called from a threadsafe-style
// death test child process, which operates on a very small stack. Use
// the heap for any additional non-minuscule memory requirements.
const InternalRunDeathTestFlag* const flag =
GetUnitTestImpl()->internal_run_death_test_flag();
- if (flag != NULL) {
+ if (flag != nullptr) {
FILE* parent = posix::FDOpen(flag->write_fd(), "w");
fputc(kDeathTestInternalError, parent);
fprintf(parent, "%s", message.c_str());
@@ -345,7 +368,7 @@ static void FailFromInternalError(int fd) {
// for the current test.
DeathTest::DeathTest() {
TestInfo* const info = GetUnitTestImpl()->current_test_info();
- if (info == NULL) {
+ if (info == nullptr) {
DeathTestAbort("Cannot run a death test outside of a TEST or "
"TEST_F construct");
}
@@ -353,10 +376,11 @@ DeathTest::DeathTest() {
// Creates and returns a death test by dispatching to the current
// death test factory.
-bool DeathTest::Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test) {
+bool DeathTest::Create(const char* statement,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) {
return GetUnitTestImpl()->death_test_factory()->Create(
- statement, regex, file, line, test);
+ statement, std::move(matcher), file, line, test);
}
const char* DeathTest::LastMessage() {
@@ -372,9 +396,9 @@ std::string DeathTest::last_death_test_message_;
// Provides cross platform implementation for some death functionality.
class DeathTestImpl : public DeathTest {
protected:
- DeathTestImpl(const char* a_statement, const RE* a_regex)
+ DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher)
: statement_(a_statement),
- regex_(a_regex),
+ matcher_(std::move(matcher)),
spawned_(false),
status_(-1),
outcome_(IN_PROGRESS),
@@ -382,13 +406,12 @@ class DeathTestImpl : public DeathTest {
write_fd_(-1) {}
// read_fd_ is expected to be closed and cleared by a derived class.
- ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+ ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
- void Abort(AbortReason reason);
- virtual bool Passed(bool status_ok);
+ void Abort(AbortReason reason) override;
+ bool Passed(bool status_ok) override;
const char* statement() const { return statement_; }
- const RE* regex() const { return regex_; }
bool spawned() const { return spawned_; }
void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
int status() const { return status_; }
@@ -406,13 +429,15 @@ class DeathTestImpl : public DeathTest {
// case of unexpected codes.
void ReadAndInterpretStatusByte();
+ // Returns stderr output from the child process.
+ virtual std::string GetErrorLogs();
+
private:
// The textual content of the code this object is testing. This class
// doesn't own this string and should not attempt to delete it.
const char* const statement_;
- // The regular expression which test output must match. DeathTestImpl
- // doesn't own this object and should not attempt to delete it.
- const RE* const regex_;
+ // A matcher that's expected to match the stderr output by the child process.
+ Matcher<const std::string&> matcher_;
// True if the death test child process has been successfully spawned.
bool spawned_;
// The exit status of the child process.
@@ -474,6 +499,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
set_read_fd(-1);
}
+std::string DeathTestImpl::GetErrorLogs() {
+ return GetCapturedStderr();
+}
+
// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
@@ -527,22 +556,21 @@ static ::std::string FormatDeathTestOutput(const ::std::string& output) {
// in the format specified by wait(2). On Windows, this is the
// value supplied to the ExitProcess() API or a numeric code
// of the exception that terminated the program.
-// regex: A regular expression object to be applied to
-// the test's captured standard error output; the death test
-// fails if it does not match.
+// matcher_: A matcher that's expected to match the stderr output by the child
+// process.
//
// Argument:
// status_ok: true if exit_status is acceptable in the context of
// this particular death test, which fails if it is false
//
-// Returns true iff all of the above conditions are met. Otherwise, the
-// first failing condition, in the order given above, is the one that is
+// Returns true if and only if all of the above conditions are met. Otherwise,
+// the first failing condition, in the order given above, is the one that is
// reported. Also sets the last death test message string.
bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned())
return false;
- const std::string error_message = GetCapturedStderr();
+ const std::string error_message = GetErrorLogs();
bool success = false;
Message buffer;
@@ -563,13 +591,15 @@ bool DeathTestImpl::Passed(bool status_ok) {
break;
case DIED:
if (status_ok) {
- const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
- if (matched) {
+ if (matcher_.Matches(error_message)) {
success = true;
} else {
+ std::ostringstream stream;
+ matcher_.DescribeTo(&stream);
buffer << " Result: died but not with expected error.\n"
- << " Expected: " << regex()->pattern() << "\n"
- << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ << " Expected: " << stream.str() << "\n"
+ << "Actual msg:\n"
+ << FormatDeathTestOutput(error_message);
}
} else {
buffer << " Result: died but not with expected exit code:\n"
@@ -618,11 +648,11 @@ bool DeathTestImpl::Passed(bool status_ok) {
//
class WindowsDeathTest : public DeathTestImpl {
public:
- WindowsDeathTest(const char* a_statement,
- const RE* a_regex,
- const char* file,
- int line)
- : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+ WindowsDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
// All of these virtual functions are inherited from DeathTest.
virtual int Wait();
@@ -699,7 +729,7 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
const TestInfo* const info = impl->current_test_info();
const int death_test_index = info->result()->death_test_count();
- if (flag != NULL) {
+ if (flag != nullptr) {
// ParseInternalRunDeathTestFlag() has performed all the necessary
// processing.
set_write_fd(flag->write_fd());
@@ -708,8 +738,8 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
// WindowsDeathTest uses an anonymous pipe to communicate results of
// a death test.
- SECURITY_ATTRIBUTES handles_are_inheritable = {
- sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES),
+ nullptr, TRUE};
HANDLE read_handle, write_handle;
GTEST_DEATH_TEST_CHECK_(
::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
@@ -720,13 +750,13 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
write_handle_.Reset(write_handle);
event_handle_.Reset(::CreateEvent(
&handles_are_inheritable,
- TRUE, // The event will automatically reset to non-signaled state.
- FALSE, // The initial state is non-signalled.
- NULL)); // The even is unnamed.
- GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
- const std::string filter_flag =
- std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" +
- info->test_case_name() + "." + info->name();
+ TRUE, // The event will automatically reset to non-signaled state.
+ FALSE, // The initial state is non-signalled.
+ nullptr)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr);
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
const std::string internal_flag =
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
"=" + file_ + "|" + StreamableToString(line_) + "|" +
@@ -739,10 +769,9 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
"|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
char executable_path[_MAX_PATH + 1]; // NOLINT
- GTEST_DEATH_TEST_CHECK_(
- _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
- executable_path,
- _MAX_PATH));
+ GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr,
+ executable_path,
+ _MAX_PATH));
std::string command_line =
std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
@@ -763,33 +792,290 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
PROCESS_INFORMATION process_info;
- GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
- executable_path,
- const_cast<char*>(command_line.c_str()),
- NULL, // Retuned process handle is not inheritable.
- NULL, // Retuned thread handle is not inheritable.
- TRUE, // Child inherits all inheritable handles (for write_handle_).
- 0x0, // Default creation flags.
- NULL, // Inherit the parent's environment.
- UnitTest::GetInstance()->original_working_dir(),
- &startup_info,
- &process_info) != FALSE);
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreateProcessA(
+ executable_path, const_cast<char*>(command_line.c_str()),
+ nullptr, // Retuned process handle is not inheritable.
+ nullptr, // Retuned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ nullptr, // Inherit the parent's environment.
+ UnitTest::GetInstance()->original_working_dir(), &startup_info,
+ &process_info) != FALSE);
child_handle_.Reset(process_info.hProcess);
::CloseHandle(process_info.hThread);
set_spawned(true);
return OVERSEE_TEST;
}
-# else // We are not on Windows.
+
+# elif GTEST_OS_FUCHSIA
+
+class FuchsiaDeathTest : public DeathTestImpl {
+ public:
+ FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ int Wait() override;
+ TestRole AssumeRole() override;
+ std::string GetErrorLogs() override;
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+ // The stderr data captured by the child process.
+ std::string captured_stderr_;
+
+ zx::process child_process_;
+ zx::channel exception_channel_;
+ zx::socket stderr_socket_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() { args_.push_back(nullptr); }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+
+ int size() {
+ return args_.size() - 1;
+ }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int FuchsiaDeathTest::Wait() {
+ const int kProcessKey = 0;
+ const int kSocketKey = 1;
+ const int kExceptionKey = 2;
+
+ if (!spawned())
+ return 0;
+
+ // Create a port to wait for socket/task/exception events.
+ zx_status_t status_zx;
+ zx::port port;
+ status_zx = zx::port::create(0, &port);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the child process to terminate.
+ status_zx = child_process_.wait_async(
+ port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the socket to be readable or closed.
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
+ ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for an exception.
+ status_zx = exception_channel_.wait_async(
+ port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ bool process_terminated = false;
+ bool socket_closed = false;
+ do {
+ zx_port_packet_t packet = {};
+ status_zx = port.wait(zx::time::infinite(), &packet);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ if (packet.key == kExceptionKey) {
+ // Process encountered an exception. Kill it directly rather than
+ // letting other handlers process the event. We will get a kProcessKey
+ // event when the process actually terminates.
+ status_zx = child_process_.kill();
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ } else if (packet.key == kProcessKey) {
+ // Process terminated.
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
+ process_terminated = true;
+ } else if (packet.key == kSocketKey) {
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ if (packet.signal.observed & ZX_SOCKET_READABLE) {
+ // Read data from the socket.
+ constexpr size_t kBufferSize = 1024;
+ do {
+ size_t old_length = captured_stderr_.length();
+ size_t bytes_read = 0;
+ captured_stderr_.resize(old_length + kBufferSize);
+ status_zx = stderr_socket_.read(
+ 0, &captured_stderr_.front() + old_length, kBufferSize,
+ &bytes_read);
+ captured_stderr_.resize(old_length + bytes_read);
+ } while (status_zx == ZX_OK);
+ if (status_zx == ZX_ERR_PEER_CLOSED) {
+ socket_closed = true;
+ } else {
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT);
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
+ ZX_WAIT_ASYNC_ONCE);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ }
+ } else {
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED);
+ socket_closed = true;
+ }
+ }
+ } while (!process_terminated && !socket_closed);
+
+ ReadAndInterpretStatusByte();
+
+ zx_info_process_t buffer;
+ status_zx = child_process_.get_info(
+ ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ GTEST_DEATH_TEST_CHECK_(buffer.exited);
+ set_status(buffer.return_code);
+ return status();
+}
+
+// The AssumeRole process for a Fuchsia death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != nullptr) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(kFuchsiaReadPipeFd);
+ return EXECUTE_TEST;
+ }
+
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // Build the child process command line.
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ + file_ + "|"
+ + StreamableToString(line_) + "|"
+ + StreamableToString(death_test_index);
+ Arguments args;
+ args.AddArguments(GetInjectableArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ // Build the pipe for communication with the child.
+ zx_status_t status;
+ zx_handle_t child_pipe_handle;
+ int child_pipe_fd;
+ status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ set_read_fd(child_pipe_fd);
+
+ // Set the pipe handle for the child.
+ fdio_spawn_action_t spawn_actions[2] = {};
+ fdio_spawn_action_t* add_handle_action = &spawn_actions[0];
+ add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
+ add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd);
+ add_handle_action->h.handle = child_pipe_handle;
+
+ // Create a socket pair will be used to receive the child process' stderr.
+ zx::socket stderr_producer_socket;
+ status =
+ zx::socket::create(0, &stderr_producer_socket, &stderr_socket_);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+ int stderr_producer_fd = -1;
+ status =
+ fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+
+ // Make the stderr socket nonblocking.
+ GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0);
+
+ fdio_spawn_action_t* add_stderr_action = &spawn_actions[1];
+ add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD;
+ add_stderr_action->fd.local_fd = stderr_producer_fd;
+ add_stderr_action->fd.target_fd = STDERR_FILENO;
+
+ // Create a child job.
+ zx_handle_t child_job = ZX_HANDLE_INVALID;
+ status = zx_job_create(zx_job_default(), 0, & child_job);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ zx_policy_basic_t policy;
+ policy.condition = ZX_POL_NEW_ANY;
+ policy.policy = ZX_POL_ACTION_ALLOW;
+ status = zx_job_set_policy(
+ child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Create an exception channel attached to the |child_job|, to allow
+ // us to suppress the system default exception handler from firing.
+ status =
+ zx_task_create_exception_channel(
+ child_job, 0, exception_channel_.reset_and_get_address());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Spawn the child process.
+ status = fdio_spawn_etc(
+ child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr,
+ 2, spawn_actions, child_process_.reset_and_get_address(), nullptr);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+std::string FuchsiaDeathTest::GetErrorLogs() {
+ return captured_stderr_;
+}
+
+#else // We are neither on Windows, nor on Fuchsia.
// ForkingDeathTest provides implementations for most of the abstract
// methods of the DeathTest interface. Only the AssumeRole method is
// left undefined.
class ForkingDeathTest : public DeathTestImpl {
public:
- ForkingDeathTest(const char* statement, const RE* regex);
+ ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher);
// All of these virtual functions are inherited from DeathTest.
- virtual int Wait();
+ int Wait() override;
protected:
void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
@@ -800,9 +1086,9 @@ class ForkingDeathTest : public DeathTestImpl {
};
// Constructs a ForkingDeathTest.
-ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
- : DeathTestImpl(a_statement, a_regex),
- child_pid_(-1) {}
+ForkingDeathTest::ForkingDeathTest(const char* a_statement,
+ Matcher<const std::string&> matcher)
+ : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {}
// Waits for the child in a death test to exit, returning its exit
// status, or 0 if no child process exists. As a side effect, sets the
@@ -823,9 +1109,9 @@ int ForkingDeathTest::Wait() {
// in the child process.
class NoExecDeathTest : public ForkingDeathTest {
public:
- NoExecDeathTest(const char* a_statement, const RE* a_regex) :
- ForkingDeathTest(a_statement, a_regex) { }
- virtual TestRole AssumeRole();
+ NoExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher)
+ : ForkingDeathTest(a_statement, std::move(matcher)) {}
+ TestRole AssumeRole() override;
};
// The AssumeRole process for a fork-and-run death test. It implements a
@@ -878,16 +1164,18 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// only this specific death test to be run.
class ExecDeathTest : public ForkingDeathTest {
public:
- ExecDeathTest(const char* a_statement, const RE* a_regex,
- const char* file, int line) :
- ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
- virtual TestRole AssumeRole();
+ ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : ForkingDeathTest(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+ TestRole AssumeRole() override;
+
private:
- static ::std::vector<testing::internal::string>
- GetArgvsForDeathTestChildProcess() {
- ::std::vector<testing::internal::string> args = GetInjectableArgvs();
+ static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() {
+ ::std::vector<std::string> args = GetInjectableArgvs();
# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
- ::std::vector<testing::internal::string> extra_args =
+ ::std::vector<std::string> extra_args =
GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
args.insert(args.end(), extra_args.begin(), extra_args.end());
# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
@@ -902,9 +1190,7 @@ class ExecDeathTest : public ForkingDeathTest {
// Utility class for accumulating command-line arguments.
class Arguments {
public:
- Arguments() {
- args_.push_back(NULL);
- }
+ Arguments() { args_.push_back(nullptr); }
~Arguments() {
for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
@@ -986,6 +1272,7 @@ static int ExecDeathTestChildMain(void* child_arg) {
}
# endif // !GTEST_OS_QNX
+# if GTEST_HAS_CLONE
// Two utility routines that together determine the direction the stack
// grows.
// This could be accomplished more elegantly by a single recursive
@@ -995,20 +1282,26 @@ static int ExecDeathTestChildMain(void* child_arg) {
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
// StackLowerThanAddress into StackGrowsDown, which then doesn't give
// correct answer.
-void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_;
-void StackLowerThanAddress(const void* ptr, bool* result) {
+static void StackLowerThanAddress(const void* ptr,
+ bool* result) GTEST_NO_INLINE_;
+// HWAddressSanitizer add a random tag to the MSB of the local variable address,
+// making comparison result unpredictable.
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static void StackLowerThanAddress(const void* ptr, bool* result) {
int dummy;
*result = (&dummy < ptr);
}
// Make sure AddressSanitizer does not tamper with the stack here.
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
-bool StackGrowsDown() {
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static bool StackGrowsDown() {
int dummy;
bool result;
StackLowerThanAddress(&dummy, &result);
return result;
}
+# endif // GTEST_HAS_CLONE
// Spawns a child process with the same executable as the current process in
// a thread-safe manner and instructs it to run the death test. The
@@ -1046,7 +1339,8 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
fd_flags | FD_CLOEXEC));
struct inheritance inherit = {0};
// spawn is a system call.
- child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron());
+ child_pid =
+ spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron());
// Restores the current working directory.
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
@@ -1070,9 +1364,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
if (!use_fork) {
static const bool stack_grows_down = StackGrowsDown();
- const size_t stack_size = getpagesize();
+ const auto stack_size = static_cast<size_t>(getpagesize());
// MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
- void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
@@ -1086,8 +1380,9 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
void* const stack_top =
static_cast<char*>(stack) +
(stack_grows_down ? stack_size - kMaxStackAlignment : 0);
- GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
- reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
+ GTEST_DEATH_TEST_CHECK_(
+ static_cast<size_t>(stack_size) > kMaxStackAlignment &&
+ reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0);
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
@@ -1104,7 +1399,7 @@ static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
# endif // GTEST_OS_QNX
# if GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_SYSCALL_(
- sigaction(SIGPROF, &saved_sigprof_action, NULL));
+ sigaction(SIGPROF, &saved_sigprof_action, nullptr));
# endif // GTEST_OS_LINUX
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
@@ -1122,7 +1417,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
const TestInfo* const info = impl->current_test_info();
const int death_test_index = info->result()->death_test_count();
- if (flag != NULL) {
+ if (flag != nullptr) {
set_write_fd(flag->write_fd());
return EXECUTE_TEST;
}
@@ -1133,9 +1428,9 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
// it be closed when the child process does an exec:
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
- const std::string filter_flag =
- std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
- + info->test_case_name() + "." + info->name();
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
const std::string internal_flag =
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ file_ + "|" + StreamableToString(line_) + "|"
@@ -1168,7 +1463,8 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
// by the "test" argument to its address. If the test should be
// skipped, sets that pointer to NULL. Returns true, unless the
// flag is set to an invalid value.
-bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+bool DefaultDeathTestFactory::Create(const char* statement,
+ Matcher<const std::string&> matcher,
const char* file, int line,
DeathTest** test) {
UnitTestImpl* const impl = GetUnitTestImpl();
@@ -1177,7 +1473,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
const int death_test_index = impl->current_test_info()
->increment_death_test_count();
- if (flag != NULL) {
+ if (flag != nullptr) {
if (death_test_index > flag->index()) {
DeathTest::set_last_death_test_message(
"Death test count (" + StreamableToString(death_test_index)
@@ -1188,7 +1484,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
if (!(flag->file() == file && flag->line() == line &&
flag->index() == death_test_index)) {
- *test = NULL;
+ *test = nullptr;
return true;
}
}
@@ -1197,15 +1493,22 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
if (GTEST_FLAG(death_test_style) == "threadsafe" ||
GTEST_FLAG(death_test_style) == "fast") {
- *test = new WindowsDeathTest(statement, regex, file, line);
+ *test = new WindowsDeathTest(statement, std::move(matcher), file, line);
+ }
+
+# elif GTEST_OS_FUCHSIA
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line);
}
# else
if (GTEST_FLAG(death_test_style) == "threadsafe") {
- *test = new ExecDeathTest(statement, regex, file, line);
+ *test = new ExecDeathTest(statement, std::move(matcher), file, line);
} else if (GTEST_FLAG(death_test_style) == "fast") {
- *test = new NoExecDeathTest(statement, regex);
+ *test = new NoExecDeathTest(statement, std::move(matcher));
}
# endif // GTEST_OS_WINDOWS
@@ -1224,7 +1527,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
// Recreates the pipe and event handles from the provided parameters,
// signals the event, and returns a file descriptor wrapped around the pipe
// handle. This function is called in the child process only.
-int GetStatusFileDescriptor(unsigned int parent_process_id,
+static int GetStatusFileDescriptor(unsigned int parent_process_id,
size_t write_handle_as_size_t,
size_t event_handle_as_size_t) {
AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
@@ -1235,15 +1538,13 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
StreamableToString(parent_process_id));
}
- // TODO(vladl@google.com): Replace the following check with a
- // compile-time assertion when available.
GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
const HANDLE write_handle =
reinterpret_cast<HANDLE>(write_handle_as_size_t);
HANDLE dup_write_handle;
- // The newly initialized handle is accessible only in in the parent
+ // The newly initialized handle is accessible only in the parent
// process. To obtain one accessible within the child, we need to use
// DuplicateHandle.
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
@@ -1292,7 +1593,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
// the flag is specified; otherwise returns NULL.
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
- if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+ if (GTEST_FLAG(internal_run_death_test) == "") return nullptr;
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
// can use it here.
@@ -1320,6 +1621,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
write_fd = GetStatusFileDescriptor(parent_process_id,
write_handle_as_size_t,
event_handle_as_size_t);
+
+# elif GTEST_OS_FUCHSIA
+
+ if (fields.size() != 3
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+ + GTEST_FLAG(internal_run_death_test));
+ }
+
# else
if (fields.size() != 4