From 4ef92181501dac783a6597591e7c0ea97673f844 Mon Sep 17 00:00:00 2001 From: Emily Date: Sat, 13 Sep 2025 19:41:08 +0100 Subject: [PATCH 1/2] Move `CapturedStream` iOS temporary directory logic into `TempDir()` We can drop `EndsWithPathSeparator()` because `TempDir()` provides this as an API contract. We prefer `$TEST_TMPDIR` when set for consistency with other platforms. --- googletest/src/gtest-port.cc | 50 +----------------------------------- googletest/src/gtest.cc | 38 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 49 deletions(-) diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index 490dbb579..f9f2fb582 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -1054,16 +1054,6 @@ GTestLog::~GTestLog() { // this class (creat, dup, dup2, and close) GTEST_DISABLE_MSC_DEPRECATED_PUSH_() -namespace { - -#if defined(GTEST_OS_LINUX_ANDROID) || defined(GTEST_OS_IOS) -bool EndsWithPathSeparator(const std::string& path) { - return !path.empty() && path.back() == GTEST_PATH_SEP_[0]; -} -#endif - -} // namespace - // Object that captures an output stream (stdout/stderr). class CapturedStream { public: @@ -1088,46 +1078,8 @@ class CapturedStream { // directory, so we create the temporary file in a temporary directory. std::string name_template; -#ifdef GTEST_OS_LINUX_ANDROID - // Note: Android applications are expected to call the framework's - // Context.getExternalStorageDirectory() method through JNI to get - // the location of the world-writable SD Card directory. However, - // this requires a Context handle, which cannot be retrieved - // globally from native code. Doing so also precludes running the - // code as part of a regular standalone executable, which doesn't - // run in a Dalvik process (e.g. when running it through 'adb shell'). - // - // The location /data/local/tmp is directly accessible from native code. - // '/sdcard' and other variants cannot be relied on, as they are not - // guaranteed to be mounted, or may have a delay in mounting. - // - // However, prefer using the TMPDIR environment variable if set, as newer - // devices may have /data/local/tmp read-only. +#if defined(GTEST_OS_LINUX_ANDROID) || defined(GTEST_OS_IOS) name_template = TempDir(); - if (!EndsWithPathSeparator(name_template)) - name_template.push_back(GTEST_PATH_SEP_[0]); - -#elif defined(GTEST_OS_IOS) - char user_temp_dir[PATH_MAX + 1]; - - // Documented alternative to NSTemporaryDirectory() (for obtaining creating - // a temporary directory) at - // https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 - // - // _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not - // documented in the confstr() man page at - // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr - // but are still available, according to the WebKit patches at - // https://trac.webkit.org/changeset/262004/webkit - // https://trac.webkit.org/changeset/263705/webkit - // - // The confstr() implementation falls back to getenv("TMPDIR"). See - // https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.auto.html - ::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir)); - - name_template = user_temp_dir; - if (!EndsWithPathSeparator(name_template)) - name_template.push_back(GTEST_PATH_SEP_[0]); #else name_template = "/tmp/"; #endif diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index cd218c9b0..715980096 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -33,6 +33,7 @@ #include "gtest/gtest.h" #include +#include #include #include #include @@ -7051,7 +7052,44 @@ std::string TempDir() { #elif defined(GTEST_OS_WINDOWS) || defined(GTEST_OS_WINDOWS_MOBILE) return GetDirFromEnv({"TEST_TMPDIR", "TEMP"}, "\\temp\\", '\\'); #elif defined(GTEST_OS_LINUX_ANDROID) + // Note: Android applications are expected to call the framework's + // Context.getExternalStorageDirectory() method through JNI to get + // the location of the world-writable SD Card directory. However, + // this requires a Context handle, which cannot be retrieved + // globally from native code. Doing so also precludes running the + // code as part of a regular standalone executable, which doesn't + // run in a Dalvik process (e.g. when running it through 'adb shell'). + // + // The location /data/local/tmp is directly accessible from native code. + // '/sdcard' and other variants cannot be relied on, as they are not + // guaranteed to be mounted, or may have a delay in mounting. + // + // However, prefer using the TMPDIR environment variable if set, as newer + // devices may have /data/local/tmp read-only. return GetDirFromEnv({"TEST_TMPDIR", "TMPDIR"}, "/data/local/tmp/", '/'); +#elif defined(GTEST_OS_IOS) + char user_temp_dir[PATH_MAX + 1]; + + // Documented alternative to NSTemporaryDirectory() (for obtaining creating + // a temporary directory) at + // https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10 + // + // _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not + // documented in the confstr() man page at + // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr + // but are still available, according to the WebKit patches at + // https://trac.webkit.org/changeset/262004/webkit + // https://trac.webkit.org/changeset/263705/webkit + // + // The confstr() implementation falls back to getenv("TMPDIR"). See + // https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.auto.html + ::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir)); + + std::string temp_dir = user_temp_dir; + if (path.empty() || path.back() != GTEST_PATH_SEP_[0]) + temp_dir.push_back(GTEST_PATH_SEP_[0]); + + return GetDirFromEnv({"TEST_TMPDIR"}, temp_dir.c_str(), '/'); #else return GetDirFromEnv({"TEST_TMPDIR", "TMPDIR"}, "/tmp/", '/'); #endif From 7a60b1abe8be0a2790f7c7aebd2a065ecad60d3a Mon Sep 17 00:00:00 2001 From: Emily Date: Sat, 13 Sep 2025 19:41:08 +0100 Subject: [PATCH 2/2] =?UTF-8?q?Use=20`TempDir()`=20in=20`CapturedStream`?= =?UTF-8?q?=20on=20all=20non=E2=80=90Windows=20platforms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is more consistent and makes tests using output capture behave as expected in environments with custom values of `$TEST_TMPDIR` or `$TMPDIR`, including fixing them in ones where `/tmp` may not be accessible, such as sandboxed build environments on macOS. --- googletest/src/gtest-port.cc | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index f9f2fb582..7ada8a9b7 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -1076,13 +1076,7 @@ class CapturedStream { #else // There's no guarantee that a test has write access to the current // directory, so we create the temporary file in a temporary directory. - std::string name_template; - -#if defined(GTEST_OS_LINUX_ANDROID) || defined(GTEST_OS_IOS) - name_template = TempDir(); -#else - name_template = "/tmp/"; -#endif + std::string name_template = TempDir(); name_template.append("gtest_captured_stream.XXXXXX"); // mkstemp() modifies the string bytes in place, and does not go beyond the