diff options
author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-03-06 01:20:15 +0000 |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-03-06 01:20:15 +0000 |
commit | 4984c93490eeeb7d3d1979b30a39a21cad07cba5 (patch) | |
tree | ca3c2306a370dda3388a4cbd34d22331debaec87 /src | |
parent | 0af0709b02899f9177db55eba7929e65e5834b29 (diff) | |
download | googletest-4984c93490eeeb7d3d1979b30a39a21cad07cba5.tar.gz googletest-4984c93490eeeb7d3d1979b30a39a21cad07cba5.tar.bz2 googletest-4984c93490eeeb7d3d1979b30a39a21cad07cba5.zip |
Implements death tests on Windows (by Vlad Losev); enables POSIX regex on Mac and Cygwin; fixes build issue on some Linux versions due to PATH_MAX.
Diffstat (limited to 'src')
-rw-r--r-- | src/gtest-death-test.cc | 742 | ||||
-rw-r--r-- | src/gtest-filepath.cc | 1 | ||||
-rw-r--r-- | src/gtest-internal-inl.h | 80 | ||||
-rw-r--r-- | src/gtest-port.cc | 66 | ||||
-rw-r--r-- | src/gtest.cc | 38 |
5 files changed, 781 insertions, 146 deletions
diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 7bb36490..71b749b9 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -27,7 +27,7 @@ // (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@losev.com (Vlad Losev) // // This file implements death tests. @@ -36,8 +36,16 @@ #if GTEST_HAS_DEATH_TEST #include <errno.h> +#include <fcntl.h> #include <limits.h> #include <stdarg.h> + +#if GTEST_OS_WINDOWS +#include <windows.h> +#else +#include <sys/mman.h> +#endif // GTEST_OS_WINDOWS + #endif // GTEST_HAS_DEATH_TEST #include <gtest/gtest-message.h> @@ -98,9 +106,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) { } @@ -109,6 +122,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 { @@ -118,6 +132,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)) { @@ -128,6 +145,7 @@ static String ExitSummary(int exit_code) { m << " (core dumped)"; } #endif +#endif // GTEST_OS_WINDOWS return m.GetString(); } @@ -137,6 +155,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 @@ -151,10 +170,7 @@ static String DeathTestThreadWarning(size_t thread_count) { 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'; @@ -170,29 +186,33 @@ 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"); +// Suppress MSVC complaints about POSIX functions. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER + FILE* parent = fdopen(flag->status_fd(), "w"); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER 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(); } } @@ -202,8 +222,9 @@ void DeathTestAbort(const char* format, ...) { #define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!(expression)) { \ - DeathTestAbort("CHECK failed: File %s, line %d: %s", \ - __FILE__, __LINE__, #expression); \ + DeathTestAbort(::testing::internal::String::Format(\ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ } \ } while (0) @@ -216,16 +237,59 @@ 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) +// Returns the message describing the last system error, regardless of the +// platform. +String GetLastSystemErrorMessage() { +#if GTEST_OS_WINDOWS + const DWORD error_num = ::GetLastError(); + + if (error_num == NULL) + return String(""); + + char* message_ptr; + + ::FormatMessageA( + // The caller does not provide a buffer. The function will allocate one. + FORMAT_MESSAGE_ALLOCATE_BUFFER | + // The function must look up an error message in its system error + // message table. + FORMAT_MESSAGE_FROM_SYSTEM | + // Do not expand insert sequences in the message definition. + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, // Message source. Ignored in this call. + error_num, + 0x0, // Use system-default language. + reinterpret_cast<LPSTR>(&message_ptr), + 0, // Buffer size. Ignored in this call. + NULL); // Message arguments. Ignored in this call. + + const String message = message_ptr; + ::LocalFree(message_ptr); + return message; +#else + return errno == 0 ? String("") : String(strerror(errno)); +#endif // GTEST_OS_WINDOWS +} + +// TODO(vladl@google.com): Move the definition of FailFromInternalError +// here. +#if GTEST_OS_WINDOWS +static void FailFromInternalError(HANDLE handle); +#else +static void FailFromInternalError(int fd); +#endif // GTEST_OS_WINDOWS + // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { @@ -245,61 +309,393 @@ 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(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; } +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +// TODO(vladl@google.com): Merge this class with DeathTest in +// gtest-death-test-internal.h. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* statement, const RE* regex) + : statement_(statement), + regex_(regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS) {} + + 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 spawned) { spawned_ = spawned; } + int status() const { return status_; } + void set_status(int status) { status_ = status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; } + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // 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_; +}; + +// TODO(vladl@google.com): Move definition of DeathTestImpl::Passed() here. + +#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 void Abort(AbortReason reason); + 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 read end of the pipe to the child process. + // The child keeps its write end of the pipe in the status_handle_ + // field of its InternalRunDeathTestFlag class. + AutoHandle read_handle_; + // 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. +// TODO(vladl@google.com): Outcome classification logic is common with +// ForkingDeathTes::Wait(). Refactor it into a +// common function. +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(); + + // ReadFile() 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 or + // after the child process has exited. + char flag; + DWORD bytes_read; + GTEST_DEATH_TEST_CHECK_(::ReadFile(read_handle_.Get(), + &flag, + 1, + &bytes_read, + NULL) || + ::GetLastError() == ERROR_BROKEN_PIPE); + + 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_handle_.Get()); // Does not return. + break; + default: + GTEST_LOG_(FATAL, + Message() << "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: " + << GetLastSystemErrorMessage()); + } + read_handle_.Reset(); // Done with reading. + + // 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)); + child_handle_.Reset(); + set_status(static_cast<int>(status)); + return this->status(); +} + +// TODO(vladl@google.com): define a cross-platform way to write to +// status_fd to be used both here and in ForkingDeathTest::Abort(). +// +// Signals that the death test did not die as expected. This is called +// from the child process only. +void WindowsDeathTest::Abort(AbortReason reason) { + const InternalRunDeathTestFlag* const internal_flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + // 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; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER + GTEST_DEATH_TEST_CHECK_SYSCALL_(write(internal_flag->status_fd(), + &status_ch, 1)); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + + // The write handle will be closed when the child terminates in _exit(). + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// 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. + 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. + read_handle_.Reset(read_handle); + 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)); + 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 DeathTest { +class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); - virtual bool Passed(bool status_ok); virtual void Abort(AbortReason reason); protected: - void set_forked(bool forked) { forked_ = forked; } void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } void set_read_fd(int fd) { read_fd_ = fd; } void set_write_fd(int fd) { write_fd_ = fd; } private: - // The textual content of the code this object is testing. - const char* const statement_; - // The regular expression which test output must match. - 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. - // The exit status of the child process. - int status_; - // How the death test concluded. - DeathTestOutcome outcome_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex) - : DeathTest(), - statement_(statement), - regex_(regex), - forked_(false), + : DeathTestImpl(statement, regex), child_pid_(-1), read_fd_(-1), - write_fd_(-1), - status_(-1), - outcome_(IN_PROGRESS) { + write_fd_(-1) { } +#endif // GTEST_OS_WINDOWS + +// 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. +// TODO(vladl@google.com): Re-factor the code to merge common parts after +// the reading code is abstracted. +#if GTEST_OS_WINDOWS +static void FailFromInternalError(HANDLE handle) { + Message error; + char buffer[256]; -// 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. + bool read_succeeded = true; + DWORD bytes_read; + do { + // ERROR_BROKEN_PIPE arises when the other end of the pipe has been + // closed. This is a normal condition for us. + bytes_read = 0; + read_succeeded = ::ReadFile(handle, + buffer, + sizeof(buffer) - 1, + &bytes_read, + NULL) || ::GetLastError() == ERROR_BROKEN_PIPE; + buffer[bytes_read] = 0; + error << buffer; + } while (read_succeeded && bytes_read > 0); + + if (read_succeeded) { + GTEST_LOG_(FATAL, error); + } else { + const DWORD last_error = ::GetLastError(); + const String message = GetLastSystemErrorMessage(); + GTEST_LOG_(FATAL, + Message() << "Error while reading death test internal: " + << message << " [" << last_error << "]"); + } +} +#else static void FailFromInternalError(int fd) { Message error; char buffer[256]; @@ -312,21 +708,24 @@ static void FailFromInternalError(int fd) { } } while (num_read == -1 && errno == EINTR); - // TODO(smcafee): Maybe just FAIL the test instead? if (num_read == 0) { GTEST_LOG_(FATAL, error); } else { + const int last_error = errno; + const String message = GetLastSystemErrorMessage(); GTEST_LOG_(FATAL, Message() << "Error while reading death test internal: " - << strerror(errno) << " [" << errno << "]"); + << message << " [" << last_error << "]"); } } +#endif // GTEST_OS_WINDOWS +#if !GTEST_OS_WINDOWS // 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_) + if (!spawned()) return 0; // The read() here blocks until data is available (signifying the @@ -341,14 +740,14 @@ int ForkingDeathTest::Wait() { } 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. @@ -360,28 +759,34 @@ int ForkingDeathTest::Wait() { << ")"); } } else { + const String error_message = GetLastSystemErrorMessage(); GTEST_LOG_(FATAL, Message() << "Read from death test child process failed: " - << strerror(errno)); + << error_message); } GTEST_DEATH_TEST_CHECK_SYSCALL_(close(read_fd_)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_, 0)); - return status_; + int status; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0)); + set_status(status); + return status; } +#endif // !GTEST_OS_WINDOWS // 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 @@ -389,9 +794,9 @@ 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 @@ -403,8 +808,8 @@ bool ForkingDeathTest::Passed(bool status_ok) { 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; @@ -415,16 +820,16 @@ bool ForkingDeathTest::Passed(bool status_ok) { break; case DIED: if (status_ok) { - if (RE::PartialMatch(error_message, *regex_)) { + if (RE::PartialMatch(error_message, *regex())) { 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: @@ -433,13 +838,14 @@ bool ForkingDeathTest::Passed(bool status_ok) { "DeathTest::Passed somehow called before conclusion of test"); } - last_death_test_message = buffer.GetString(); + DeathTest::set_last_death_test_message(buffer.GetString()); return success; } +#if !GTEST_OS_WINDOWS // 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 +// Writes a status byte to the child's status file descriptor, then // calls _exit(1). void ForkingDeathTest::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if @@ -472,7 +878,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { 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 @@ -497,7 +903,7 @@ DeathTest::TestRole NoExecDeathTest::AssumeRole() { } 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; } } @@ -524,9 +930,9 @@ 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); } @@ -571,8 +977,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, + GetLastSystemErrorMessage().c_str())); return EXIT_FAILURE; } @@ -582,8 +989,10 @@ static int ExecDeathTestChildMain(void* child_arg) { // 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)); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastSystemErrorMessage().c_str())); return EXIT_FAILURE; } @@ -643,7 +1052,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->status_fd()); return EXECUTE_TEST; } @@ -658,16 +1067,15 @@ DeathTest::TestRole ExecDeathTest::AssumeRole() { 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 @@ -678,10 +1086,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 @@ -697,28 +1107,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; } @@ -728,6 +1146,8 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. +// TODO(vladl@google.com): Get rid of std::vector to be able to build on +// Visual C++ 7.1 with exceptions disabled. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; @@ -745,25 +1165,72 @@ 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 status_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 status_handle = + reinterpret_cast<HANDLE>(status_handle_as_size_t); + HANDLE dup_status_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(), status_handle, + ::GetCurrentProcess(), &dup_status_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", + status_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 status_fd = + ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_status_handle), + O_APPEND | O_TEXT); + if (status_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + status_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 status_fd; } +#endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if @@ -771,22 +1238,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 status_fd = -1; + +#if GTEST_OS_WINDOWS + unsigned int parent_process_id = 0; + size_t status_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], &status_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())); + } + status_fd = GetStatusFileDescriptor(parent_process_id, + status_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()); - } - internal_run_death_test_flag->file = fields[0].c_str(); - return internal_run_death_test_flag; + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &status_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, status_fd); } } // namespace internal diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index e5908012..32fd3bcb 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -48,6 +48,7 @@ #include <limits.h> #include <sys/stat.h> // NOLINT #include <unistd.h> // NOLINT +#include <climits> // Some Linux distributions define PATH_MAX here. #endif // _WIN32_WCE or _WIN32 #if GTEST_OS_WINDOWS diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index b1a5dbb1..eadcf95e 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -45,17 +45,20 @@ #error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ +#include <errno.h> #include <stddef.h> - -#include <gtest/internal/gtest-port.h> +#include <stdlib.h> // For strtoll/_strtoul64. #if GTEST_OS_WINDOWS -#include <windows.h> // NOLINT +#include <windows.h> // For DWORD. #endif // GTEST_OS_WINDOWS +#include <gtest/internal/gtest-port.h> #include <gtest/gtest.h> #include <gtest/gtest-spi.h> +#include <string> + namespace testing { // Declares the flags. @@ -1313,6 +1316,77 @@ bool MatchRegexAnywhere(const char* regex, const char* str); void ParseGoogleTestFlagsOnly(int* argc, char** argv); void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +String GetLastSystemErrorMessage(); + +#if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +#endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template <typename Integer> +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !isdigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. +#if GTEST_OS_WINDOWS + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); +#else + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); +#endif // GTEST_OS_WINDOWS + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast<Integer>(parsed); + if (parse_success && static_cast<BiggestConvertible>(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + } // namespace internal } // namespace testing diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 59a22308..aacb5e72 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -35,9 +35,9 @@ #include <stdlib.h> #include <stdio.h> -#if GTEST_HAS_DEATH_TEST -#include <regex.h> -#endif // GTEST_HAS_DEATH_TEST +#if !GTEST_OS_WINDOWS +#include <unistd.h> +#endif // GTEST_OS_WINDOWS #if GTEST_USES_SIMPLE_RE #include <string.h> @@ -63,6 +63,13 @@ namespace testing { namespace internal { +#if GTEST_OS_WINDOWS +// Microsoft does not provide a definition of STDERR_FILENO. +const int kStdErrFileno = 2; +#else +const int kStdErrFileno = STDERR_FILENO; +#endif // GTEST_OS_WINDOWS + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. @@ -105,7 +112,13 @@ void RE::Init(const char* regex) { // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. - is_valid_ = (regcomp(&partial_regex_, regex, REG_EXTENDED) == 0) && is_valid_; + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = (regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0) + && is_valid_; EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; @@ -379,11 +392,19 @@ void GTestLog(GTestLogSeverity severity, const char* file, severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg); if (severity == GTEST_FATAL) { + fflush(NULL); // abort() is not guaranteed to flush open file streams. abort(); } } -#if GTEST_HAS_DEATH_TEST +#if GTEST_HAS_STD_STRING + +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER // Defines the stderr capturer. @@ -391,16 +412,26 @@ class CapturedStderr { public: // The ctor redirects stderr to a temporary file. CapturedStderr() { - uncaptured_fd_ = dup(STDERR_FILENO); + uncaptured_fd_ = dup(kStdErrFileno); + +#if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, temp_file_path); + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + filename_ = temp_file_path; +#else // There's no guarantee that a test has write access to the // current directory, so we create the temporary file in the /tmp // directory instead. char name_template[] = "/tmp/captured_stderr.XXXXXX"; const int captured_fd = mkstemp(name_template); filename_ = name_template; +#endif // GTEST_OS_WINDOWS fflush(NULL); - dup2(captured_fd, STDERR_FILENO); + dup2(captured_fd, kStdErrFileno); close(captured_fd); } @@ -412,7 +443,7 @@ class CapturedStderr { void StopCapture() { // Restores the original stream. fflush(NULL); - dup2(uncaptured_fd_, STDERR_FILENO); + dup2(uncaptured_fd_, kStdErrFileno); close(uncaptured_fd_); uncaptured_fd_ = -1; } @@ -427,6 +458,10 @@ class CapturedStderr { ::std::string filename_; }; +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + static CapturedStderr* g_captured_stderr = NULL; // Returns the size (in bytes) of a file. @@ -436,8 +471,6 @@ static size_t GetFileSize(FILE * file) { } // Reads the entire content of a file as a string. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can -// use it here. static ::std::string ReadEntireFile(FILE * file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; @@ -473,9 +506,18 @@ void CaptureStderr() { // use it here. ::std::string GetCapturedStderr() { g_captured_stderr->StopCapture(); + +// Disables Microsoft deprecation warning for fopen and fclose. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4996) +#endif // _MSC_VER FILE* const file = fopen(g_captured_stderr->filename().c_str(), "r"); const ::std::string content = ReadEntireFile(file); fclose(file); +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER delete g_captured_stderr; g_captured_stderr = NULL; @@ -483,6 +525,10 @@ void CaptureStderr() { return content; } +#endif // GTEST_HAS_STD_STRING + +#if GTEST_HAS_DEATH_TEST + // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector<String> g_argvs; diff --git a/src/gtest.cc b/src/gtest.cc index e4f9d0f3..f86a2a35 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3300,17 +3300,43 @@ void UnitTest::RecordPropertyForCurrentTest(const char* key, int UnitTest::Run() { #if GTEST_OS_WINDOWS + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected.. + if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) { #if !defined(_WIN32_WCE) - // SetErrorMode doesn't exist on CE. - if (GTEST_FLAG(catch_exceptions)) { - // The user wants Google Test to catch exceptions thrown by the tests. - - // This lets fatal errors be handled by us, instead of causing pop-ups. + // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); - } #endif // _WIN32_WCE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); + + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. +#if _MSC_VER >= 1400 + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +#endif // _MSC_VER >= 1400 + } + __try { return impl_->RunAllTests(); } __except(internal::UnitTestOptions::GTestShouldProcessSEH( |