From f189e6412651022f1466c5768856adfb89c8f469 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 7 Feb 2025 21:10:03 -0500 Subject: Tests: Add cases covering our mkdtemp code paths * `cmSystemTools::MakeTempDirectory` is our own code. * `uv_fs_mkdtemp` requires patching to backport to platforms not supported by upstream libuv. --- Tests/CMakeLib/CMakeLists.txt | 1 + Tests/CMakeLib/testSystemTools.cxx | 23 +++++++++++++++++++ Tests/CMakeLib/testUVPatches.cxx | 46 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 Tests/CMakeLib/testUVPatches.cxx diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index dda1622..19794b8 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -33,6 +33,7 @@ set(CMakeLib_TESTS testFindPackageCommand.cxx testUVHandlePtr.cxx testUVJobServerClient.cxx + testUVPatches.cxx testUVProcessChain.cxx testUVRAII.cxx testUVStreambuf.cxx diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx index cb4fb6c..3d932a4 100644 --- a/Tests/CMakeLib/testSystemTools.cxx +++ b/Tests/CMakeLib/testSystemTools.cxx @@ -96,11 +96,34 @@ static bool testStrVersCmp() return true; } +static bool testMakeTempDirectory() +{ + std::cout << "testMakeTempDirectory()\n"; + + static std::string const kTemplate = "testMakeTempDirectory-XXXXXX"; + std::string tempDir = kTemplate; + cmsys::Status status = cmSystemTools::MakeTempDirectory(tempDir); + if (!status) { + std::cout << "cmSystemTools::MakeTempDirectory failed on \"" << tempDir + << "\": " << status.GetString() << '\n'; + return false; + } + if (!cmSystemTools::FileIsDirectory(tempDir)) { + std::cout << "cmSystemTools::MakeTempDirectory did not create \"" + << tempDir << '\n'; + return false; + } + cmSystemTools::RemoveADirectory(tempDir); + ASSERT_TRUE(tempDir != kTemplate); + return true; +} + int testSystemTools(int /*unused*/, char* /*unused*/[]) { return runTests({ testUpperCase, testVersionCompare, testStrVersCmp, + testMakeTempDirectory, }); } diff --git a/Tests/CMakeLib/testUVPatches.cxx b/Tests/CMakeLib/testUVPatches.cxx new file mode 100644 index 0000000..06f8d1f --- /dev/null +++ b/Tests/CMakeLib/testUVPatches.cxx @@ -0,0 +1,46 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include // IWYU pragma: keep + +#include + +#include + +#include "cmSystemTools.h" + +#include "testCommon.h" + +static bool test_uv_fs_mkdtemp() +{ + std::cout << "test_uv_fs_mkdtemp()\n"; + static std::string const kTemplate = "test-uv_fs_mkdtemp-XXXXXX"; + std::string tempDir; + uv_fs_t tempDirReq; + tempDirReq.data = &tempDir; + uv_loop_t* loop = uv_default_loop(); + int r = + uv_fs_mkdtemp(loop, &tempDirReq, kTemplate.c_str(), [](uv_fs_t* req) { + if (req->data && req->path) { + *static_cast(req->data) = req->path; + } + }); + ASSERT_EQUAL(r, 0); + uv_run(loop, UV_RUN_DEFAULT); + uv_fs_req_cleanup(&tempDirReq); + if (!cmSystemTools::FileIsDirectory(tempDir)) { + std::cout << "cmSystemTools::MakeTempDirectory did not create \"" + << tempDir << '\n'; + return false; + } + cmSystemTools::RemoveADirectory(tempDir); + ASSERT_TRUE(tempDir != kTemplate); + return true; +} + +int testUVPatches(int /*unused*/, char* /*unused*/[]) +{ + return runTests({ + test_uv_fs_mkdtemp, + }); +} -- cgit v0.12 From 4db9e1009d8a4aa3a46c9d35afaa265a8c2201a6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 7 Feb 2025 17:38:05 -0500 Subject: Solaris: Backport our mkdtemp code paths to SunOS 5.10 i386 `mkdtemp` is not available on this architecture until SunOS 5.11. Look up the symbol at runtime, and if missing, fall back to an approximate implementation. --- Source/CMakeLists.txt | 4 ++++ Source/cmSystemTools.cxx | 33 ++++++++++++++++++++++++++++++++- Utilities/cmlibuv/CMakeLists.txt | 4 ++++ Utilities/cmlibuv/src/unix/fs.c | 23 ++++++++++++++++++++--- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 745c38c..94fa62a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1030,6 +1030,10 @@ if(WIN32 AND NOT CYGWIN) list(APPEND _tools cmcldeps) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "SunOS" AND CMAKE_SYSTEM_VERSION STREQUAL "5.10" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "i386") + set_property(SOURCE cmSystemTools.cxx APPEND PROPERTY COMPILE_DEFINITIONS CMAKE_NO_MKDTEMP) +endif() + # Some atomic instructions are implemented using libatomic on some platforms. if(CMake_HAVE_CXX_ATOMIC_LIB) target_link_libraries(CMakeLib PUBLIC atomic) diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 065c4e7..8e9deb1 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -141,6 +141,14 @@ # include #endif +#if defined(CMAKE_BOOTSTRAP) && defined(__sun) && defined(__i386) +# define CMAKE_NO_MKDTEMP +#endif + +#ifdef CMAKE_NO_MKDTEMP +# include +#endif + #if defined(_MSC_VER) && _MSC_VER >= 1800 # define CM_WINDOWS_DEPRECATED_GetVersionEx #endif @@ -1369,6 +1377,29 @@ inline int Mkdir(char const* dir, mode_t const* mode) #endif } +#ifdef CMAKE_NO_MKDTEMP +namespace { +char* cm_mkdtemp_fallback(char* template_) +{ + if (mktemp(template_) == nullptr || mkdir(template_, 0700) != 0) { + return nullptr; + } + return template_; +} +using cm_mkdtemp_t = char* (*)(char*); +cm_mkdtemp_t const cm_mkdtemp = []() -> cm_mkdtemp_t { + cm_mkdtemp_t f = (cm_mkdtemp_t)dlsym(RTLD_DEFAULT, "mkdtemp"); + dlerror(); // Ignore/cleanup dlsym errors. + if (!f) { + f = cm_mkdtemp_fallback; + } + return f; +}(); +} +#else +# define cm_mkdtemp mkdtemp +#endif + cmsys::Status cmSystemTools::MakeTempDirectory(std::string& path, mode_t const* mode) { @@ -1422,7 +1453,7 @@ cmsys::Status cmSystemTools::MakeTempDirectory(char* path, mode_t const* mode) } return cmsys::Status::POSIX(EAGAIN); #else - if (mkdtemp(path)) { + if (cm_mkdtemp(path)) { if (mode) { chmod(path, *mode); } diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index c9b3a2c..8773e56 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -302,6 +302,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") endif() if(CMAKE_SYSTEM_VERSION STREQUAL "5.10") list(APPEND uv_defines SUNOS_NO_IFADDRS) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "i386") + list(APPEND uv_defines CMAKE_NO_MKDTEMP) + endif() endif() list(APPEND uv_sources src/unix/no-proctitle.c @@ -318,6 +321,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "HP-UX") ) list(APPEND uv_defines _XOPEN_SOURCE_EXTENDED + CMAKE_NO_MKDTEMP ) list(APPEND uv_sources src/unix/hpux.c diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c index e2db3ad..ce7076b 100644 --- a/Utilities/cmlibuv/src/unix/fs.c +++ b/Utilities/cmlibuv/src/unix/fs.c @@ -282,13 +282,30 @@ static ssize_t uv__fs_futime(uv_fs_t* req) { #endif } -#if (defined(__sun) || defined(__hpux)) && (_XOPEN_SOURCE < 600 || defined(CMAKE_BOOTSTRAP)) -static char* uv__mkdtemp(char *template) -{ +#if defined(CMAKE_BOOTSTRAP) && defined(__sun) && defined(__i386) +# define CMAKE_NO_MKDTEMP +#endif + +#if defined(CMAKE_NO_MKDTEMP) +static char* uv__mkdtemp_fallback(char *template) { if (!mktemp(template) || mkdir(template, 0700)) return NULL; return template; } +static char* (*uv__mkdtemp_f)(char*); +static void uv__mkdtemp_initonce(void) { + uv__mkdtemp_f = (char* (*)(char*)) dlsym(RTLD_DEFAULT, "mkdtemp"); + dlerror(); /* Ignore/cleanup dlsym errors. */ + if (uv__mkdtemp_f == NULL) { + uv__mkdtemp_f = uv__mkdtemp_fallback; + } +} +static char* uv__mkdtemp(char *template) +{ + static uv_once_t once = UV_ONCE_INIT; + uv_once(&once, uv__mkdtemp_initonce); + return uv__mkdtemp_f(template); +} #else #define uv__mkdtemp mkdtemp #endif -- cgit v0.12