gtest-death-test.cc [plain text]
#include <gtest/gtest-death-test.h>
#include <gtest/internal/gtest-port.h>
#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>
#include <gtest/internal/gtest-string.h>
#define GTEST_IMPLEMENTATION_ 1
#include "gtest/internal/gtest-internal-inl.h"
#undef GTEST_IMPLEMENTATION_
namespace testing {
static const char kDefaultDeathTestStyle[] = "fast";
GTEST_DEFINE_string_(
death_test_style,
internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
"Indicates how to run a death test in a forked child process: "
"\"threadsafe\" (child process re-executes the test binary "
"from the beginning, running only the specific death test) or "
"\"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, "",
"Indicates the file, line number, temporal index of "
"the single death test to run, and a file descriptor to "
"which a success code may be sent, all separated by "
"colons. This flag is specified if and only if the current "
"process is a sub-process launched for running a thread-safe "
"death test. FOR INTERNAL USE ONLY.");
}
#if GTEST_HAS_DEATH_TEST
ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
}
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::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 {
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)) {
m << "Terminated by signal " << WTERMSIG(exit_code);
}
#ifdef WCOREDUMP
if (WCOREDUMP(exit_code)) {
m << " (core dumped)";
}
#endif
#endif // GTEST_OS_WINDOWS
return m.GetString();
}
bool ExitedUnsuccessfully(int exit_status) {
return !ExitedWithCode(0)(exit_status);
}
#if !GTEST_OS_WINDOWS
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_ << " ";
if (thread_count == 0)
msg << "couldn't detect the number of threads.";
else
msg << "detected " << thread_count << " threads.";
return msg.GetString();
}
#endif // !GTEST_OS_WINDOWS
static const char kDeathTestLived = 'L';
static const char kDeathTestReturned = 'R';
static const char kDeathTestInternalError = 'I';
enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
void DeathTestAbort(const String& message) {
const InternalRunDeathTestFlag* const flag =
GetUnitTestImpl()->internal_run_death_test_flag();
if (flag != NULL) {
FILE* parent = posix::FDOpen(flag->write_fd(), "w");
fputc(kDeathTestInternalError, parent);
fprintf(parent, "%s", message.c_str());
fflush(parent);
_exit(1);
} else {
fprintf(stderr, "%s", message.c_str());
fflush(stderr);
abort();
}
}
#define GTEST_DEATH_TEST_CHECK_(expression) \
do { \
if (!::testing::internal::IsTrue(expression)) { \
DeathTestAbort(::testing::internal::String::Format( \
"CHECK failed: File %s, line %d: %s", \
__FILE__, __LINE__, #expression)); \
} \
} while (::testing::internal::AlwaysFalse())
#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
do { \
int gtest_retval; \
do { \
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 (::testing::internal::AlwaysFalse())
String GetLastErrnoDescription() {
return String(errno == 0 ? "" : posix::StrError(errno));
}
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 << "]";
}
}
DeathTest::DeathTest() {
TestInfo* const info = GetUnitTestImpl()->current_test_info();
if (info == NULL) {
DeathTestAbort("Cannot run a death test outside of a TEST or "
"TEST_F construct");
}
}
bool DeathTest::Create(const char* statement, const RE* regex,
const char* file, int line, DeathTest** test) {
return GetUnitTestImpl()->death_test_factory()->Create(
statement, regex, file, line, test);
}
const char* DeathTest::LastMessage() {
return last_death_test_message_.c_str();
}
void DeathTest::set_last_death_test_message(const String& message) {
last_death_test_message_ = message;
}
String DeathTest::last_death_test_message_;
class DeathTestImpl : public DeathTest {
protected:
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) {}
~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; }
void ReadAndInterpretStatusByte();
private:
const char* const statement_;
const RE* const regex_;
bool spawned_;
int status_;
DeathTestOutcome outcome_;
int read_fd_;
int write_fd_;
};
void DeathTestImpl::ReadAndInterpretStatusByte() {
char flag;
int bytes_read;
do {
bytes_read = posix::Read(read_fd(), &flag, 1);
} while (bytes_read == -1 && errno == EINTR);
if (bytes_read == 0) {
set_outcome(DIED);
} else if (bytes_read == 1) {
switch (flag) {
case kDeathTestReturned:
set_outcome(RETURNED);
break;
case kDeathTestLived:
set_outcome(LIVED);
break;
case kDeathTestInternalError:
FailFromInternalError(read_fd()); break;
default:
GTEST_LOG_(FATAL) << "Death test child process reported "
<< "unexpected status byte ("
<< static_cast<unsigned int>(flag) << ")";
}
} else {
GTEST_LOG_(FATAL) << "Read from death test child process failed: "
<< GetLastErrnoDescription();
}
GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
set_read_fd(-1);
}
void DeathTestImpl::Abort(AbortReason reason) {
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); }
bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned())
return false;
const String error_message = GetCapturedStderr();
bool success = false;
Message buffer;
buffer << "Death test: " << statement() << "\n";
switch (outcome()) {
case LIVED:
buffer << " Result: failed to die.\n"
<< " Error msg: " << error_message;
break;
case RETURNED:
buffer << " Result: illegal return in test statement.\n"
<< " Error msg: " << error_message;
break;
case DIED:
if (status_ok) {
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"
<< "Actual msg: " << error_message;
}
} else {
buffer << " Result: died but not with expected exit code:\n"
<< " " << ExitSummary(status()) << "\n";
}
break;
case IN_PROGRESS:
default:
GTEST_LOG_(FATAL)
<< "DeathTest::Passed somehow called before conclusion of test";
}
DeathTest::set_last_death_test_message(buffer.GetString());
return success;
}
#if GTEST_OS_WINDOWS
class WindowsDeathTest : public DeathTestImpl {
public:
WindowsDeathTest(const char* statement,
const RE* regex,
const char* file,
int line)
: DeathTestImpl(statement, regex), file_(file), line_(line) {}
virtual int Wait();
virtual TestRole AssumeRole();
private:
const char* const file_;
const int line_;
AutoHandle write_handle_;
AutoHandle child_handle_;
AutoHandle event_handle_;
};
int WindowsDeathTest::Wait() {
if (!spawned())
return 0;
const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
switch (::WaitForMultipleObjects(2,
wait_handles,
FALSE, INFINITE)) {
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
break;
default:
GTEST_DEATH_TEST_CHECK_(false); }
write_handle_.Reset();
event_handle_.Reset();
ReadAndInterpretStatusByte();
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();
}
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) {
set_write_fd(flag->write_fd());
return EXECUTE_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) != 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, FALSE, NULL)); 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()),
reinterpret_cast<size_t>(write_handle),
reinterpret_cast<size_t>(event_handle_.Get()));
char executable_path[_MAX_PATH + 1]; 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();
FlushInfoLog();
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, NULL, TRUE, 0x0, NULL, 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.
class ForkingDeathTest : public DeathTestImpl {
public:
ForkingDeathTest(const char* statement, const RE* regex);
virtual int Wait();
protected:
void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
private:
pid_t child_pid_;
};
ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
: DeathTestImpl(a_statement, a_regex),
child_pid_(-1) {}
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;
}
class NoExecDeathTest : public ForkingDeathTest {
public:
NoExecDeathTest(const char* a_statement, const RE* a_regex) :
ForkingDeathTest(a_statement, a_regex) { }
virtual TestRole AssumeRole();
};
DeathTest::TestRole NoExecDeathTest::AssumeRole() {
const size_t thread_count = GetThreadCount();
if (thread_count != 1) {
GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
}
int pipe_fd[2];
GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
DeathTest::set_last_death_test_message("");
CaptureStderr();
FlushInfoLog();
const pid_t child_pid = fork();
GTEST_DEATH_TEST_CHECK_(child_pid != -1);
set_child_pid(child_pid);
if (child_pid == 0) {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
set_write_fd(pipe_fd[1]);
LogToStderr();
GetUnitTestImpl()->listeners()->SuppressEventForwarding();
return EXECUTE_TEST;
} else {
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
set_read_fd(pipe_fd[0]);
set_spawned(true);
return OVERSEE_TEST;
}
}
class ExecDeathTest : public ForkingDeathTest {
public:
ExecDeathTest(const char* a_statement, const RE* a_regex,
const char* file, int line) :
ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
virtual TestRole AssumeRole();
private:
const char* const file_;
const int line_;
};
class Arguments {
public:
Arguments() {
args_.push_back(NULL);
}
~Arguments() {
for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
++i) {
free(*i);
}
}
void AddArgument(const char* argument) {
args_.insert(args_.end() - 1, posix::StrDup(argument));
}
template <typename Str>
void AddArguments(const ::std::vector<Str>& arguments) {
for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
i != arguments.end();
++i) {
args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
}
}
char* const* Argv() {
return &args_[0];
}
private:
std::vector<char*> args_;
};
struct ExecDeathTestArgs {
char* const* argv; int close_fd; };
#if GTEST_OS_MAC
inline char** GetEnviron() {
return *_NSGetEnviron();
}
#else
extern "C" char** environ;
inline char** GetEnviron() { return environ; }
#endif // GTEST_OS_MAC
static int ExecDeathTestChildMain(void* child_arg) {
ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
const char* const original_dir =
UnitTest::GetInstance()->original_working_dir();
if (chdir(original_dir) != 0) {
DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
original_dir,
GetLastErrnoDescription().c_str()));
return EXIT_FAILURE;
}
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;
}
bool StackLowerThanAddress(const void* ptr) {
int dummy;
return &dummy < ptr;
}
bool StackGrowsDown() {
int dummy;
return StackLowerThanAddress(&dummy);
}
static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
ExecDeathTestArgs args = { argv, close_fd };
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();
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);
return child_pid;
}
DeathTest::TestRole ExecDeathTest::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) {
set_write_fd(flag->write_fd());
return EXECUTE_TEST;
}
int pipe_fd[2];
GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
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|%d",
GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
file_, line_, death_test_index, pipe_fd[1]);
Arguments args;
args.AddArguments(GetArgvs());
args.AddArgument(filter_flag.c_str());
args.AddArgument(internal_flag.c_str());
DeathTest::set_last_death_test_message("");
CaptureStderr();
FlushInfoLog();
const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
set_child_pid(child_pid);
set_read_fd(pipe_fd[0]);
set_spawned(true);
return OVERSEE_TEST;
}
#endif // !GTEST_OS_WINDOWS
bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
const char* file, int line,
DeathTest** test) {
UnitTestImpl* const impl = GetUnitTestImpl();
const InternalRunDeathTestFlag* const flag =
impl->internal_run_death_test_flag();
const int death_test_index = impl->current_test_info()
->increment_death_test_count();
if (flag != NULL) {
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()));
return false;
}
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);
}
#endif // GTEST_OS_WINDOWS
else { DeathTest::set_last_death_test_message(String::Format(
"Unknown death test style \"%s\" encountered",
GTEST_FLAG(death_test_style).c_str()));
return false;
}
return true;
}
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 (::testing::internal::AlwaysTrue()) {
const ::std::string::size_type colon = str.find(delimiter, pos);
if (colon == ::std::string::npos) {
parsed.push_back(str.substr(pos));
break;
} else {
parsed.push_back(str.substr(pos, colon - pos));
pos = colon + 1;
}
}
dest->swap(parsed);
}
#if GTEST_OS_WINDOWS
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, parent_process_id));
if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
DeathTestAbort(String::Format("Unable to open parent process %u",
parent_process_id));
}
GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
const HANDLE write_handle =
reinterpret_cast<HANDLE>(write_handle_as_size_t);
HANDLE dup_write_handle;
if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
::GetCurrentProcess(), &dup_write_handle,
0x0, FALSE, 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));
}
::SetEvent(dup_event_handle);
return write_fd;
}
#endif // GTEST_OS_WINDOWS
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
int line = -1;
int index = -1;
::std::vector< ::std::string> 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
|| !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()));
}
#endif // GTEST_OS_WINDOWS
return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
}
}
#endif // GTEST_HAS_DEATH_TEST
}