summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorshiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925>2008-09-12 04:01:37 (GMT)
committershiqian <shiqian@861a406c-534a-0410-8894-cb66d6ee9925>2008-09-12 04:01:37 (GMT)
commit019d19af978f05b774407e0d46a3bda2c18c67c6 (patch)
tree8522f2db6e168ee4e829c2e7f2cf6dfbaaab30c7 /src
parent29d8235540f1983c3dbd53a23783530017be80e7 (diff)
downloadgoogletest-019d19af978f05b774407e0d46a3bda2c18c67c6.zip
googletest-019d19af978f05b774407e0d46a3bda2c18c67c6.tar.gz
googletest-019d19af978f05b774407e0d46a3bda2c18c67c6.tar.bz2
Improves thread-safe death tests by changing to the original working directory before they are executed; also fixes out-dated comments about death tests.
Diffstat (limited to 'src')
-rw-r--r--src/gtest-death-test.cc23
-rw-r--r--src/gtest-filepath.cc18
-rw-r--r--src/gtest-internal-inl.h21
-rw-r--r--src/gtest.cc6
4 files changed, 67 insertions, 1 deletions
diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc
index cb0d3cd..971c300 100644
--- a/src/gtest-death-test.cc
+++ b/src/gtest-death-test.cc
@@ -546,11 +546,32 @@ struct ExecDeathTestArgs {
};
// 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.
static int ExecDeathTestChildMain(void* child_arg) {
ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
GTEST_DEATH_TEST_CHECK_SYSCALL(close(args->close_fd));
+
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ 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));
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execve() as it's a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // 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 failed: %s", strerror(errno));
+ DeathTestAbort("execve(%s, ...) in %s failed: %s",
+ args->argv[0], original_dir, strerror(errno));
return EXIT_FAILURE;
}
diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc
index 3c32c70..2a5be8c 100644
--- a/src/gtest-filepath.cc
+++ b/src/gtest-filepath.cc
@@ -32,6 +32,8 @@
#include <gtest/internal/gtest-filepath.h>
#include <gtest/internal/gtest-port.h>
+#include <stdlib.h>
+
#ifdef _WIN32_WCE
#include <windows.h>
#elif defined(_WIN32)
@@ -40,6 +42,7 @@
#include <sys/stat.h>
#else
#include <sys/stat.h>
+#include <unistd.h>
#endif // _WIN32_WCE or _WIN32
#include <gtest/internal/gtest-string.h>
@@ -66,6 +69,21 @@ const char kPathSeparatorString[] = "/";
const char kCurrentDirectoryString[] = "./";
#endif // GTEST_OS_WINDOWS
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#ifdef _WIN32_WCE
+// Windows CE doesn't have a current directory, so we just return
+// something reasonable.
+ return FilePath(kCurrentDirectoryString);
+#elif defined(GTEST_OS_WINDOWS)
+ char cwd[_MAX_PATH + 1] = {};
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+ char cwd[PATH_MAX + 1] = {};
+ return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif
+}
+
// Returns a copy of the FilePath with the case-insensitive extension removed.
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
// FilePath("dir/file"). If a case-insensitive extension is not
diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h
index 6aafc7b..d488948 100644
--- a/src/gtest-internal-inl.h
+++ b/src/gtest-internal-inl.h
@@ -1003,6 +1003,21 @@ class UnitTestImpl : public TestPartResultReporterInterface {
void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
Test::TearDownTestCaseFunc tear_down_tc,
TestInfo * test_info) {
+ // In order to support thread-safe death tests, we need to
+ // remember the original working directory when the test program
+ // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
+ // the user may have changed the current directory before calling
+ // RUN_ALL_TESTS(). Therefore we capture the current directory in
+ // AddTestInfo(), which is called to register a TEST or TEST_F
+ // before main() is reached.
+ if (original_working_dir_.IsEmpty()) {
+ original_working_dir_.Set(FilePath::GetCurrentDir());
+ if (original_working_dir_.IsEmpty()) {
+ printf("%s\n", "Failed to get the current working directory.");
+ abort();
+ }
+ }
+
GetTestCase(test_info->test_case_name(),
test_info->test_case_comment(),
set_up_tc,
@@ -1083,9 +1098,15 @@ class UnitTestImpl : public TestPartResultReporterInterface {
#endif // GTEST_HAS_DEATH_TEST
private:
+ friend class ::testing::UnitTest;
+
// The UnitTest object that owns this implementation object.
UnitTest* const parent_;
+ // The working directory when the first TEST() or TEST_F() was
+ // executed.
+ internal::FilePath original_working_dir_;
+
// Points to (but doesn't own) the test part result reporter.
TestPartResultReporterInterface* test_part_result_reporter_;
diff --git a/src/gtest.cc b/src/gtest.cc
index 09f6bae..8ca6ac8 100644
--- a/src/gtest.cc
+++ b/src/gtest.cc
@@ -3211,6 +3211,12 @@ int UnitTest::Run() {
#endif // GTEST_OS_WINDOWS
}
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+ return impl_->original_working_dir_.c_str();
+}
+
// Returns the TestCase object for the test that's currently running,
// or NULL if no test is running.
// L < mutex_