summaryrefslogtreecommitdiffstats
path: root/utils/unittest/googletest/gtest-death-test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'utils/unittest/googletest/gtest-death-test.cc')
-rw-r--r--utils/unittest/googletest/gtest-death-test.cc849
1 files changed, 623 insertions, 226 deletions
diff --git a/utils/unittest/googletest/gtest-death-test.cc b/utils/unittest/googletest/gtest-death-test.cc
index 617e301..e4199de 100644
--- a/utils/unittest/googletest/gtest-death-test.cc
+++ b/utils/unittest/googletest/gtest-death-test.cc
@@ -27,17 +27,31 @@
// (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)
+// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
//
// This file implements death tests.
#include <gtest/gtest-death-test.h>
#include <gtest/internal/gtest-port.h>
-#ifdef GTEST_HAS_DEATH_TEST
+#if GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_MAC
+#include <crt_externs.h>
+#endif // GTEST_OS_MAC
+
#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#include <sys/wait.h>
+#endif // GTEST_OS_WINDOWS
+
#endif // GTEST_HAS_DEATH_TEST
#include <gtest/gtest-message.h>
@@ -48,9 +62,9 @@
// included, or there will be a compiler error. This trick is to
// prevent a user from accidentally including gtest-internal-inl.h in
// his code.
-#define GTEST_IMPLEMENTATION
+#define GTEST_IMPLEMENTATION_ 1
#include "gtest/internal/gtest-internal-inl.h"
-#undef GTEST_IMPLEMENTATION
+#undef GTEST_IMPLEMENTATION_
namespace testing {
@@ -68,6 +82,18 @@ GTEST_DEFINE_string_(
"\"fast\" (child process runs the death test immediately "
"after forking).");
+GTEST_DEFINE_bool_(
+ death_test_use_fork,
+ internal::BoolFromGTestEnv("death_test_use_fork", false),
+ "Instructs to use fork()/_exit() instead of clone() in death tests. "
+ "Ignored and always uses fork() on POSIX systems where clone() is not "
+ "implemented. Useful when running under valgrind or similar tools if "
+ "those do not support clone(). Valgrind 3.3.1 will just fail if "
+ "it sees an unsupported combination of clone() flags. "
+ "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 "
+ "most likely be removed.");
+
namespace internal {
GTEST_DEFINE_string_(
internal_run_death_test, "",
@@ -79,7 +105,7 @@ GTEST_DEFINE_string_(
"death test. FOR INTERNAL USE ONLY.");
} // namespace internal
-#ifdef GTEST_HAS_DEATH_TEST
+#if GTEST_HAS_DEATH_TEST
// ExitedWithCode constructor.
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
@@ -87,9 +113,14 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
// ExitedWithCode function-call operator.
bool ExitedWithCode::operator()(int exit_status) const {
+#if GTEST_OS_WINDOWS
+ return exit_status == exit_code_;
+#else
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+#endif // GTEST_OS_WINDOWS
}
+#if !GTEST_OS_WINDOWS
// KilledBySignal constructor.
KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
}
@@ -98,6 +129,7 @@ KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
bool KilledBySignal::operator()(int exit_status) const {
return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
}
+#endif // !GTEST_OS_WINDOWS
namespace internal {
@@ -107,6 +139,9 @@ namespace internal {
// specified by wait(2).
static String ExitSummary(int exit_code) {
Message m;
+#if GTEST_OS_WINDOWS
+ m << "Exited with exit status " << exit_code;
+#else
if (WIFEXITED(exit_code)) {
m << "Exited with exit status " << WEXITSTATUS(exit_code);
} else if (WIFSIGNALED(exit_code)) {
@@ -117,6 +152,7 @@ static String ExitSummary(int exit_code) {
m << " (core dumped)";
}
#endif
+#endif // GTEST_OS_WINDOWS
return m.GetString();
}
@@ -126,6 +162,7 @@ bool ExitedUnsuccessfully(int exit_status) {
return !ExitedWithCode(0)(exit_status);
}
+#if !GTEST_OS_WINDOWS
// 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
@@ -133,17 +170,14 @@ bool ExitedUnsuccessfully(int exit_status) {
static 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 << " ";
+ << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
if (thread_count == 0)
msg << "couldn't detect the number of threads.";
else
msg << "detected " << thread_count << " threads.";
return msg.GetString();
}
-
-// Static string containing a description of the outcome of the
-// last death test.
-static String last_death_test_message;
+#endif // !GTEST_OS_WINDOWS
// Flag characters for reporting a death test that did not die.
static const char kDeathTestLived = 'L';
@@ -159,29 +193,25 @@ static const char kDeathTestInternalError = 'I';
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
// Routine for aborting the program which is safe to call from an
-// exec-style death test child process, in which case the the error
+// exec-style death test child process, in which case the error
// 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 char* format, ...) {
- // 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-miniscule memory requirements.
+void DeathTestAbort(const 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();
- va_list args;
- va_start(args, format);
-
if (flag != NULL) {
- FILE* parent = fdopen(flag->status_fd, "w");
+ FILE* parent = posix::FDOpen(flag->write_fd(), "w");
fputc(kDeathTestInternalError, parent);
- vfprintf(parent, format, args);
- fclose(parent);
- va_end(args);
+ fprintf(parent, "%s", message.c_str());
+ fflush(parent);
_exit(1);
} else {
- vfprintf(stderr, format, args);
- va_end(args);
+ fprintf(stderr, "%s", message.c_str());
+ fflush(stderr);
abort();
}
}
@@ -190,11 +220,12 @@ void DeathTestAbort(const char* format, ...) {
// fails.
#define GTEST_DEATH_TEST_CHECK_(expression) \
do { \
- if (!(expression)) { \
- DeathTestAbort("CHECK failed: File %s, line %d: %s", \
- __FILE__, __LINE__, #expression); \
+ if (!::testing::internal::IsTrue(expression)) { \
+ DeathTestAbort(::testing::internal::String::Format( \
+ "CHECK failed: File %s, line %d: %s", \
+ __FILE__, __LINE__, #expression)); \
} \
- } while (0)
+ } while (::testing::internal::AlwaysFalse())
// 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
@@ -205,15 +236,46 @@ void DeathTestAbort(const char* format, ...) {
// something other than EINTR, DeathTestAbort is called.
#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
do { \
- int retval; \
+ int gtest_retval; \
do { \
- retval = (expression); \
- } while (retval == -1 && errno == EINTR); \
- if (retval == -1) { \
- DeathTestAbort("CHECK failed: File %s, line %d: %s != -1", \
- __FILE__, __LINE__, #expression); \
+ gtest_retval = (expression); \
+ } while (gtest_retval == -1 && errno == EINTR); \
+ if (gtest_retval == -1) { \
+ DeathTestAbort(::testing::internal::String::Format( \
+ "CHECK failed: File %s, line %d: %s != -1", \
+ __FILE__, __LINE__, #expression)); \
} \
- } while (0)
+ } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+String GetLastErrnoDescription() {
+ return String(errno == 0 ? "" : posix::StrError(errno));
+}
+
+// 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
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+ Message error;
+ char buffer[256];
+ int num_read;
+
+ do {
+ while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ if (num_read == 0) {
+ GTEST_LOG_(FATAL) << error.GetString();
+ } else {
+ const int last_error = errno;
+ GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+ << GetLastErrnoDescription() << " [" << last_error << "]";
+ }
+}
// Death test constructor. Increments the running death test count
// for the current test.
@@ -234,143 +296,146 @@ bool DeathTest::Create(const char* statement, const RE* regex,
}
const char* DeathTest::LastMessage() {
- return last_death_test_message.c_str();
+ return last_death_test_message_.c_str();
}
-// ForkingDeathTest provides implementations for most of the abstract
-// methods of the DeathTest interface. Only the AssumeRole method is
-// left undefined.
-class ForkingDeathTest : public DeathTest {
- public:
- ForkingDeathTest(const char* statement, const RE* regex);
+void DeathTest::set_last_death_test_message(const String& message) {
+ last_death_test_message_ = message;
+}
- // All of these virtual functions are inherited from DeathTest.
- virtual int Wait();
- virtual bool Passed(bool status_ok);
- virtual void Abort(AbortReason reason);
+String DeathTest::last_death_test_message_;
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
protected:
- void set_forked(bool forked) { forked_ = forked; }
- void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+ DeathTestImpl(const char* a_statement, const RE* a_regex)
+ : statement_(a_statement),
+ regex_(a_regex),
+ spawned_(false),
+ status_(-1),
+ outcome_(IN_PROGRESS),
+ read_fd_(-1),
+ write_fd_(-1) {}
+
+ // read_fd_ is expected to be closed and cleared by a derived class.
+ ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+ void Abort(AbortReason reason);
+ virtual bool Passed(bool status_ok);
+
+ 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_; }
+ void set_status(int a_status) { status_ = a_status; }
+ DeathTestOutcome outcome() const { return outcome_; }
+ void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+ int read_fd() const { return read_fd_; }
void set_read_fd(int fd) { read_fd_ = fd; }
+ int write_fd() const { return write_fd_; }
void set_write_fd(int fd) { write_fd_ = fd; }
+ // Called in the parent process only. Reads the result code of the death
+ // test child process via a pipe, interprets it to set the outcome_
+ // member, and closes read_fd_. Outputs diagnostics and terminates in
+ // case of unexpected codes.
+ void ReadAndInterpretStatusByte();
+
private:
- // The textual content of the code this object is testing.
+ // 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.
+ // 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_;
- // True if the death test successfully forked.
- bool forked_;
- // PID of child process during death test; 0 in the child process itself.
- pid_t child_pid_;
- // File descriptors for communicating the death test's status byte.
- int read_fd_; // Always -1 in the child process.
- int write_fd_; // Always -1 in the parent process.
+ // True if the death test child process has been successfully spawned.
+ bool spawned_;
// The exit status of the child process.
int status_;
// How the death test concluded.
DeathTestOutcome outcome_;
+ // Descriptor to the read end of the pipe to the child process. It is
+ // always -1 in the child process. The child keeps its write end of the
+ // pipe in write_fd_.
+ int read_fd_;
+ // Descriptor to the child's write end of the pipe to the parent process.
+ // It is always -1 in the parent process. The parent keeps its end of the
+ // pipe in read_fd_.
+ int write_fd_;
};
-// Constructs a ForkingDeathTest.
-ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex)
- : DeathTest(),
- statement_(statement),
- regex_(regex),
- forked_(false),
- child_pid_(-1),
- read_fd_(-1),
- write_fd_(-1),
- status_(-1),
- outcome_(IN_PROGRESS) {
-}
-
-// Reads an internal failure message from a file descriptor, then calls
-// LOG(FATAL) with that message. Called from a death test parent process
-// to read a failure message from the death test child process.
-static void FailFromInternalError(int fd) {
- Message error;
- char buffer[256];
- ssize_t num_read;
-
- do {
- while ((num_read = read(fd, buffer, 255)) > 0) {
- buffer[num_read] = '\0';
- error << buffer;
- }
- } while (num_read == -1 && errno == EINTR);
-
- // TODO(smcafee): Maybe just FAIL the test instead?
- if (num_read == 0) {
- GTEST_LOG_(FATAL, error);
- } else {
- GTEST_LOG_(FATAL,
- Message() << "Error while reading death test internal: "
- << strerror(errno) << " [" << errno << "]");
- }
-}
-
-// 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 ForkingDeathTest::Wait() {
- if (!forked_)
- return 0;
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_. Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+ char flag;
+ int bytes_read;
// The read() here blocks until data is available (signifying the
// failure of the death test) or until the pipe is closed (signifying
// its success), so it's okay to call this in the parent before
// the child process has exited.
- char flag;
- ssize_t bytes_read;
-
do {
- bytes_read = read(read_fd_, &flag, 1);
+ bytes_read = posix::Read(read_fd(), &flag, 1);
} while (bytes_read == -1 && errno == EINTR);
if (bytes_read == 0) {
- outcome_ = DIED;
+ set_outcome(DIED);
} else if (bytes_read == 1) {
switch (flag) {
case kDeathTestReturned:
- outcome_ = RETURNED;
+ set_outcome(RETURNED);
break;
case kDeathTestLived:
- outcome_ = LIVED;
+ set_outcome(LIVED);
break;
case kDeathTestInternalError:
- FailFromInternalError(read_fd_); // Does not return.
+ FailFromInternalError(read_fd()); // Does not return.
break;
default:
- GTEST_LOG_(FATAL,
- Message() << "Death test child process reported unexpected "
- << "status byte (" << static_cast<unsigned int>(flag)
- << ")");
+ GTEST_LOG_(FATAL) << "Death test child process reported "
+ << "unexpected status byte ("
+ << static_cast<unsigned int>(flag) << ")";
}
} else {
- GTEST_LOG_(FATAL,
- Message() << "Read from death test child process failed: "
- << strerror(errno));
+ GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+ << GetLastErrnoDescription();
}
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+ set_read_fd(-1);
+}
- GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_));
- GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_, 0));
- return status_;
+// 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
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+ // 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
+ // to the pipe, then exit.
+ const char status_ch =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd()));
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
}
// Assesses the success or failure of a death test, using both private
// members which have previously been set, and one argument:
//
// Private data members:
-// outcome: an enumeration describing how the death test
+// outcome: An enumeration describing how the death test
// concluded: DIED, LIVED, or RETURNED. The death test fails
-// in the latter two cases
-// status: the exit status of the child process, in the format
-// specified by wait(2)
-// regex: a regular expression object to be applied to
+// in the latter two cases.
+// status: The exit status of the child process. On *nix, it is in the
+// 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
+// fails if it does not match.
//
// Argument:
// status_ok: true if exit_status is acceptable in the context of
@@ -378,22 +443,18 @@ int ForkingDeathTest::Wait() {
//
// 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
-// reported. Also sets the static variable last_death_test_message.
-bool ForkingDeathTest::Passed(bool status_ok) {
- if (!forked_)
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+ if (!spawned())
return false;
-#if GTEST_HAS_GLOBAL_STRING
- const ::string error_message = GetCapturedStderr();
-#else
- const ::std::string error_message = GetCapturedStderr();
-#endif // GTEST_HAS_GLOBAL_STRING
+ const String error_message = GetCapturedStderr();
bool success = false;
Message buffer;
- buffer << "Death test: " << statement_ << "\n";
- switch (outcome_) {
+ buffer << "Death test: " << statement() << "\n";
+ switch (outcome()) {
case LIVED:
buffer << " Result: failed to die.\n"
<< " Error msg: " << error_message;
@@ -404,49 +465,271 @@ bool ForkingDeathTest::Passed(bool status_ok) {
break;
case DIED:
if (status_ok) {
- if (RE::PartialMatch(error_message, *regex_)) {
+ const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
+ if (matched) {
success = true;
} else {
buffer << " Result: died but not with expected error.\n"
- << " Expected: " << regex_->pattern() << "\n"
+ << " Expected: " << regex()->pattern() << "\n"
<< "Actual msg: " << error_message;
}
} else {
buffer << " Result: died but not with expected exit code:\n"
- << " " << ExitSummary(status_) << "\n";
+ << " " << ExitSummary(status()) << "\n";
}
break;
case IN_PROGRESS:
default:
- GTEST_LOG_(FATAL,
- "DeathTest::Passed somehow called before conclusion of test");
+ GTEST_LOG_(FATAL)
+ << "DeathTest::Passed somehow called before conclusion of test";
}
- last_death_test_message = buffer.GetString();
+ DeathTest::set_last_death_test_message(buffer.GetString());
return success;
}
-// 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 desriptor, then
-// calls _exit(1).
-void ForkingDeathTest::Abort(AbortReason reason) {
- // 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
- // to the pipe, then exit.
- const char flag =
- reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
- GTEST_DEATH_TEST_CHECK_SYSCALL_(write(write_fd_, &flag, 1));
- GTEST_DEATH_TEST_CHECK_SYSCALL_(close(write_fd_));
- _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+#if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes: Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+// ends of it.
+// 2. The parent starts the child and provides it with the information
+// necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+// using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+// this is done before step 3, the object's reference count goes down to
+// 0 and it is destroyed, preventing the child from acquiring it. The
+// parent now has to release it, or read operations on the read end of
+// the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+// any possible error messages) from the pipe, and its stderr and then
+// determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+ WindowsDeathTest(const char* statement,
+ const RE* regex,
+ const char* file,
+ int line)
+ : DeathTestImpl(statement, regex), file_(file), line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual TestRole AssumeRole();
+
+ 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_;
+ // Handle to the write end of the pipe to the child process.
+ AutoHandle write_handle_;
+ // Child process handle.
+ AutoHandle child_handle_;
+ // Event the child process uses to signal the parent that it has
+ // 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
+ // ReadFile() calls return when the child terminates.
+ AutoHandle event_handle_;
+};
+
+// 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 WindowsDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ // Wait until the child either signals that it has acquired the write end
+ // of the pipe or it dies.
+ const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+ switch (::WaitForMultipleObjects(2,
+ wait_handles,
+ FALSE, // Waits for any of the handles.
+ INFINITE)) {
+ case WAIT_OBJECT_0:
+ case WAIT_OBJECT_0 + 1:
+ break;
+ default:
+ GTEST_DEATH_TEST_CHECK_(false); // Should not get here.
+ }
+
+ // The child has acquired the write end of the pipe or exited.
+ // We release the handle on our side and continue.
+ write_handle_.Reset();
+ event_handle_.Reset();
+
+ ReadAndInterpretStatusByte();
+
+ // Waits for the child process to exit if it haven't already. This
+ // returns immediately if the child has already exited, regardless of
+ // whether previous calls to WaitForMultipleObjects synchronized on this
+ // handle or not.
+ GTEST_DEATH_TEST_CHECK_(
+ WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+ INFINITE));
+ DWORD status;
+ GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status)
+ != FALSE);
+ child_handle_.Reset();
+ set_status(static_cast<int>(status));
+ return this->status();
+}
+
+// The AssumeRole process for a Windows 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 WindowsDeathTest::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 != NULL) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ // WindowsDeathTest uses an anonymous pipe to communicate results of
+ // a death test.
+ SECURITY_ATTRIBUTES handles_are_inheritable = {
+ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ HANDLE read_handle, write_handle;
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+ 0) // Default buffer size.
+ != FALSE);
+ set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+ O_RDONLY));
+ 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 String filter_flag = String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX_, kFilterFlag,
+ info->test_case_name(),
+ info->name());
+ const String internal_flag = String::Format(
+ "--%s%s=%s|%d|%d|%u|%Iu|%Iu",
+ GTEST_FLAG_PREFIX_,
+ kInternalRunDeathTestFlag,
+ file_, line_,
+ death_test_index,
+ static_cast<unsigned int>(::GetCurrentProcessId()),
+ // size_t has the same with as pointers on both 32-bit and 64-bit
+ // Windows platforms.
+ // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+ reinterpret_cast<size_t>(write_handle),
+ 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));
+
+ String command_line = String::Format("%s %s \"%s\"",
+ ::GetCommandLineA(),
+ filter_flag.c_str(),
+ internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // The child process will share the standard handles with the parent.
+ STARTUPINFOA startup_info;
+ memset(&startup_info, 0, sizeof(STARTUPINFO));
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+ startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+ 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);
+ child_handle_.Reset(process_info.hProcess);
+ ::CloseHandle(process_info.hThread);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+#else // We are not on Windows.
+
+// 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);
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+
+ protected:
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
+ : DeathTestImpl(a_statement, a_regex),
+ 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
+// outcome data member.
+int ForkingDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ ReadAndInterpretStatusByte();
+
+ int status_value;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+ set_status(status_value);
+ return status_value;
}
// A concrete death test class that forks, then immediately runs the test
// in the child process.
class NoExecDeathTest : public ForkingDeathTest {
public:
- NoExecDeathTest(const char* statement, const RE* regex) :
- ForkingDeathTest(statement, regex) { }
+ NoExecDeathTest(const char* a_statement, const RE* a_regex) :
+ ForkingDeathTest(a_statement, a_regex) { }
virtual TestRole AssumeRole();
};
@@ -455,13 +738,13 @@ class NoExecDeathTest : public ForkingDeathTest {
DeathTest::TestRole NoExecDeathTest::AssumeRole() {
const size_t thread_count = GetThreadCount();
if (thread_count != 1) {
- GTEST_LOG_(WARNING, DeathTestThreadWarning(thread_count));
+ GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
}
int pipe_fd[2];
GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
- last_death_test_message = "";
+ DeathTest::set_last_death_test_message("");
CaptureStderr();
// When we fork the process below, the log file buffers are copied, but the
// file descriptors are shared. We flush all log files here so that closing
@@ -482,11 +765,14 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// concurrent writes to the log files. We capture stderr in the parent
// process and append the child process' output to a log.
LogToStderr();
+ // Event forwarding to the listeners of event listener API mush be shut
+ // down in death test subprocesses.
+ GetUnitTestImpl()->listeners()->SuppressEventForwarding();
return EXECUTE_TEST;
} else {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
set_read_fd(pipe_fd[0]);
- set_forked(true);
+ set_spawned(true);
return OVERSEE_TEST;
}
}
@@ -496,9 +782,9 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() {
// only this specific death test to be run.
class ExecDeathTest : public ForkingDeathTest {
public:
- ExecDeathTest(const char* statement, const RE* regex,
+ ExecDeathTest(const char* a_statement, const RE* a_regex,
const char* file, int line) :
- ForkingDeathTest(statement, regex), file_(file), line_(line) { }
+ ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
virtual TestRole AssumeRole();
private:
// The name of the file in which the death test is located.
@@ -513,15 +799,15 @@ class Arguments {
Arguments() {
args_.push_back(NULL);
}
+
~Arguments() {
- for (std::vector<char*>::iterator i = args_.begin();
- i + 1 != args_.end();
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
++i) {
free(*i);
}
}
void AddArgument(const char* argument) {
- args_.insert(args_.end() - 1, strdup(argument));
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
}
template <typename Str>
@@ -529,7 +815,7 @@ class Arguments {
for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
i != arguments.end();
++i) {
- args_.insert(args_.end() - 1, strdup(i->c_str()));
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
}
}
char* const* Argv() {
@@ -546,6 +832,20 @@ struct ExecDeathTestArgs {
int close_fd; // File descriptor to close; the read end of a pipe
};
+#if GTEST_OS_MAC
+inline char** GetEnviron() {
+ // When Google Test is built as a framework on MacOS X, the environ variable
+ // is unavailable. Apple's documentation (man environ) recommends using
+ // _NSGetEnviron() instead.
+ return *_NSGetEnviron();
+}
+#else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#endif // GTEST_OS_MAC
+
// The main function for a threadsafe-style death test child process.
// This function is called in a clone()-ed process and thus must avoid
// any potentially unsafe operations like malloc or libc functions.
@@ -560,8 +860,9 @@ static int ExecDeathTestChildMain(void* child_arg) {
UnitTest::GetInstance()->original_working_dir();
// We can safely call chdir() as it's a direct system call.
if (chdir(original_dir) != 0) {
- DeathTestAbort("chdir(\"%s\") failed: %s",
- original_dir, strerror(errno));
+ DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
+ original_dir,
+ GetLastErrnoDescription().c_str()));
return EXIT_FAILURE;
}
@@ -570,9 +871,11 @@ static int ExecDeathTestChildMain(void* child_arg) {
// unsafe. Since execve() doesn't search the PATH, the user must
// invoke the test program via a valid path that contains at least
// one path separator.
- execve(args->argv[0], args->argv, environ);
- DeathTestAbort("execve(%s, ...) in %s failed: %s",
- args->argv[0], original_dir, strerror(errno));
+ execve(args->argv[0], args->argv, GetEnviron());
+ DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
+ args->argv[0],
+ original_dir,
+ GetLastErrnoDescription().c_str()));
return EXIT_FAILURE;
}
@@ -581,12 +884,12 @@ static int ExecDeathTestChildMain(void* child_arg) {
// This could be accomplished more elegantly by a single recursive
// function, but we want to guard against the unlikely possibility of
// a smart compiler optimizing the recursion away.
-static bool StackLowerThanAddress(const void* ptr) {
+bool StackLowerThanAddress(const void* ptr) {
int dummy;
return &dummy < ptr;
}
-static bool StackGrowsDown() {
+bool StackGrowsDown() {
int dummy;
return StackLowerThanAddress(&dummy);
}
@@ -595,18 +898,36 @@ static bool StackGrowsDown() {
// that uses clone(2). It dies with an error message if anything goes
// wrong.
static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
- static const bool stack_grows_down = StackGrowsDown();
- const size_t stack_size = getpagesize();
- void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
- void* const stack_top =
- static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
ExecDeathTestArgs args = { argv, close_fd };
- const pid_t child_pid = clone(&ExecDeathTestChildMain, stack_top,
- SIGCHLD, &args);
+ pid_t child_pid = -1;
+
+#if GTEST_HAS_CLONE
+ const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+ if (!use_fork) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const size_t stack_size = 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,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+ void* const stack_top =
+ static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
+
+ child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+ GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+ }
+#else
+ const bool use_fork = true;
+#endif // GTEST_HAS_CLONE
+
+ if (use_fork && (child_pid = fork()) == 0) {
+ ExecDeathTestChildMain(&args);
+ _exit(0);
+ }
+
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
- GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
return child_pid;
}
@@ -622,7 +943,7 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
const int death_test_index = info->result()->death_test_count();
if (flag != NULL) {
- set_write_fd(flag->status_fd);
+ set_write_fd(flag->write_fd());
return EXECUTE_TEST;
}
@@ -634,19 +955,18 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
const String filter_flag =
String::Format("--%s%s=%s.%s",
- GTEST_FLAG_PREFIX, kFilterFlag,
+ GTEST_FLAG_PREFIX_, kFilterFlag,
info->test_case_name(), info->name());
const String internal_flag =
- String::Format("--%s%s=%s:%d:%d:%d",
- GTEST_FLAG_PREFIX, kInternalRunDeathTestFlag, file_, line_,
- death_test_index, pipe_fd[1]);
+ String::Format("--%s%s=%s|%d|%d|%d",
+ GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
+ file_, line_, death_test_index, pipe_fd[1]);
Arguments args;
args.AddArguments(GetArgvs());
- args.AddArgument("--logtostderr");
args.AddArgument(filter_flag.c_str());
args.AddArgument(internal_flag.c_str());
- last_death_test_message = "";
+ DeathTest::set_last_death_test_message("");
CaptureStderr();
// See the comment in NoExecDeathTest::AssumeRole for why the next line
@@ -657,10 +977,12 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
set_child_pid(child_pid);
set_read_fd(pipe_fd[0]);
- set_forked(true);
+ set_spawned(true);
return OVERSEE_TEST;
}
+#endif // !GTEST_OS_WINDOWS
+
// Creates a concrete DeathTest-derived class that depends on the
// --gtest_death_test_style flag, and sets the pointer pointed to
// by the "test" argument to its address. If the test should be
@@ -676,28 +998,36 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
->increment_death_test_count();
if (flag != NULL) {
- if (death_test_index > flag->index) {
- last_death_test_message = String::Format(
+ if (death_test_index > flag->index()) {
+ DeathTest::set_last_death_test_message(String::Format(
"Death test count (%d) somehow exceeded expected maximum (%d)",
- death_test_index, flag->index);
+ death_test_index, flag->index()));
return false;
}
- if (!(flag->file == file && flag->line == line &&
- flag->index == death_test_index)) {
+ if (!(flag->file() == file && flag->line() == line &&
+ flag->index() == death_test_index)) {
*test = NULL;
return true;
}
}
+#if GTEST_OS_WINDOWS
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new WindowsDeathTest(statement, regex, file, line);
+ }
+#else
if (GTEST_FLAG(death_test_style) == "threadsafe") {
*test = new ExecDeathTest(statement, regex, file, line);
} else if (GTEST_FLAG(death_test_style) == "fast") {
*test = new NoExecDeathTest(statement, regex);
- } else {
- last_death_test_message = String::Format(
+ }
+#endif // GTEST_OS_WINDOWS
+ else { // NOLINT - this is more readable than unbalanced brackets inside #if.
+ DeathTest::set_last_death_test_message(String::Format(
"Unknown death test style \"%s\" encountered",
- GTEST_FLAG(death_test_style).c_str());
+ GTEST_FLAG(death_test_style).c_str()));
return false;
}
@@ -711,7 +1041,7 @@ static void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest) {
::std::vector< ::std::string> parsed;
::std::string::size_type pos = 0;
- while (true) {
+ while (::testing::internal::AlwaysTrue()) {
const ::std::string::size_type colon = str.find(delimiter, pos);
if (colon == ::std::string::npos) {
parsed.push_back(str.substr(pos));
@@ -724,25 +1054,71 @@ static void SplitString(const ::std::string& str, char delimiter,
dest->swap(parsed);
}
-// Attempts to parse a string into a positive integer. Returns true
-// if that is possible. GTEST_HAS_DEATH_TEST implies that we have
-// ::std::string, so we can use it here.
-static bool ParsePositiveInt(const ::std::string& str, int* number) {
- // Fail fast if the given string does not begin with a digit;
- // this bypasses strtol's "optional leading whitespace and plus
- // or minus sign" semantics, which are undesirable here.
- if (str.empty() || !isdigit(str[0])) {
- return false;
+#if GTEST_OS_WINDOWS
+// 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,
+ size_t write_handle_as_size_t,
+ size_t event_handle_as_size_t) {
+ AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+ FALSE, // Non-inheritable.
+ parent_process_id));
+ if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+ DeathTestAbort(String::Format("Unable to open parent process %u",
+ parent_process_id));
}
- char* endptr;
- const long parsed = strtol(str.c_str(), &endptr, 10); // NOLINT
- if (*endptr == '\0' && parsed <= INT_MAX) {
- *number = static_cast<int>(parsed);
- return true;
- } else {
- return false;
+
+ // 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
+ // process. To obtain one accessible within the child, we need to use
+ // DuplicateHandle.
+ if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+ ::GetCurrentProcess(), &dup_write_handle,
+ 0x0, // Requested privileges ignored since
+ // DUPLICATE_SAME_ACCESS is used.
+ FALSE, // Request non-inheritable handler.
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort(String::Format(
+ "Unable to duplicate the pipe handle %Iu from the parent process %u",
+ write_handle_as_size_t, parent_process_id));
}
+
+ const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+ HANDLE dup_event_handle;
+
+ if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+ ::GetCurrentProcess(), &dup_event_handle,
+ 0x0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort(String::Format(
+ "Unable to duplicate the event handle %Iu from the parent process %u",
+ event_handle_as_size_t, parent_process_id));
+ }
+
+ const int write_fd =
+ ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+ if (write_fd == -1) {
+ DeathTestAbort(String::Format(
+ "Unable to convert pipe handle %Iu to a file descriptor",
+ write_handle_as_size_t));
+ }
+
+ // Signals the parent that the write end of the pipe has been acquired
+ // so the parent can release its own write end.
+ ::SetEvent(dup_event_handle);
+
+ return write_fd;
}
+#endif // GTEST_OS_WINDOWS
// Returns a newly created InternalRunDeathTestFlag object with fields
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
@@ -750,22 +1126,43 @@ static bool ParsePositiveInt(const ::std::string& str, int* number) {
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
- InternalRunDeathTestFlag* const internal_run_death_test_flag =
- new InternalRunDeathTestFlag;
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
// can use it here.
+ int line = -1;
+ int index = -1;
::std::vector< ::std::string> fields;
- SplitString(GTEST_FLAG(internal_run_death_test).c_str(), ':', &fields);
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+ int write_fd = -1;
+
+#if GTEST_OS_WINDOWS
+ unsigned int parent_process_id = 0;
+ size_t write_handle_as_size_t = 0;
+ size_t event_handle_as_size_t = 0;
+
+ if (fields.size() != 6
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &parent_process_id)
+ || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+ || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+ DeathTestAbort(String::Format(
+ "Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str()));
+ }
+ write_fd = GetStatusFileDescriptor(parent_process_id,
+ write_handle_as_size_t,
+ event_handle_as_size_t);
+#else
if (fields.size() != 4
- || !ParsePositiveInt(fields[1], &internal_run_death_test_flag->line)
- || !ParsePositiveInt(fields[2], &internal_run_death_test_flag->index)
- || !ParsePositiveInt(fields[3],
- &internal_run_death_test_flag->status_fd)) {
- DeathTestAbort("Bad --gtest_internal_run_death_test flag: %s",
- GTEST_FLAG(internal_run_death_test).c_str());
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &write_fd)) {
+ DeathTestAbort(String::Format(
+ "Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str()));
}
- internal_run_death_test_flag->file = fields[0].c_str();
- return internal_run_death_test_flag;
+#endif // GTEST_OS_WINDOWS
+ return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
}
} // namespace internal
OpenPOWER on IntegriCloud