gtest-death-test.cc (googletest-release-1.11.0) | : | gtest-death-test.cc (googletest-release-1.12.0) | ||
---|---|---|---|---|
skipping to change at line 38 | skipping to change at line 38 | |||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
// | // | |||
// This file implements death tests. | // This file implements death tests. | |||
#include "gtest/gtest-death-test.h" | #include "gtest/gtest-death-test.h" | |||
#include <functional> | #include <functional> | |||
#include <utility> | #include <utility> | |||
#include "gtest/internal/gtest-port.h" | ||||
#include "gtest/internal/custom/gtest.h" | #include "gtest/internal/custom/gtest.h" | |||
#include "gtest/internal/gtest-port.h" | ||||
#if GTEST_HAS_DEATH_TEST | #if GTEST_HAS_DEATH_TEST | |||
# if GTEST_OS_MAC | #if GTEST_OS_MAC | |||
# include <crt_externs.h> | #include <crt_externs.h> | |||
# endif // GTEST_OS_MAC | #endif // GTEST_OS_MAC | |||
# include <errno.h> | #include <errno.h> | |||
# include <fcntl.h> | #include <fcntl.h> | |||
# include <limits.h> | #include <limits.h> | |||
# if GTEST_OS_LINUX | #if GTEST_OS_LINUX | |||
# include <signal.h> | #include <signal.h> | |||
# endif // GTEST_OS_LINUX | #endif // GTEST_OS_LINUX | |||
# include <stdarg.h> | #include <stdarg.h> | |||
# if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
# include <windows.h> | #include <windows.h> | |||
# else | #else | |||
# include <sys/mman.h> | #include <sys/mman.h> | |||
# include <sys/wait.h> | #include <sys/wait.h> | |||
# endif // GTEST_OS_WINDOWS | #endif // GTEST_OS_WINDOWS | |||
# if GTEST_OS_QNX | #if GTEST_OS_QNX | |||
# include <spawn.h> | #include <spawn.h> | |||
# endif // GTEST_OS_QNX | #endif // GTEST_OS_QNX | |||
# if GTEST_OS_FUCHSIA | #if GTEST_OS_FUCHSIA | |||
# include <lib/fdio/fd.h> | #include <lib/fdio/fd.h> | |||
# include <lib/fdio/io.h> | #include <lib/fdio/io.h> | |||
# include <lib/fdio/spawn.h> | #include <lib/fdio/spawn.h> | |||
# include <lib/zx/channel.h> | #include <lib/zx/channel.h> | |||
# include <lib/zx/port.h> | #include <lib/zx/port.h> | |||
# include <lib/zx/process.h> | #include <lib/zx/process.h> | |||
# include <lib/zx/socket.h> | #include <lib/zx/socket.h> | |||
# include <zircon/processargs.h> | #include <zircon/processargs.h> | |||
# include <zircon/syscalls.h> | #include <zircon/syscalls.h> | |||
# include <zircon/syscalls/policy.h> | #include <zircon/syscalls/policy.h> | |||
# include <zircon/syscalls/port.h> | #include <zircon/syscalls/port.h> | |||
# endif // GTEST_OS_FUCHSIA | #endif // GTEST_OS_FUCHSIA | |||
#endif // GTEST_HAS_DEATH_TEST | #endif // GTEST_HAS_DEATH_TEST | |||
#include "gtest/gtest-message.h" | #include "gtest/gtest-message.h" | |||
#include "gtest/internal/gtest-string.h" | #include "gtest/internal/gtest-string.h" | |||
#include "src/gtest-internal-inl.h" | #include "src/gtest-internal-inl.h" | |||
namespace testing { | namespace testing { | |||
// Constants. | // Constants. | |||
// The default death test style. | // The default death test style. | |||
// | // | |||
// This is defined in internal/gtest-port.h as "fast", but can be overridden by | // 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 | // a definition in internal/custom/gtest-port.h. The recommended value, which is | |||
// used internally at Google, is "threadsafe". | // used internally at Google, is "threadsafe". | |||
static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; | static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; | |||
} // namespace testing | ||||
GTEST_DEFINE_string_( | GTEST_DEFINE_string_( | |||
death_test_style, | death_test_style, | |||
internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), | testing::internal::StringFromGTestEnv("death_test_style", | |||
testing::kDefaultDeathTestStyle), | ||||
"Indicates how to run a death test in a forked child process: " | "Indicates how to run a death test in a forked child process: " | |||
"\"threadsafe\" (child process re-executes the test binary " | "\"threadsafe\" (child process re-executes the test binary " | |||
"from the beginning, running only the specific death test) or " | "from the beginning, running only the specific death test) or " | |||
"\"fast\" (child process runs the death test immediately " | "\"fast\" (child process runs the death test immediately " | |||
"after forking)."); | "after forking)."); | |||
GTEST_DEFINE_bool_( | GTEST_DEFINE_bool_( | |||
death_test_use_fork, | death_test_use_fork, | |||
internal::BoolFromGTestEnv("death_test_use_fork", false), | testing::internal::BoolFromGTestEnv("death_test_use_fork", false), | |||
"Instructs to use fork()/_exit() instead of clone() in death tests. " | "Instructs to use fork()/_exit() instead of clone() in death tests. " | |||
"Ignored and always uses fork() on POSIX systems where clone() is not " | "Ignored and always uses fork() on POSIX systems where clone() is not " | |||
"implemented. Useful when running under valgrind or similar tools if " | "implemented. Useful when running under valgrind or similar tools if " | |||
"those do not support clone(). Valgrind 3.3.1 will just fail if " | "those do not support clone(). Valgrind 3.3.1 will just fail if " | |||
"it sees an unsupported combination of clone() flags. " | "it sees an unsupported combination of clone() flags. " | |||
"It is not recommended to use this flag w/o valgrind though it will " | "It is not recommended to use this flag w/o valgrind though it will " | |||
"work in 99% of the cases. Once valgrind is fixed, this flag will " | "work in 99% of the cases. Once valgrind is fixed, this flag will " | |||
"most likely be removed."); | "most likely be removed."); | |||
namespace internal { | ||||
GTEST_DEFINE_string_( | GTEST_DEFINE_string_( | |||
internal_run_death_test, "", | internal_run_death_test, "", | |||
"Indicates the file, line number, temporal index of " | "Indicates the file, line number, temporal index of " | |||
"the single death test to run, and a file descriptor to " | "the single death test to run, and a file descriptor to " | |||
"which a success code may be sent, all separated by " | "which a success code may be sent, all separated by " | |||
"the '|' characters. This flag is specified if and only if the " | "the '|' characters. This flag is specified if and only if the " | |||
"current process is a sub-process launched for running a thread-safe " | "current process is a sub-process launched for running a thread-safe " | |||
"death test. FOR INTERNAL USE ONLY."); | "death test. FOR INTERNAL USE ONLY."); | |||
} // namespace internal | ||||
namespace testing { | ||||
#if GTEST_HAS_DEATH_TEST | #if GTEST_HAS_DEATH_TEST | |||
namespace internal { | namespace internal { | |||
// Valid only for fast death tests. Indicates the code is running in the | // Valid only for fast death tests. Indicates the code is running in the | |||
// child process of a fast style death test. | // child process of a fast style death test. | |||
# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | #if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | |||
static bool g_in_fast_death_test_child = false; | static bool g_in_fast_death_test_child = false; | |||
# endif | #endif | |||
// Returns a Boolean value indicating whether the caller is currently | // Returns a Boolean value indicating whether the caller is currently | |||
// executing in the context of the death test child process. Tools such as | // executing in the context of the death test child process. Tools such as | |||
// Valgrind heap checkers may need this to modify their behavior in death | // Valgrind heap checkers may need this to modify their behavior in death | |||
// tests. IMPORTANT: This is an internal utility. Using it may break the | // tests. IMPORTANT: This is an internal utility. Using it may break the | |||
// implementation of death tests. User code MUST NOT use it. | // implementation of death tests. User code MUST NOT use it. | |||
bool InDeathTestChild() { | bool InDeathTestChild() { | |||
# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | #if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | |||
// On Windows and Fuchsia, death tests are thread-safe regardless of the value | // On Windows and Fuchsia, death tests are thread-safe regardless of the value | |||
// of the death_test_style flag. | // of the death_test_style flag. | |||
return !GTEST_FLAG(internal_run_death_test).empty(); | return !GTEST_FLAG_GET(internal_run_death_test).empty(); | |||
# else | #else | |||
if (GTEST_FLAG(death_test_style) == "threadsafe") | if (GTEST_FLAG_GET(death_test_style) == "threadsafe") | |||
return !GTEST_FLAG(internal_run_death_test).empty(); | return !GTEST_FLAG_GET(internal_run_death_test).empty(); | |||
else | else | |||
return g_in_fast_death_test_child; | return g_in_fast_death_test_child; | |||
#endif | #endif | |||
} | } | |||
} // namespace internal | } // namespace internal | |||
// ExitedWithCode constructor. | // ExitedWithCode constructor. | |||
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { | ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {} | |||
} | ||||
// ExitedWithCode function-call operator. | // ExitedWithCode function-call operator. | |||
bool ExitedWithCode::operator()(int exit_status) const { | bool ExitedWithCode::operator()(int exit_status) const { | |||
# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | #if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | |||
return exit_status == exit_code_; | return exit_status == exit_code_; | |||
# else | #else | |||
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; | return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; | |||
# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | #endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | |||
} | } | |||
# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | #if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | |||
// KilledBySignal constructor. | // KilledBySignal constructor. | |||
KilledBySignal::KilledBySignal(int signum) : signum_(signum) { | KilledBySignal::KilledBySignal(int signum) : signum_(signum) {} | |||
} | ||||
// KilledBySignal function-call operator. | // KilledBySignal function-call operator. | |||
bool KilledBySignal::operator()(int exit_status) const { | bool KilledBySignal::operator()(int exit_status) const { | |||
# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) | #if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) | |||
{ | { | |||
bool result; | bool result; | |||
if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { | if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { | |||
return result; | return result; | |||
} | } | |||
} | } | |||
# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) | #endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) | |||
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; | return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; | |||
} | } | |||
# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | #endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | |||
namespace internal { | namespace internal { | |||
// Utilities needed for death tests. | // Utilities needed for death tests. | |||
// Generates a textual description of a given exit code, in the format | // Generates a textual description of a given exit code, in the format | |||
// specified by wait(2). | // specified by wait(2). | |||
static std::string ExitSummary(int exit_code) { | static std::string ExitSummary(int exit_code) { | |||
Message m; | Message m; | |||
# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | #if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | |||
m << "Exited with exit status " << exit_code; | m << "Exited with exit status " << exit_code; | |||
# else | #else | |||
if (WIFEXITED(exit_code)) { | if (WIFEXITED(exit_code)) { | |||
m << "Exited with exit status " << WEXITSTATUS(exit_code); | m << "Exited with exit status " << WEXITSTATUS(exit_code); | |||
} else if (WIFSIGNALED(exit_code)) { | } else if (WIFSIGNALED(exit_code)) { | |||
m << "Terminated by signal " << WTERMSIG(exit_code); | m << "Terminated by signal " << WTERMSIG(exit_code); | |||
} | } | |||
# ifdef WCOREDUMP | #ifdef WCOREDUMP | |||
if (WCOREDUMP(exit_code)) { | if (WCOREDUMP(exit_code)) { | |||
m << " (core dumped)"; | m << " (core dumped)"; | |||
} | } | |||
# endif | #endif | |||
# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | #endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA | |||
return m.GetString(); | return m.GetString(); | |||
} | } | |||
// Returns true if exit_status describes a process that was terminated | // Returns true if exit_status describes a process that was terminated | |||
// by a signal, or exited normally with a nonzero exit code. | // by a signal, or exited normally with a nonzero exit code. | |||
bool ExitedUnsuccessfully(int exit_status) { | bool ExitedUnsuccessfully(int exit_status) { | |||
return !ExitedWithCode(0)(exit_status); | return !ExitedWithCode(0)(exit_status); | |||
} | } | |||
# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | #if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | |||
// Generates a textual failure message when a death test finds more than | // Generates a textual failure message when a death test finds more than | |||
// one thread running, or cannot determine the number of threads, prior | // one thread running, or cannot determine the number of threads, prior | |||
// to executing the given statement. It is the responsibility of the | // to executing the given statement. It is the responsibility of the | |||
// caller not to pass a thread_count of 1. | // caller not to pass a thread_count of 1. | |||
static std::string DeathTestThreadWarning(size_t thread_count) { | static std::string DeathTestThreadWarning(size_t thread_count) { | |||
Message msg; | Message msg; | |||
msg << "Death tests use fork(), which is unsafe particularly" | msg << "Death tests use fork(), which is unsafe particularly" | |||
<< " in a threaded context. For this test, " << GTEST_NAME_ << " "; | << " 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."; | msg << "couldn't detect the number of threads."; | |||
} else { | } else { | |||
msg << "detected " << thread_count << " threads."; | msg << "detected " << thread_count << " threads."; | |||
} | } | |||
msg << " See " | msg << " See " | |||
"https://github.com/google/googletest/blob/master/docs/" | "https://github.com/google/googletest/blob/master/docs/" | |||
"advanced.md#death-tests-and-threads" | "advanced.md#death-tests-and-threads" | |||
<< " for more explanation and suggested solutions, especially if" | << " for more explanation and suggested solutions, especially if" | |||
<< " this is the last message you see before your test times out."; | << " this is the last message you see before your test times out."; | |||
return msg.GetString(); | return msg.GetString(); | |||
} | } | |||
# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | #endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | |||
// Flag characters for reporting a death test that did not die. | // Flag characters for reporting a death test that did not die. | |||
static const char kDeathTestLived = 'L'; | static const char kDeathTestLived = 'L'; | |||
static const char kDeathTestReturned = 'R'; | static const char kDeathTestReturned = 'R'; | |||
static const char kDeathTestThrew = 'T'; | static const char kDeathTestThrew = 'T'; | |||
static const char kDeathTestInternalError = 'I'; | static const char kDeathTestInternalError = 'I'; | |||
#if GTEST_OS_FUCHSIA | #if GTEST_OS_FUCHSIA | |||
// File descriptor used for the pipe in the child process. | // File descriptor used for the pipe in the child process. | |||
skipping to change at line 307 | skipping to change at line 308 | |||
_exit(1); | _exit(1); | |||
} else { | } else { | |||
fprintf(stderr, "%s", message.c_str()); | fprintf(stderr, "%s", message.c_str()); | |||
fflush(stderr); | fflush(stderr); | |||
posix::Abort(); | posix::Abort(); | |||
} | } | |||
} | } | |||
// A replacement for CHECK that calls DeathTestAbort if the assertion | // A replacement for CHECK that calls DeathTestAbort if the assertion | |||
// fails. | // fails. | |||
# define GTEST_DEATH_TEST_CHECK_(expression) \ | #define GTEST_DEATH_TEST_CHECK_(expression) \ | |||
do { \ | do { \ | |||
if (!::testing::internal::IsTrue(expression)) { \ | if (!::testing::internal::IsTrue(expression)) { \ | |||
DeathTestAbort( \ | DeathTestAbort(::std::string("CHECK failed: File ") + __FILE__ + \ | |||
::std::string("CHECK failed: File ") + __FILE__ + ", line " \ | ", line " + \ | |||
+ ::testing::internal::StreamableToString(__LINE__) + ": " \ | ::testing::internal::StreamableToString(__LINE__) + \ | |||
+ #expression); \ | ": " + #expression); \ | |||
} \ | } \ | |||
} while (::testing::internal::AlwaysFalse()) | } while (::testing::internal::AlwaysFalse()) | |||
// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for | // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for | |||
// evaluating any system call that fulfills two conditions: it must return | // evaluating any system call that fulfills two conditions: it must return | |||
// -1 on failure, and set errno to EINTR when it is interrupted and | // -1 on failure, and set errno to EINTR when it is interrupted and | |||
// should be tried again. The macro expands to a loop that repeatedly | // should be tried again. The macro expands to a loop that repeatedly | |||
// evaluates the expression as long as it evaluates to -1 and sets | // evaluates the expression as long as it evaluates to -1 and sets | |||
// errno to EINTR. If the expression evaluates to -1 but errno is | // errno to EINTR. If the expression evaluates to -1 but errno is | |||
// something other than EINTR, DeathTestAbort is called. | // something other than EINTR, DeathTestAbort is called. | |||
# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ | #define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ | |||
do { \ | do { \ | |||
int gtest_retval; \ | int gtest_retval; \ | |||
do { \ | do { \ | |||
gtest_retval = (expression); \ | gtest_retval = (expression); \ | |||
} while (gtest_retval == -1 && errno == EINTR); \ | } while (gtest_retval == -1 && errno == EINTR); \ | |||
if (gtest_retval == -1) { \ | if (gtest_retval == -1) { \ | |||
DeathTestAbort( \ | DeathTestAbort(::std::string("CHECK failed: File ") + __FILE__ + \ | |||
::std::string("CHECK failed: File ") + __FILE__ + ", line " \ | ", line " + \ | |||
+ ::testing::internal::StreamableToString(__LINE__) + ": " \ | ::testing::internal::StreamableToString(__LINE__) + \ | |||
+ #expression + " != -1"); \ | ": " + #expression + " != -1"); \ | |||
} \ | } \ | |||
} while (::testing::internal::AlwaysFalse()) | } while (::testing::internal::AlwaysFalse()) | |||
// Returns the message describing the last system error in errno. | // Returns the message describing the last system error in errno. | |||
std::string GetLastErrnoDescription() { | std::string GetLastErrnoDescription() { | |||
return errno == 0 ? "" : posix::StrError(errno); | return errno == 0 ? "" : posix::StrError(errno); | |||
} | } | |||
// This is called from a death test parent process to read a failure | // This is called from a death test parent process to read a failure | |||
// message from the death test child process and log it with the FATAL | // message from the death test child process and log it with the FATAL | |||
// severity. On Windows, the message is read from a pipe handle. On other | // severity. On Windows, the message is read from a pipe handle. On other | |||
// platforms, it is read from a file descriptor. | // platforms, it is read from a file descriptor. | |||
static void FailFromInternalError(int fd) { | static void FailFromInternalError(int fd) { | |||
Message error; | Message error; | |||
char buffer[256]; | char buffer[256]; | |||
int num_read; | int num_read; | |||
skipping to change at line 373 | skipping to change at line 374 | |||
GTEST_LOG_(FATAL) << "Error while reading death test internal: " | GTEST_LOG_(FATAL) << "Error while reading death test internal: " | |||
<< GetLastErrnoDescription() << " [" << last_error << "]"; | << GetLastErrnoDescription() << " [" << last_error << "]"; | |||
} | } | |||
} | } | |||
// Death test constructor. Increments the running death test count | // Death test constructor. Increments the running death test count | |||
// for the current test. | // for the current test. | |||
DeathTest::DeathTest() { | DeathTest::DeathTest() { | |||
TestInfo* const info = GetUnitTestImpl()->current_test_info(); | TestInfo* const info = GetUnitTestImpl()->current_test_info(); | |||
if (info == nullptr) { | if (info == nullptr) { | |||
DeathTestAbort("Cannot run a death test outside of a TEST or " | DeathTestAbort( | |||
"TEST_F construct"); | "Cannot run a death test outside of a TEST or " | |||
"TEST_F construct"); | ||||
} | } | |||
} | } | |||
// Creates and returns a death test by dispatching to the current | // Creates and returns a death test by dispatching to the current | |||
// death test factory. | // death test factory. | |||
bool DeathTest::Create(const char* statement, | bool DeathTest::Create(const char* statement, | |||
Matcher<const std::string&> matcher, const char* file, | Matcher<const std::string&> matcher, const char* file, | |||
int line, DeathTest** test) { | int line, DeathTest** test) { | |||
return GetUnitTestImpl()->death_test_factory()->Create( | return GetUnitTestImpl()->death_test_factory()->Create( | |||
statement, std::move(matcher), file, line, test); | statement, std::move(matcher), file, line, test); | |||
skipping to change at line 503 | skipping to change at line 505 | |||
<< static_cast<unsigned int>(flag) << ")"; | << static_cast<unsigned int>(flag) << ")"; | |||
} | } | |||
} else { | } else { | |||
GTEST_LOG_(FATAL) << "Read from death test child process failed: " | GTEST_LOG_(FATAL) << "Read from death test child process failed: " | |||
<< GetLastErrnoDescription(); | << GetLastErrnoDescription(); | |||
} | } | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); | GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); | |||
set_read_fd(-1); | set_read_fd(-1); | |||
} | } | |||
std::string DeathTestImpl::GetErrorLogs() { | std::string DeathTestImpl::GetErrorLogs() { return GetCapturedStderr(); } | |||
return GetCapturedStderr(); | ||||
} | ||||
// Signals that the death test code which should have exited, didn't. | // Signals that the death test code which should have exited, didn't. | |||
// Should be called only in a death test child process. | // Should be called only in a death test child process. | |||
// Writes a status byte to the child's status file descriptor, then | // Writes a status byte to the child's status file descriptor, then | |||
// calls _exit(1). | // calls _exit(1). | |||
void DeathTestImpl::Abort(AbortReason reason) { | void DeathTestImpl::Abort(AbortReason reason) { | |||
// The parent process considers the death test to be a failure if | // The parent process considers the death test to be a failure if | |||
// it finds any data in our pipe. So, here we write a single flag byte | // it finds any data in our pipe. So, here we write a single flag byte | |||
// to the pipe, then exit. | // to the pipe, then exit. | |||
const char status_ch = | const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived | |||
reason == TEST_DID_NOT_DIE ? kDeathTestLived : | : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew | |||
reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; | : kDeathTestReturned; | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); | |||
// We are leaking the descriptor here because on some platforms (i.e., | // We are leaking the descriptor here because on some platforms (i.e., | |||
// when built as Windows DLL), destructors of global objects will still | // when built as Windows DLL), destructors of global objects will still | |||
// run after calling _exit(). On such systems, write_fd_ will be | // run after calling _exit(). On such systems, write_fd_ will be | |||
// indirectly closed from the destructor of UnitTestImpl, causing double | // indirectly closed from the destructor of UnitTestImpl, causing double | |||
// close if it is also closed here. On debug configurations, double close | // close if it is also closed here. On debug configurations, double close | |||
// may assert. As there are no in-process buffers to flush here, we are | // may assert. As there are no in-process buffers to flush here, we are | |||
// relying on the OS to close the descriptor after the process terminates | // relying on the OS to close the descriptor after the process terminates | |||
// when the destructors are not run. | // when the destructors are not run. | |||
_exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) | _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) | |||
} | } | |||
// Returns an indented copy of stderr output for a death test. | // Returns an indented copy of stderr output for a death test. | |||
// This makes distinguishing death test output lines from regular log lines | // This makes distinguishing death test output lines from regular log lines | |||
// much easier. | // much easier. | |||
static ::std::string FormatDeathTestOutput(const ::std::string& output) { | static ::std::string FormatDeathTestOutput(const ::std::string& output) { | |||
::std::string ret; | ::std::string ret; | |||
for (size_t at = 0; ; ) { | for (size_t at = 0;;) { | |||
const size_t line_end = output.find('\n', at); | const size_t line_end = output.find('\n', at); | |||
ret += "[ DEATH ] "; | ret += "[ DEATH ] "; | |||
if (line_end == ::std::string::npos) { | if (line_end == ::std::string::npos) { | |||
ret += output.substr(at); | ret += output.substr(at); | |||
break; | break; | |||
} | } | |||
ret += output.substr(at, line_end + 1 - at); | ret += output.substr(at, line_end + 1 - at); | |||
at = line_end + 1; | at = line_end + 1; | |||
} | } | |||
return ret; | return ret; | |||
skipping to change at line 571 | skipping to change at line 571 | |||
// process. | // process. | |||
// | // | |||
// Argument: | // Argument: | |||
// status_ok: true if exit_status is acceptable in the context of | // status_ok: true if exit_status is acceptable in the context of | |||
// this particular death test, which fails if it is false | // this particular death test, which fails if it is false | |||
// | // | |||
// Returns true if and only if all of the above conditions are met. Otherwise, | // 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 | // the first failing condition, in the order given above, is the one that is | |||
// reported. Also sets the last death test message string. | // reported. Also sets the last death test message string. | |||
bool DeathTestImpl::Passed(bool status_ok) { | bool DeathTestImpl::Passed(bool status_ok) { | |||
if (!spawned()) | if (!spawned()) return false; | |||
return false; | ||||
const std::string error_message = GetErrorLogs(); | const std::string error_message = GetErrorLogs(); | |||
bool success = false; | bool success = false; | |||
Message buffer; | Message buffer; | |||
buffer << "Death test: " << statement() << "\n"; | buffer << "Death test: " << statement() << "\n"; | |||
switch (outcome()) { | switch (outcome()) { | |||
case LIVED: | case LIVED: | |||
buffer << " Result: failed to die.\n" | buffer << " Result: failed to die.\n" | |||
<< " Error msg:\n" << FormatDeathTestOutput(error_message); | << " Error msg:\n" | |||
<< FormatDeathTestOutput(error_message); | ||||
break; | break; | |||
case THREW: | case THREW: | |||
buffer << " Result: threw an exception.\n" | buffer << " Result: threw an exception.\n" | |||
<< " Error msg:\n" << FormatDeathTestOutput(error_message); | << " Error msg:\n" | |||
<< FormatDeathTestOutput(error_message); | ||||
break; | break; | |||
case RETURNED: | case RETURNED: | |||
buffer << " Result: illegal return in test statement.\n" | buffer << " Result: illegal return in test statement.\n" | |||
<< " Error msg:\n" << FormatDeathTestOutput(error_message); | << " Error msg:\n" | |||
<< FormatDeathTestOutput(error_message); | ||||
break; | break; | |||
case DIED: | case DIED: | |||
if (status_ok) { | if (status_ok) { | |||
if (matcher_.Matches(error_message)) { | if (matcher_.Matches(error_message)) { | |||
success = true; | success = true; | |||
} else { | } else { | |||
std::ostringstream stream; | std::ostringstream stream; | |||
matcher_.DescribeTo(&stream); | matcher_.DescribeTo(&stream); | |||
buffer << " Result: died but not with expected error.\n" | buffer << " Result: died but not with expected error.\n" | |||
<< " Expected: " << stream.str() << "\n" | << " Expected: " << stream.str() << "\n" | |||
<< "Actual msg:\n" | << "Actual msg:\n" | |||
<< FormatDeathTestOutput(error_message); | << FormatDeathTestOutput(error_message); | |||
} | } | |||
} else { | } else { | |||
buffer << " Result: died but not with expected exit code:\n" | buffer << " Result: died but not with expected exit code:\n" | |||
<< " " << ExitSummary(status()) << "\n" | << " " << ExitSummary(status()) << "\n" | |||
<< "Actual msg:\n" << FormatDeathTestOutput(error_message); | << "Actual msg:\n" | |||
<< FormatDeathTestOutput(error_message); | ||||
} | } | |||
break; | break; | |||
case IN_PROGRESS: | case IN_PROGRESS: | |||
default: | default: | |||
GTEST_LOG_(FATAL) | GTEST_LOG_(FATAL) | |||
<< "DeathTest::Passed somehow called before conclusion of test"; | << "DeathTest::Passed somehow called before conclusion of test"; | |||
} | } | |||
DeathTest::set_last_death_test_message(buffer.GetString()); | DeathTest::set_last_death_test_message(buffer.GetString()); | |||
return success; | return success; | |||
} | } | |||
# if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
// WindowsDeathTest implements death tests on Windows. Due to the | // WindowsDeathTest implements death tests on Windows. Due to the | |||
// specifics of starting new processes on Windows, death tests there are | // specifics of starting new processes on Windows, death tests there are | |||
// always threadsafe, and Google Test considers the | // always threadsafe, and Google Test considers the | |||
// --gtest_death_test_style=fast setting to be equivalent to | // --gtest_death_test_style=fast setting to be equivalent to | |||
// --gtest_death_test_style=threadsafe there. | // --gtest_death_test_style=threadsafe there. | |||
// | // | |||
// A few implementation notes: Like the Linux version, the Windows | // A few implementation notes: Like the Linux version, the Windows | |||
// implementation uses pipes for child-to-parent communication. But due to | // implementation uses pipes for child-to-parent communication. But due to | |||
// the specifics of pipes on Windows, some extra steps are required: | // the specifics of pipes on Windows, some extra steps are required: | |||
// | // | |||
skipping to change at line 682 | skipping to change at line 685 | |||
// acquired the handle to the write end of the pipe. After seeing this | // acquired the handle to the write end of the pipe. After seeing this | |||
// event the parent can release its own handles to make sure its | // event the parent can release its own handles to make sure its | |||
// ReadFile() calls return when the child terminates. | // ReadFile() calls return when the child terminates. | |||
AutoHandle event_handle_; | AutoHandle event_handle_; | |||
}; | }; | |||
// Waits for the child in a death test to exit, returning its exit | // 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 | // status, or 0 if no child process exists. As a side effect, sets the | |||
// outcome data member. | // outcome data member. | |||
int WindowsDeathTest::Wait() { | int WindowsDeathTest::Wait() { | |||
if (!spawned()) | if (!spawned()) return 0; | |||
return 0; | ||||
// Wait until the child either signals that it has acquired the write end | // Wait until the child either signals that it has acquired the write end | |||
// of the pipe or it dies. | // of the pipe or it dies. | |||
const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; | const HANDLE wait_handles[2] = {child_handle_.Get(), event_handle_.Get()}; | |||
switch (::WaitForMultipleObjects(2, | switch (::WaitForMultipleObjects(2, wait_handles, | |||
wait_handles, | ||||
FALSE, // Waits for any of the handles. | FALSE, // Waits for any of the handles. | |||
INFINITE)) { | INFINITE)) { | |||
case WAIT_OBJECT_0: | case WAIT_OBJECT_0: | |||
case WAIT_OBJECT_0 + 1: | case WAIT_OBJECT_0 + 1: | |||
break; | break; | |||
default: | default: | |||
GTEST_DEATH_TEST_CHECK_(false); // Should not get here. | GTEST_DEATH_TEST_CHECK_(false); // Should not get here. | |||
} | } | |||
// The child has acquired the write end of the pipe or exited. | // The child has acquired the write end of the pipe or exited. | |||
// We release the handle on our side and continue. | // We release the handle on our side and continue. | |||
write_handle_.Reset(); | write_handle_.Reset(); | |||
event_handle_.Reset(); | event_handle_.Reset(); | |||
ReadAndInterpretStatusByte(); | ReadAndInterpretStatusByte(); | |||
// Waits for the child process to exit if it haven't already. This | // Waits for the child process to exit if it haven't already. This | |||
// returns immediately if the child has already exited, regardless of | // returns immediately if the child has already exited, regardless of | |||
// whether previous calls to WaitForMultipleObjects synchronized on this | // whether previous calls to WaitForMultipleObjects synchronized on this | |||
// handle or not. | // handle or not. | |||
GTEST_DEATH_TEST_CHECK_( | GTEST_DEATH_TEST_CHECK_(WAIT_OBJECT_0 == | |||
WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), | ::WaitForSingleObject(child_handle_.Get(), INFINITE)); | |||
INFINITE)); | ||||
DWORD status_code; | DWORD status_code; | |||
GTEST_DEATH_TEST_CHECK_( | GTEST_DEATH_TEST_CHECK_( | |||
::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); | ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); | |||
child_handle_.Reset(); | child_handle_.Reset(); | |||
set_status(static_cast<int>(status_code)); | set_status(static_cast<int>(status_code)); | |||
return status(); | return status(); | |||
} | } | |||
// The AssumeRole process for a Windows death test. It creates a child | // The AssumeRole process for a Windows death test. It creates a child | |||
// process with the same executable as the current process to run the | // process with the same executable as the current process to run the | |||
skipping to change at line 745 | skipping to change at line 745 | |||
// processing. | // processing. | |||
set_write_fd(flag->write_fd()); | set_write_fd(flag->write_fd()); | |||
return EXECUTE_TEST; | return EXECUTE_TEST; | |||
} | } | |||
// WindowsDeathTest uses an anonymous pipe to communicate results of | // WindowsDeathTest uses an anonymous pipe to communicate results of | |||
// a death test. | // a death test. | |||
SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), | SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES), | |||
nullptr, TRUE}; | nullptr, TRUE}; | |||
HANDLE read_handle, write_handle; | HANDLE read_handle, write_handle; | |||
GTEST_DEATH_TEST_CHECK_( | GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle, | |||
::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, | &handles_are_inheritable, | |||
0) // Default buffer size. | 0) // Default buffer size. | |||
!= FALSE); | != FALSE); | |||
set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle), | set_read_fd( | |||
O_RDONLY)); | ::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle), O_RDONLY)); | |||
write_handle_.Reset(write_handle); | write_handle_.Reset(write_handle); | |||
event_handle_.Reset(::CreateEvent( | event_handle_.Reset(::CreateEvent( | |||
&handles_are_inheritable, | &handles_are_inheritable, | |||
TRUE, // The event will automatically reset to non-signaled state. | TRUE, // The event will automatically reset to non-signaled state. | |||
FALSE, // The initial state is non-signalled. | FALSE, // The initial state is non-signalled. | |||
nullptr)); // The even is unnamed. | nullptr)); // The even is unnamed. | |||
GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); | GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr); | |||
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | |||
kFilterFlag + "=" + info->test_suite_name() + | "filter=" + info->test_suite_name() + "." + | |||
"." + info->name(); | info->name(); | |||
const std::string internal_flag = | const std::string internal_flag = | |||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + | std::string("--") + GTEST_FLAG_PREFIX_ + | |||
"=" + file_ + "|" + StreamableToString(line_) + "|" + | "internal_run_death_test=" + file_ + "|" + StreamableToString(line_) + | |||
StreamableToString(death_test_index) + "|" + | "|" + StreamableToString(death_test_index) + "|" + | |||
StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) + | StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) + | |||
// size_t has the same width as pointers on both 32-bit and 64-bit | // size_t has the same width as pointers on both 32-bit and 64-bit | |||
// Windows platforms. | // Windows platforms. | |||
// See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. | // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. | |||
"|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) + | "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) + "|" + | |||
"|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get())); | StreamableToString(reinterpret_cast<size_t>(event_handle_.Get())); | |||
char executable_path[_MAX_PATH + 1]; // NOLINT | char executable_path[_MAX_PATH + 1]; // NOLINT | |||
GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, | GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr, | |||
executable_path, | executable_path, | |||
_MAX_PATH)); | _MAX_PATH)); | |||
std::string command_line = | std::string command_line = std::string(::GetCommandLineA()) + " " + | |||
std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + | filter_flag + " \"" + internal_flag + "\""; | |||
internal_flag + "\""; | ||||
DeathTest::set_last_death_test_message(""); | DeathTest::set_last_death_test_message(""); | |||
CaptureStderr(); | CaptureStderr(); | |||
// Flush the log buffers since the log streams are shared with the child. | // Flush the log buffers since the log streams are shared with the child. | |||
FlushInfoLog(); | FlushInfoLog(); | |||
// The child process will share the standard handles with the parent. | // The child process will share the standard handles with the parent. | |||
STARTUPINFOA startup_info; | STARTUPINFOA startup_info; | |||
memset(&startup_info, 0, sizeof(STARTUPINFO)); | memset(&startup_info, 0, sizeof(STARTUPINFO)); | |||
startup_info.dwFlags = STARTF_USESTDHANDLES; | startup_info.dwFlags = STARTF_USESTDHANDLES; | |||
startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); | startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); | |||
startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); | startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); | |||
startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); | startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); | |||
PROCESS_INFORMATION process_info; | PROCESS_INFORMATION process_info; | |||
GTEST_DEATH_TEST_CHECK_( | GTEST_DEATH_TEST_CHECK_( | |||
::CreateProcessA( | ::CreateProcessA( | |||
executable_path, const_cast<char*>(command_line.c_str()), | executable_path, const_cast<char*>(command_line.c_str()), | |||
nullptr, // Retuned process handle is not inheritable. | nullptr, // Returned process handle is not inheritable. | |||
nullptr, // Retuned thread handle is not inheritable. | nullptr, // Returned thread handle is not inheritable. | |||
TRUE, // Child inherits all inheritable handles (for write_handle_). | TRUE, // Child inherits all inheritable handles (for write_handle_). | |||
0x0, // Default creation flags. | 0x0, // Default creation flags. | |||
nullptr, // Inherit the parent's environment. | nullptr, // Inherit the parent's environment. | |||
UnitTest::GetInstance()->original_working_dir(), &startup_info, | UnitTest::GetInstance()->original_working_dir(), &startup_info, | |||
&process_info) != FALSE); | &process_info) != FALSE); | |||
child_handle_.Reset(process_info.hProcess); | child_handle_.Reset(process_info.hProcess); | |||
::CloseHandle(process_info.hThread); | ::CloseHandle(process_info.hThread); | |||
set_spawned(true); | set_spawned(true); | |||
return OVERSEE_TEST; | return OVERSEE_TEST; | |||
} | } | |||
# elif GTEST_OS_FUCHSIA | #elif GTEST_OS_FUCHSIA | |||
class FuchsiaDeathTest : public DeathTestImpl { | class FuchsiaDeathTest : public DeathTestImpl { | |||
public: | public: | |||
FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher, | FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher, | |||
const char* file, int line) | const char* file, int line) | |||
: DeathTestImpl(a_statement, std::move(matcher)), | : DeathTestImpl(a_statement, std::move(matcher)), | |||
file_(file), | file_(file), | |||
line_(line) {} | line_(line) {} | |||
// All of these virtual functions are inherited from DeathTest. | // All of these virtual functions are inherited from DeathTest. | |||
skipping to change at line 858 | skipping to change at line 857 | |||
free(*i); | free(*i); | |||
} | } | |||
} | } | |||
void AddArgument(const char* argument) { | void AddArgument(const char* argument) { | |||
args_.insert(args_.end() - 1, posix::StrDup(argument)); | args_.insert(args_.end() - 1, posix::StrDup(argument)); | |||
} | } | |||
template <typename Str> | template <typename Str> | |||
void AddArguments(const ::std::vector<Str>& arguments) { | void AddArguments(const ::std::vector<Str>& arguments) { | |||
for (typename ::std::vector<Str>::const_iterator i = arguments.begin(); | for (typename ::std::vector<Str>::const_iterator i = arguments.begin(); | |||
i != arguments.end(); | i != arguments.end(); ++i) { | |||
++i) { | ||||
args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); | args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); | |||
} | } | |||
} | } | |||
char* const* Argv() { | char* const* Argv() { return &args_[0]; } | |||
return &args_[0]; | ||||
} | ||||
int size() { | int size() { return static_cast<int>(args_.size()) - 1; } | |||
return static_cast<int>(args_.size()) - 1; | ||||
} | ||||
private: | private: | |||
std::vector<char*> args_; | std::vector<char*> args_; | |||
}; | }; | |||
// Waits for the child in a death test to exit, returning its exit | // 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 | // status, or 0 if no child process exists. As a side effect, sets the | |||
// outcome data member. | // outcome data member. | |||
int FuchsiaDeathTest::Wait() { | int FuchsiaDeathTest::Wait() { | |||
const int kProcessKey = 0; | const int kProcessKey = 0; | |||
const int kSocketKey = 1; | const int kSocketKey = 1; | |||
const int kExceptionKey = 2; | const int kExceptionKey = 2; | |||
if (!spawned()) | if (!spawned()) return 0; | |||
return 0; | ||||
// Create a port to wait for socket/task/exception events. | // Create a port to wait for socket/task/exception events. | |||
zx_status_t status_zx; | zx_status_t status_zx; | |||
zx::port port; | zx::port port; | |||
status_zx = zx::port::create(0, &port); | status_zx = zx::port::create(0, &port); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
// Register to wait for the child process to terminate. | // Register to wait for the child process to terminate. | |||
status_zx = child_process_.wait_async( | status_zx = | |||
port, kProcessKey, ZX_PROCESS_TERMINATED, 0); | child_process_.wait_async(port, kProcessKey, ZX_PROCESS_TERMINATED, 0); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
// Register to wait for the socket to be readable or closed. | // Register to wait for the socket to be readable or closed. | |||
status_zx = stderr_socket_.wait_async( | status_zx = stderr_socket_.wait_async( | |||
port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); | port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
// Register to wait for an exception. | // Register to wait for an exception. | |||
status_zx = exception_channel_.wait_async( | status_zx = exception_channel_.wait_async(port, kExceptionKey, | |||
port, kExceptionKey, ZX_CHANNEL_READABLE, 0); | ZX_CHANNEL_READABLE, 0); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
bool process_terminated = false; | bool process_terminated = false; | |||
bool socket_closed = false; | bool socket_closed = false; | |||
do { | do { | |||
zx_port_packet_t packet = {}; | zx_port_packet_t packet = {}; | |||
status_zx = port.wait(zx::time::infinite(), &packet); | status_zx = port.wait(zx::time::infinite(), &packet); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
if (packet.key == kExceptionKey) { | if (packet.key == kExceptionKey) { | |||
skipping to change at line 934 | skipping to change at line 927 | |||
process_terminated = true; | process_terminated = true; | |||
} else if (packet.key == kSocketKey) { | } else if (packet.key == kSocketKey) { | |||
GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); | GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); | |||
if (packet.signal.observed & ZX_SOCKET_READABLE) { | if (packet.signal.observed & ZX_SOCKET_READABLE) { | |||
// Read data from the socket. | // Read data from the socket. | |||
constexpr size_t kBufferSize = 1024; | constexpr size_t kBufferSize = 1024; | |||
do { | do { | |||
size_t old_length = captured_stderr_.length(); | size_t old_length = captured_stderr_.length(); | |||
size_t bytes_read = 0; | size_t bytes_read = 0; | |||
captured_stderr_.resize(old_length + kBufferSize); | captured_stderr_.resize(old_length + kBufferSize); | |||
status_zx = stderr_socket_.read( | status_zx = | |||
0, &captured_stderr_.front() + old_length, kBufferSize, | stderr_socket_.read(0, &captured_stderr_.front() + old_length, | |||
&bytes_read); | kBufferSize, &bytes_read); | |||
captured_stderr_.resize(old_length + bytes_read); | captured_stderr_.resize(old_length + bytes_read); | |||
} while (status_zx == ZX_OK); | } while (status_zx == ZX_OK); | |||
if (status_zx == ZX_ERR_PEER_CLOSED) { | if (status_zx == ZX_ERR_PEER_CLOSED) { | |||
socket_closed = true; | socket_closed = true; | |||
} else { | } else { | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); | |||
status_zx = stderr_socket_.wait_async( | status_zx = stderr_socket_.wait_async( | |||
port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); | port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
} | } | |||
skipping to change at line 990 | skipping to change at line 983 | |||
// processing. | // processing. | |||
set_write_fd(kFuchsiaReadPipeFd); | set_write_fd(kFuchsiaReadPipeFd); | |||
return EXECUTE_TEST; | return EXECUTE_TEST; | |||
} | } | |||
// Flush the log buffers since the log streams are shared with the child. | // Flush the log buffers since the log streams are shared with the child. | |||
FlushInfoLog(); | FlushInfoLog(); | |||
// Build the child process command line. | // Build the child process command line. | |||
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | |||
kFilterFlag + "=" + info->test_suite_name() + | "filter=" + info->test_suite_name() + "." + | |||
"." + info->name(); | info->name(); | |||
const std::string internal_flag = | const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | |||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" | kInternalRunDeathTestFlag + "=" + file_ + | |||
+ file_ + "|" | "|" + StreamableToString(line_) + "|" + | |||
+ StreamableToString(line_) + "|" | StreamableToString(death_test_index); | |||
+ StreamableToString(death_test_index); | ||||
Arguments args; | Arguments args; | |||
args.AddArguments(GetInjectableArgvs()); | args.AddArguments(GetInjectableArgvs()); | |||
args.AddArgument(filter_flag.c_str()); | args.AddArgument(filter_flag.c_str()); | |||
args.AddArgument(internal_flag.c_str()); | args.AddArgument(internal_flag.c_str()); | |||
// Build the pipe for communication with the child. | // Build the pipe for communication with the child. | |||
zx_status_t status; | zx_status_t status; | |||
zx_handle_t child_pipe_handle; | zx_handle_t child_pipe_handle; | |||
int child_pipe_fd; | int child_pipe_fd; | |||
status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); | status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle); | |||
skipping to change at line 1019 | skipping to change at line 1011 | |||
// Set the pipe handle for the child. | // Set the pipe handle for the child. | |||
fdio_spawn_action_t spawn_actions[2] = {}; | fdio_spawn_action_t spawn_actions[2] = {}; | |||
fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; | fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; | |||
add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; | add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; | |||
add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); | add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd); | |||
add_handle_action->h.handle = child_pipe_handle; | add_handle_action->h.handle = child_pipe_handle; | |||
// Create a socket pair will be used to receive the child process' stderr. | // Create a socket pair will be used to receive the child process' stderr. | |||
zx::socket stderr_producer_socket; | zx::socket stderr_producer_socket; | |||
status = | status = zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); | |||
zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); | ||||
GTEST_DEATH_TEST_CHECK_(status >= 0); | GTEST_DEATH_TEST_CHECK_(status >= 0); | |||
int stderr_producer_fd = -1; | int stderr_producer_fd = -1; | |||
status = | status = | |||
fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); | fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd); | |||
GTEST_DEATH_TEST_CHECK_(status >= 0); | GTEST_DEATH_TEST_CHECK_(status >= 0); | |||
// Make the stderr socket nonblocking. | // Make the stderr socket nonblocking. | |||
GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); | GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); | |||
fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; | fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; | |||
add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; | add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; | |||
add_stderr_action->fd.local_fd = stderr_producer_fd; | add_stderr_action->fd.local_fd = stderr_producer_fd; | |||
add_stderr_action->fd.target_fd = STDERR_FILENO; | add_stderr_action->fd.target_fd = STDERR_FILENO; | |||
// Create a child job. | // Create a child job. | |||
zx_handle_t child_job = ZX_HANDLE_INVALID; | zx_handle_t child_job = ZX_HANDLE_INVALID; | |||
status = zx_job_create(zx_job_default(), 0, & child_job); | status = zx_job_create(zx_job_default(), 0, &child_job); | |||
GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | |||
zx_policy_basic_t policy; | zx_policy_basic_t policy; | |||
policy.condition = ZX_POL_NEW_ANY; | policy.condition = ZX_POL_NEW_ANY; | |||
policy.policy = ZX_POL_ACTION_ALLOW; | policy.policy = ZX_POL_ACTION_ALLOW; | |||
status = zx_job_set_policy( | status = zx_job_set_policy(child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, | |||
child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1); | &policy, 1); | |||
GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | |||
// Create an exception channel attached to the |child_job|, to allow | // Create an exception channel attached to the |child_job|, to allow | |||
// us to suppress the system default exception handler from firing. | // us to suppress the system default exception handler from firing. | |||
status = | status = zx_task_create_exception_channel( | |||
zx_task_create_exception_channel( | child_job, 0, exception_channel_.reset_and_get_address()); | |||
child_job, 0, exception_channel_.reset_and_get_address()); | ||||
GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | |||
// Spawn the child process. | // Spawn the child process. | |||
status = fdio_spawn_etc( | status = fdio_spawn_etc(child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], | |||
child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr, | args.Argv(), nullptr, 2, spawn_actions, | |||
2, spawn_actions, child_process_.reset_and_get_address(), nullptr); | child_process_.reset_and_get_address(), nullptr); | |||
GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status == ZX_OK); | |||
set_spawned(true); | set_spawned(true); | |||
return OVERSEE_TEST; | return OVERSEE_TEST; | |||
} | } | |||
std::string FuchsiaDeathTest::GetErrorLogs() { | std::string FuchsiaDeathTest::GetErrorLogs() { return captured_stderr_; } | |||
return captured_stderr_; | ||||
} | ||||
#else // We are neither on Windows, nor on Fuchsia. | #else // We are neither on Windows, nor on Fuchsia. | |||
// ForkingDeathTest provides implementations for most of the abstract | // ForkingDeathTest provides implementations for most of the abstract | |||
// methods of the DeathTest interface. Only the AssumeRole method is | // methods of the DeathTest interface. Only the AssumeRole method is | |||
// left undefined. | // left undefined. | |||
class ForkingDeathTest : public DeathTestImpl { | class ForkingDeathTest : public DeathTestImpl { | |||
public: | public: | |||
ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher); | ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher); | |||
skipping to change at line 1096 | skipping to change at line 1084 | |||
// Constructs a ForkingDeathTest. | // Constructs a ForkingDeathTest. | |||
ForkingDeathTest::ForkingDeathTest(const char* a_statement, | ForkingDeathTest::ForkingDeathTest(const char* a_statement, | |||
Matcher<const std::string&> matcher) | Matcher<const std::string&> matcher) | |||
: DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} | : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {} | |||
// Waits for the child in a death test to exit, returning its exit | // 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 | // status, or 0 if no child process exists. As a side effect, sets the | |||
// outcome data member. | // outcome data member. | |||
int ForkingDeathTest::Wait() { | int ForkingDeathTest::Wait() { | |||
if (!spawned()) | if (!spawned()) return 0; | |||
return 0; | ||||
ReadAndInterpretStatusByte(); | ReadAndInterpretStatusByte(); | |||
int status_value; | int status_value; | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); | |||
set_status(status_value); | set_status(status_value); | |||
return status_value; | return status_value; | |||
} | } | |||
// A concrete death test class that forks, then immediately runs the test | // A concrete death test class that forks, then immediately runs the test | |||
skipping to change at line 1176 | skipping to change at line 1163 | |||
ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher, | ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher, | |||
const char* file, int line) | const char* file, int line) | |||
: ForkingDeathTest(a_statement, std::move(matcher)), | : ForkingDeathTest(a_statement, std::move(matcher)), | |||
file_(file), | file_(file), | |||
line_(line) {} | line_(line) {} | |||
TestRole AssumeRole() override; | TestRole AssumeRole() override; | |||
private: | private: | |||
static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() { | static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() { | |||
::std::vector<std::string> args = GetInjectableArgvs(); | ::std::vector<std::string> args = GetInjectableArgvs(); | |||
# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) | #if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) | |||
::std::vector<std::string> extra_args = | ::std::vector<std::string> extra_args = | |||
GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); | GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); | |||
args.insert(args.end(), extra_args.begin(), extra_args.end()); | args.insert(args.end(), extra_args.begin(), extra_args.end()); | |||
# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) | #endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) | |||
return args; | return args; | |||
} | } | |||
// The name of the file in which the death test is located. | // The name of the file in which the death test is located. | |||
const char* const file_; | const char* const file_; | |||
// The line number on which the death test is located. | // The line number on which the death test is located. | |||
const int line_; | const int line_; | |||
}; | }; | |||
// Utility class for accumulating command-line arguments. | // Utility class for accumulating command-line arguments. | |||
class Arguments { | class Arguments { | |||
skipping to change at line 1207 | skipping to change at line 1194 | |||
free(*i); | free(*i); | |||
} | } | |||
} | } | |||
void AddArgument(const char* argument) { | void AddArgument(const char* argument) { | |||
args_.insert(args_.end() - 1, posix::StrDup(argument)); | args_.insert(args_.end() - 1, posix::StrDup(argument)); | |||
} | } | |||
template <typename Str> | template <typename Str> | |||
void AddArguments(const ::std::vector<Str>& arguments) { | void AddArguments(const ::std::vector<Str>& arguments) { | |||
for (typename ::std::vector<Str>::const_iterator i = arguments.begin(); | for (typename ::std::vector<Str>::const_iterator i = arguments.begin(); | |||
i != arguments.end(); | i != arguments.end(); ++i) { | |||
++i) { | ||||
args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); | args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); | |||
} | } | |||
} | } | |||
char* const* Argv() { | char* const* Argv() { return &args_[0]; } | |||
return &args_[0]; | ||||
} | ||||
private: | private: | |||
std::vector<char*> args_; | std::vector<char*> args_; | |||
}; | }; | |||
// A struct that encompasses the arguments to the child process of a | // A struct that encompasses the arguments to the child process of a | |||
// threadsafe-style death test process. | // threadsafe-style death test process. | |||
struct ExecDeathTestArgs { | struct ExecDeathTestArgs { | |||
char* const* argv; // Command-line arguments for the child's call to exec | char* const* argv; // Command-line arguments for the child's call to exec | |||
int close_fd; // File descriptor to close; the read end of a pipe | int close_fd; // File descriptor to close; the read end of a pipe | |||
}; | }; | |||
# if GTEST_OS_QNX | #if GTEST_OS_QNX | |||
extern "C" char** environ; | extern "C" char** environ; | |||
# else // GTEST_OS_QNX | #else // GTEST_OS_QNX | |||
// The main function for a threadsafe-style death test child process. | // The main function for a threadsafe-style death test child process. | |||
// This function is called in a clone()-ed process and thus must avoid | // This function is called in a clone()-ed process and thus must avoid | |||
// any potentially unsafe operations like malloc or libc functions. | // any potentially unsafe operations like malloc or libc functions. | |||
static int ExecDeathTestChildMain(void* child_arg) { | static int ExecDeathTestChildMain(void* child_arg) { | |||
ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg); | ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); | |||
// We need to execute the test program in the same environment where | // We need to execute the test program in the same environment where | |||
// it was originally invoked. Therefore we change to the original | // it was originally invoked. Therefore we change to the original | |||
// working directory first. | // working directory first. | |||
const char* const original_dir = | const char* const original_dir = | |||
UnitTest::GetInstance()->original_working_dir(); | UnitTest::GetInstance()->original_working_dir(); | |||
// We can safely call chdir() as it's a direct system call. | // We can safely call chdir() as it's a direct system call. | |||
if (chdir(original_dir) != 0) { | if (chdir(original_dir) != 0) { | |||
DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + | DeathTestAbort(std::string("chdir(\"") + original_dir + | |||
GetLastErrnoDescription()); | "\") failed: " + GetLastErrnoDescription()); | |||
return EXIT_FAILURE; | return EXIT_FAILURE; | |||
} | } | |||
// We can safely call execv() as it's almost a direct system call. We | // We can safely call execv() as it's almost a direct system call. We | |||
// cannot use execvp() as it's a libc function and thus potentially | // cannot use execvp() as it's a libc function and thus potentially | |||
// unsafe. Since execv() doesn't search the PATH, the user must | // unsafe. Since execv() doesn't search the PATH, the user must | |||
// invoke the test program via a valid path that contains at least | // invoke the test program via a valid path that contains at least | |||
// one path separator. | // one path separator. | |||
execv(args->argv[0], args->argv); | execv(args->argv[0], args->argv); | |||
DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " + | DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " + | |||
original_dir + " failed: " + | original_dir + " failed: " + GetLastErrnoDescription()); | |||
GetLastErrnoDescription()); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | |||
} | } | |||
# endif // GTEST_OS_QNX | #endif // GTEST_OS_QNX | |||
# if GTEST_HAS_CLONE | #if GTEST_HAS_CLONE | |||
// Two utility routines that together determine the direction the stack | // Two utility routines that together determine the direction the stack | |||
// grows. | // grows. | |||
// This could be accomplished more elegantly by a single recursive | // This could be accomplished more elegantly by a single recursive | |||
// function, but we want to guard against the unlikely possibility of | // function, but we want to guard against the unlikely possibility of | |||
// a smart compiler optimizing the recursion away. | // a smart compiler optimizing the recursion away. | |||
// | // | |||
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining | // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining | |||
// StackLowerThanAddress into StackGrowsDown, which then doesn't give | // StackLowerThanAddress into StackGrowsDown, which then doesn't give | |||
// correct answer. | // correct answer. | |||
static void StackLowerThanAddress(const void* ptr, | static void StackLowerThanAddress(const void* ptr, | |||
skipping to change at line 1296 | skipping to change at line 1279 | |||
// Make sure AddressSanitizer does not tamper with the stack here. | // Make sure AddressSanitizer does not tamper with the stack here. | |||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ | GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ | |||
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ | GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ | |||
static bool StackGrowsDown() { | static bool StackGrowsDown() { | |||
int dummy = 0; | int dummy = 0; | |||
bool result; | bool result; | |||
StackLowerThanAddress(&dummy, &result); | StackLowerThanAddress(&dummy, &result); | |||
return result; | return result; | |||
} | } | |||
# endif // GTEST_HAS_CLONE | #endif // GTEST_HAS_CLONE | |||
// Spawns a child process with the same executable as the current process in | // 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 | // a thread-safe manner and instructs it to run the death test. The | |||
// implementation uses fork(2) + exec. On systems where clone(2) is | // implementation uses fork(2) + exec. On systems where clone(2) is | |||
// available, it is used instead, being slightly more thread-safe. On QNX, | // available, it is used instead, being slightly more thread-safe. On QNX, | |||
// fork supports only single-threaded environments, so this function uses | // fork supports only single-threaded environments, so this function uses | |||
// spawn(2) there instead. The function dies with an error message if | // spawn(2) there instead. The function dies with an error message if | |||
// anything goes wrong. | // anything goes wrong. | |||
static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { | static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { | |||
ExecDeathTestArgs args = { argv, close_fd }; | ExecDeathTestArgs args = {argv, close_fd}; | |||
pid_t child_pid = -1; | pid_t child_pid = -1; | |||
# if GTEST_OS_QNX | #if GTEST_OS_QNX | |||
// Obtains the current directory and sets it to be closed in the child | // Obtains the current directory and sets it to be closed in the child | |||
// process. | // process. | |||
const int cwd_fd = open(".", O_RDONLY); | const int cwd_fd = open(".", O_RDONLY); | |||
GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); | GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); | |||
// We need to execute the test program in the same environment where | // We need to execute the test program in the same environment where | |||
// it was originally invoked. Therefore we change to the original | // it was originally invoked. Therefore we change to the original | |||
// working directory first. | // working directory first. | |||
const char* const original_dir = | const char* const original_dir = | |||
UnitTest::GetInstance()->original_working_dir(); | UnitTest::GetInstance()->original_working_dir(); | |||
// We can safely call chdir() as it's a direct system call. | // We can safely call chdir() as it's a direct system call. | |||
if (chdir(original_dir) != 0) { | if (chdir(original_dir) != 0) { | |||
DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + | DeathTestAbort(std::string("chdir(\"") + original_dir + | |||
GetLastErrnoDescription()); | "\") failed: " + GetLastErrnoDescription()); | |||
return EXIT_FAILURE; | return EXIT_FAILURE; | |||
} | } | |||
int fd_flags; | int fd_flags; | |||
// Set close_fd to be closed after spawn. | // Set close_fd to be closed after spawn. | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, | GTEST_DEATH_TEST_CHECK_SYSCALL_( | |||
fd_flags | FD_CLOEXEC)); | fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); | |||
struct inheritance inherit = {0}; | struct inheritance inherit = {0}; | |||
// spawn is a system call. | // spawn is a system call. | |||
child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ); | child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ); | |||
// Restores the current working directory. | // Restores the current working directory. | |||
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); | GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); | |||
# else // GTEST_OS_QNX | #else // GTEST_OS_QNX | |||
# if GTEST_OS_LINUX | #if GTEST_OS_LINUX | |||
// When a SIGPROF signal is received while fork() or clone() are executing, | // When a SIGPROF signal is received while fork() or clone() are executing, | |||
// the process may hang. To avoid this, we ignore SIGPROF here and re-enable | // the process may hang. To avoid this, we ignore SIGPROF here and re-enable | |||
// it after the call to fork()/clone() is complete. | // it after the call to fork()/clone() is complete. | |||
struct sigaction saved_sigprof_action; | struct sigaction saved_sigprof_action; | |||
struct sigaction ignore_sigprof_action; | struct sigaction ignore_sigprof_action; | |||
memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); | memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); | |||
sigemptyset(&ignore_sigprof_action.sa_mask); | sigemptyset(&ignore_sigprof_action.sa_mask); | |||
ignore_sigprof_action.sa_handler = SIG_IGN; | ignore_sigprof_action.sa_handler = SIG_IGN; | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( | GTEST_DEATH_TEST_CHECK_SYSCALL_( | |||
SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); | sigaction(SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); | |||
# endif // GTEST_OS_LINUX | #endif // GTEST_OS_LINUX | |||
# if GTEST_HAS_CLONE | #if GTEST_HAS_CLONE | |||
const bool use_fork = GTEST_FLAG(death_test_use_fork); | const bool use_fork = GTEST_FLAG_GET(death_test_use_fork); | |||
if (!use_fork) { | if (!use_fork) { | |||
static const bool stack_grows_down = StackGrowsDown(); | static const bool stack_grows_down = StackGrowsDown(); | |||
const auto stack_size = static_cast<size_t>(getpagesize() * 2); | const auto stack_size = static_cast<size_t>(getpagesize() * 2); | |||
// MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. | // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. | |||
void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, | void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, | |||
MAP_ANON | MAP_PRIVATE, -1, 0); | MAP_ANON | MAP_PRIVATE, -1, 0); | |||
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); | GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); | |||
// Maximum stack alignment in bytes: For a downward-growing stack, this | // Maximum stack alignment in bytes: For a downward-growing stack, this | |||
// amount is subtracted from size of the stack space to get an address | // amount is subtracted from size of the stack space to get an address | |||
// that is within the stack space and is aligned on all systems we care | // that is within the stack space and is aligned on all systems we care | |||
// about. As far as I know there is no ABI with stack alignment greater | // about. As far as I know there is no ABI with stack alignment greater | |||
// than 64. We assume stack and stack_size already have alignment of | // than 64. We assume stack and stack_size already have alignment of | |||
// kMaxStackAlignment. | // kMaxStackAlignment. | |||
const size_t kMaxStackAlignment = 64; | const size_t kMaxStackAlignment = 64; | |||
void* const stack_top = | void* const stack_top = | |||
static_cast<char*>(stack) + | static_cast<char*>(stack) + | |||
(stack_grows_down ? stack_size - kMaxStackAlignment : 0); | (stack_grows_down ? stack_size - kMaxStackAlignment : 0); | |||
GTEST_DEATH_TEST_CHECK_( | GTEST_DEATH_TEST_CHECK_( | |||
static_cast<size_t>(stack_size) > kMaxStackAlignment && | static_cast<size_t>(stack_size) > kMaxStackAlignment && | |||
reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0); | reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0); | |||
child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); | child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); | |||
GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); | GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); | |||
} | } | |||
# else | #else | |||
const bool use_fork = true; | const bool use_fork = true; | |||
# endif // GTEST_HAS_CLONE | #endif // GTEST_HAS_CLONE | |||
if (use_fork && (child_pid = fork()) == 0) { | if (use_fork && (child_pid = fork()) == 0) { | |||
ExecDeathTestChildMain(&args); | ExecDeathTestChildMain(&args); | |||
_exit(0); | _exit(0); | |||
} | } | |||
# endif // GTEST_OS_QNX | #endif // GTEST_OS_QNX | |||
# if GTEST_OS_LINUX | #if GTEST_OS_LINUX | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_( | GTEST_DEATH_TEST_CHECK_SYSCALL_( | |||
sigaction(SIGPROF, &saved_sigprof_action, nullptr)); | sigaction(SIGPROF, &saved_sigprof_action, nullptr)); | |||
# endif // GTEST_OS_LINUX | #endif // GTEST_OS_LINUX | |||
GTEST_DEATH_TEST_CHECK_(child_pid != -1); | GTEST_DEATH_TEST_CHECK_(child_pid != -1); | |||
return child_pid; | return child_pid; | |||
} | } | |||
// The AssumeRole process for a fork-and-exec death test. It re-executes the | // The AssumeRole process for a fork-and-exec death test. It re-executes the | |||
// main program from the beginning, setting the --gtest_filter | // main program from the beginning, setting the --gtest_filter | |||
// and --gtest_internal_run_death_test flags to cause only the current | // and --gtest_internal_run_death_test flags to cause only the current | |||
// death test to be re-run. | // death test to be re-run. | |||
DeathTest::TestRole ExecDeathTest::AssumeRole() { | DeathTest::TestRole ExecDeathTest::AssumeRole() { | |||
skipping to change at line 1423 | skipping to change at line 1406 | |||
return EXECUTE_TEST; | return EXECUTE_TEST; | |||
} | } | |||
int pipe_fd[2]; | int pipe_fd[2]; | |||
GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); | GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); | |||
// Clear the close-on-exec flag on the write end of the pipe, lest | // Clear the close-on-exec flag on the write end of the pipe, lest | |||
// it be closed when the child process does an exec: | // it be closed when the child process does an exec: | |||
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); | GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); | |||
const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | |||
kFilterFlag + "=" + info->test_suite_name() + | "filter=" + info->test_suite_name() + "." + | |||
"." + info->name(); | info->name(); | |||
const std::string internal_flag = | const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + | |||
std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" | "internal_run_death_test=" + file_ + "|" + | |||
+ file_ + "|" + StreamableToString(line_) + "|" | StreamableToString(line_) + "|" + | |||
+ StreamableToString(death_test_index) + "|" | StreamableToString(death_test_index) + "|" + | |||
+ StreamableToString(pipe_fd[1]); | StreamableToString(pipe_fd[1]); | |||
Arguments args; | Arguments args; | |||
args.AddArguments(GetArgvsForDeathTestChildProcess()); | args.AddArguments(GetArgvsForDeathTestChildProcess()); | |||
args.AddArgument(filter_flag.c_str()); | args.AddArgument(filter_flag.c_str()); | |||
args.AddArgument(internal_flag.c_str()); | args.AddArgument(internal_flag.c_str()); | |||
DeathTest::set_last_death_test_message(""); | DeathTest::set_last_death_test_message(""); | |||
CaptureStderr(); | CaptureStderr(); | |||
// See the comment in NoExecDeathTest::AssumeRole for why the next line | // See the comment in NoExecDeathTest::AssumeRole for why the next line | |||
// is necessary. | // is necessary. | |||
FlushInfoLog(); | FlushInfoLog(); | |||
const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); | const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); | GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); | |||
set_child_pid(child_pid); | set_child_pid(child_pid); | |||
set_read_fd(pipe_fd[0]); | set_read_fd(pipe_fd[0]); | |||
set_spawned(true); | set_spawned(true); | |||
return OVERSEE_TEST; | return OVERSEE_TEST; | |||
} | } | |||
# endif // !GTEST_OS_WINDOWS | #endif // !GTEST_OS_WINDOWS | |||
// Creates a concrete DeathTest-derived class that depends on the | // Creates a concrete DeathTest-derived class that depends on the | |||
// --gtest_death_test_style flag, and sets the pointer pointed to | // --gtest_death_test_style flag, and sets the pointer pointed to | |||
// by the "test" argument to its address. If the test should be | // by the "test" argument to its address. If the test should be | |||
// skipped, sets that pointer to NULL. Returns true, unless the | // skipped, sets that pointer to NULL. Returns true, unless the | |||
// flag is set to an invalid value. | // flag is set to an invalid value. | |||
bool DefaultDeathTestFactory::Create(const char* statement, | bool DefaultDeathTestFactory::Create(const char* statement, | |||
Matcher<const std::string&> matcher, | Matcher<const std::string&> matcher, | |||
const char* file, int line, | const char* file, int line, | |||
DeathTest** test) { | DeathTest** test) { | |||
UnitTestImpl* const impl = GetUnitTestImpl(); | UnitTestImpl* const impl = GetUnitTestImpl(); | |||
const InternalRunDeathTestFlag* const flag = | const InternalRunDeathTestFlag* const flag = | |||
impl->internal_run_death_test_flag(); | impl->internal_run_death_test_flag(); | |||
const int death_test_index = impl->current_test_info() | const int death_test_index = | |||
->increment_death_test_count(); | impl->current_test_info()->increment_death_test_count(); | |||
if (flag != nullptr) { | if (flag != nullptr) { | |||
if (death_test_index > flag->index()) { | if (death_test_index > flag->index()) { | |||
DeathTest::set_last_death_test_message( | DeathTest::set_last_death_test_message( | |||
"Death test count (" + StreamableToString(death_test_index) | "Death test count (" + StreamableToString(death_test_index) + | |||
+ ") somehow exceeded expected maximum (" | ") somehow exceeded expected maximum (" + | |||
+ StreamableToString(flag->index()) + ")"); | StreamableToString(flag->index()) + ")"); | |||
return false; | return false; | |||
} | } | |||
if (!(flag->file() == file && flag->line() == line && | if (!(flag->file() == file && flag->line() == line && | |||
flag->index() == death_test_index)) { | flag->index() == death_test_index)) { | |||
*test = nullptr; | *test = nullptr; | |||
return true; | return true; | |||
} | } | |||
} | } | |||
# if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
if (GTEST_FLAG(death_test_style) == "threadsafe" || | if (GTEST_FLAG_GET(death_test_style) == "threadsafe" || | |||
GTEST_FLAG(death_test_style) == "fast") { | GTEST_FLAG_GET(death_test_style) == "fast") { | |||
*test = new WindowsDeathTest(statement, std::move(matcher), file, line); | *test = new WindowsDeathTest(statement, std::move(matcher), file, line); | |||
} | } | |||
# elif GTEST_OS_FUCHSIA | #elif GTEST_OS_FUCHSIA | |||
if (GTEST_FLAG(death_test_style) == "threadsafe" || | if (GTEST_FLAG_GET(death_test_style) == "threadsafe" || | |||
GTEST_FLAG(death_test_style) == "fast") { | GTEST_FLAG_GET(death_test_style) == "fast") { | |||
*test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); | *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line); | |||
} | } | |||
# else | #else | |||
if (GTEST_FLAG(death_test_style) == "threadsafe") { | if (GTEST_FLAG_GET(death_test_style) == "threadsafe") { | |||
*test = new ExecDeathTest(statement, std::move(matcher), file, line); | *test = new ExecDeathTest(statement, std::move(matcher), file, line); | |||
} else if (GTEST_FLAG(death_test_style) == "fast") { | } else if (GTEST_FLAG_GET(death_test_style) == "fast") { | |||
*test = new NoExecDeathTest(statement, std::move(matcher)); | *test = new NoExecDeathTest(statement, std::move(matcher)); | |||
} | } | |||
# endif // GTEST_OS_WINDOWS | #endif // GTEST_OS_WINDOWS | |||
else { // NOLINT - this is more readable than unbalanced brackets inside #if. | else { // NOLINT - this is more readable than unbalanced brackets inside #if. | |||
DeathTest::set_last_death_test_message( | DeathTest::set_last_death_test_message("Unknown death test style \"" + | |||
"Unknown death test style \"" + GTEST_FLAG(death_test_style) | GTEST_FLAG_GET(death_test_style) + | |||
+ "\" encountered"); | "\" encountered"); | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
# if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
// Recreates the pipe and event handles from the provided parameters, | // Recreates the pipe and event handles from the provided parameters, | |||
// signals the event, and returns a file descriptor wrapped around the pipe | // signals the event, and returns a file descriptor wrapped around the pipe | |||
// handle. This function is called in the child process only. | // handle. This function is called in the child process only. | |||
static int GetStatusFileDescriptor(unsigned int parent_process_id, | static int GetStatusFileDescriptor(unsigned int parent_process_id, | |||
size_t write_handle_as_size_t, | size_t write_handle_as_size_t, | |||
size_t event_handle_as_size_t) { | size_t event_handle_as_size_t) { | |||
AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, | AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, | |||
FALSE, // Non-inheritable. | FALSE, // Non-inheritable. | |||
parent_process_id)); | parent_process_id)); | |||
if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { | if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { | |||
DeathTestAbort("Unable to open parent process " + | DeathTestAbort("Unable to open parent process " + | |||
StreamableToString(parent_process_id)); | StreamableToString(parent_process_id)); | |||
} | } | |||
GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); | GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); | |||
const HANDLE write_handle = | const HANDLE write_handle = reinterpret_cast<HANDLE>(write_handle_as_size_t); | |||
reinterpret_cast<HANDLE>(write_handle_as_size_t); | ||||
HANDLE dup_write_handle; | HANDLE dup_write_handle; | |||
// The newly initialized handle is accessible only 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 | // process. To obtain one accessible within the child, we need to use | |||
// DuplicateHandle. | // DuplicateHandle. | |||
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, | if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, | |||
::GetCurrentProcess(), &dup_write_handle, | ::GetCurrentProcess(), &dup_write_handle, | |||
0x0, // Requested privileges ignored since | 0x0, // Requested privileges ignored since | |||
// DUPLICATE_SAME_ACCESS is used. | // DUPLICATE_SAME_ACCESS is used. | |||
FALSE, // Request non-inheritable handler. | FALSE, // Request non-inheritable handler. | |||
skipping to change at line 1557 | skipping to change at line 1539 | |||
DeathTestAbort("Unable to duplicate the pipe handle " + | DeathTestAbort("Unable to duplicate the pipe handle " + | |||
StreamableToString(write_handle_as_size_t) + | StreamableToString(write_handle_as_size_t) + | |||
" from the parent process " + | " from the parent process " + | |||
StreamableToString(parent_process_id)); | StreamableToString(parent_process_id)); | |||
} | } | |||
const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t); | const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t); | |||
HANDLE dup_event_handle; | HANDLE dup_event_handle; | |||
if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, | if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, | |||
::GetCurrentProcess(), &dup_event_handle, | ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, | |||
0x0, | ||||
FALSE, | ||||
DUPLICATE_SAME_ACCESS)) { | DUPLICATE_SAME_ACCESS)) { | |||
DeathTestAbort("Unable to duplicate the event handle " + | DeathTestAbort("Unable to duplicate the event handle " + | |||
StreamableToString(event_handle_as_size_t) + | StreamableToString(event_handle_as_size_t) + | |||
" from the parent process " + | " from the parent process " + | |||
StreamableToString(parent_process_id)); | StreamableToString(parent_process_id)); | |||
} | } | |||
const int write_fd = | const int write_fd = | |||
::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND); | ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND); | |||
if (write_fd == -1) { | if (write_fd == -1) { | |||
skipping to change at line 1581 | skipping to change at line 1561 | |||
StreamableToString(write_handle_as_size_t) + | StreamableToString(write_handle_as_size_t) + | |||
" to a file descriptor"); | " to a file descriptor"); | |||
} | } | |||
// Signals the parent that the write end of the pipe has been acquired | // Signals the parent that the write end of the pipe has been acquired | |||
// so the parent can release its own write end. | // so the parent can release its own write end. | |||
::SetEvent(dup_event_handle); | ::SetEvent(dup_event_handle); | |||
return write_fd; | return write_fd; | |||
} | } | |||
# endif // GTEST_OS_WINDOWS | #endif // GTEST_OS_WINDOWS | |||
// Returns a newly created InternalRunDeathTestFlag object with fields | // Returns a newly created InternalRunDeathTestFlag object with fields | |||
// initialized from the GTEST_FLAG(internal_run_death_test) flag if | // initialized from the GTEST_FLAG(internal_run_death_test) flag if | |||
// the flag is specified; otherwise returns NULL. | // the flag is specified; otherwise returns NULL. | |||
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { | InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { | |||
if (GTEST_FLAG(internal_run_death_test) == "") return nullptr; | if (GTEST_FLAG_GET(internal_run_death_test) == "") return nullptr; | |||
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we | // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we | |||
// can use it here. | // can use it here. | |||
int line = -1; | int line = -1; | |||
int index = -1; | int index = -1; | |||
::std::vector< ::std::string> fields; | ::std::vector< ::std::string> fields; | |||
SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); | SplitString(GTEST_FLAG_GET(internal_run_death_test), '|', &fields); | |||
int write_fd = -1; | int write_fd = -1; | |||
# if GTEST_OS_WINDOWS | #if GTEST_OS_WINDOWS | |||
unsigned int parent_process_id = 0; | unsigned int parent_process_id = 0; | |||
size_t write_handle_as_size_t = 0; | size_t write_handle_as_size_t = 0; | |||
size_t event_handle_as_size_t = 0; | size_t event_handle_as_size_t = 0; | |||
if (fields.size() != 6 | if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || | |||
|| !ParseNaturalNumber(fields[1], &line) | !ParseNaturalNumber(fields[2], &index) || | |||
|| !ParseNaturalNumber(fields[2], &index) | !ParseNaturalNumber(fields[3], &parent_process_id) || | |||
|| !ParseNaturalNumber(fields[3], &parent_process_id) | !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || | |||
|| !ParseNaturalNumber(fields[4], &write_handle_as_size_t) | !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { | |||
|| !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { | ||||
DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + | DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + | |||
GTEST_FLAG(internal_run_death_test)); | GTEST_FLAG_GET(internal_run_death_test)); | |||
} | } | |||
write_fd = GetStatusFileDescriptor(parent_process_id, | write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, | |||
write_handle_as_size_t, | ||||
event_handle_as_size_t); | event_handle_as_size_t); | |||
# elif GTEST_OS_FUCHSIA | #elif GTEST_OS_FUCHSIA | |||
if (fields.size() != 3 | if (fields.size() != 3 || !ParseNaturalNumber(fields[1], &line) || | |||
|| !ParseNaturalNumber(fields[1], &line) | !ParseNaturalNumber(fields[2], &index)) { | |||
|| !ParseNaturalNumber(fields[2], &index)) { | DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + | |||
DeathTestAbort("Bad --gtest_internal_run_death_test flag: " | GTEST_FLAG_GET(internal_run_death_test)); | |||
+ GTEST_FLAG(internal_run_death_test)); | ||||
} | } | |||
# else | #else | |||
if (fields.size() != 4 | if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || | |||
|| !ParseNaturalNumber(fields[1], &line) | !ParseNaturalNumber(fields[2], &index) || | |||
|| !ParseNaturalNumber(fields[2], &index) | !ParseNaturalNumber(fields[3], &write_fd)) { | |||
|| !ParseNaturalNumber(fields[3], &write_fd)) { | DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + | |||
DeathTestAbort("Bad --gtest_internal_run_death_test flag: " | GTEST_FLAG_GET(internal_run_death_test)); | |||
+ GTEST_FLAG(internal_run_death_test)); | ||||
} | } | |||
# endif // GTEST_OS_WINDOWS | #endif // GTEST_OS_WINDOWS | |||
return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); | return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); | |||
} | } | |||
} // namespace internal | } // namespace internal | |||
#endif // GTEST_HAS_DEATH_TEST | #endif // GTEST_HAS_DEATH_TEST | |||
} // namespace testing | } // namespace testing | |||
End of changes. 121 change blocks. | ||||
272 lines changed or deleted | 248 lines changed or added |