[libcxx-commits] [libcxx] 6c44cca - [libc++] Fix 64-bit file creation for Bionic and Windows

Ryan Prichard via libcxx-commits libcxx-commits at lists.llvm.org
Thu Dec 1 14:48:36 PST 2022


Author: Ryan Prichard
Date: 2022-12-01T14:48:20-08:00
New Revision: 6c44ccab43e99e1a48db917b4229ca651b303c3f

URL: https://github.com/llvm/llvm-project/commit/6c44ccab43e99e1a48db917b4229ca651b303c3f
DIFF: https://github.com/llvm/llvm-project/commit/6c44ccab43e99e1a48db917b4229ca651b303c3f.diff

LOG: [libc++] Fix 64-bit file creation for Bionic and Windows

Bionic didn't add fopen64 until API 24, but there's no meaningful
distinction between them with Bionic, so just use fopen instead.

On Windows, use _chsize_s instead of _chsize. _chsize uses a 32-bit
`long` size argument, while _chsize_s uses __int64 instead.

Factor out utils::{off64_t, fopen64, ftruncate64} for use within the
create_file function.

Reviewed By: ldionne, #libc, mstorsjo

Differential Revision: https://reviews.llvm.org/D137132

Added: 
    

Modified: 
    libcxx/test/support/filesystem_test_helper.h

Removed: 
    


################################################################################
diff  --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h
index 840e596b6a940..d09b37e057553 100644
--- a/libcxx/test/support/filesystem_test_helper.h
+++ b/libcxx/test/support/filesystem_test_helper.h
@@ -15,6 +15,7 @@
 
 #include <cassert>
 #include <chrono>
+#include <cstdint>
 #include <cstdio> // for printf
 #include <string>
 #include <system_error>
@@ -34,7 +35,6 @@
 namespace utils {
 #ifdef _WIN32
     inline int mkdir(const char* path, int mode) { (void)mode; return ::_mkdir(path); }
-    inline int ftruncate(int fd, off_t length) { return ::_chsize(fd, length); }
     inline int symlink(const char* oldname, const char* newname, bool is_dir) {
         DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
         if (CreateSymbolicLinkA(newname, oldname,
@@ -71,7 +71,6 @@ namespace utils {
     }
 #else
     using ::mkdir;
-    using ::ftruncate;
     inline int symlink(const char* oldname, const char* newname, bool is_dir) { (void)is_dir; return ::symlink(oldname, newname); }
     using ::link;
     using ::setenv;
@@ -99,6 +98,37 @@ namespace utils {
     }
 #endif
 
+    // N.B. libc might define some of the foo[64] identifiers using macros from
+    // foo64 -> foo or vice versa.
+#if defined(_WIN32)
+    using off64_t = int64_t;
+#elif defined(__MVS__) || defined(__LP64__)
+    using off64_t = ::off_t;
+#else
+    using ::off64_t;
+#endif
+
+    inline FILE* fopen64(const char* pathname, const char* mode) {
+        // Bionic does not distinguish between fopen and fopen64, but fopen64
+        // wasn't added until API 24.
+#if defined(_WIN32) || defined(__MVS__) || defined(__LP64__) || defined(__BIONIC__)
+        return ::fopen(pathname, mode);
+#else
+        return ::fopen64(pathname, mode);
+#endif
+    }
+
+    inline int ftruncate64(int fd, off64_t length) {
+#if defined(_WIN32)
+        // _chsize_s sets errno on failure and also returns the error number.
+        return ::_chsize_s(fd, length) ? -1 : 0;
+#elif defined(__MVS__) || defined(__LP64__)
+        return ::ftruncate(fd, length);
+#else
+        return ::ftruncate64(fd, length);
+#endif
+    }
+
     inline std::string getcwd() {
         // Assume that path lengths are not greater than this.
         // This should be fine for testing purposes.
@@ -185,22 +215,11 @@ struct scoped_test_env
     // off_t). On a 32-bit system this allows us to create a file larger than
     // 2GB.
     std::string create_file(fs::path filename_path, uintmax_t size = 0) {
-        std::string filename = filename_path.string();
-#if defined(__LP64__) || defined(_WIN32) || defined(__MVS__)
-        auto large_file_fopen = fopen;
-        auto large_file_ftruncate = utils::ftruncate;
-        using large_file_offset_t = off_t;
-#else
-        auto large_file_fopen = fopen64;
-        auto large_file_ftruncate = ftruncate64;
-        using large_file_offset_t = off64_t;
-#endif
-
-        filename = sanitize_path(std::move(filename));
+        std::string filename = sanitize_path(filename_path.string());
 
         if (size >
-            static_cast<typename std::make_unsigned<large_file_offset_t>::type>(
-                std::numeric_limits<large_file_offset_t>::max())) {
+            static_cast<typename std::make_unsigned<utils::off64_t>::type>(
+                std::numeric_limits<utils::off64_t>::max())) {
             fprintf(stderr, "create_file(%s, %ju) too large\n",
                     filename.c_str(), size);
             abort();
@@ -211,15 +230,15 @@ struct scoped_test_env
 #else
 #  define FOPEN_CLOEXEC_FLAG "e"
 #endif
-        FILE* file = large_file_fopen(filename.c_str(), "w" FOPEN_CLOEXEC_FLAG);
+        FILE* file = utils::fopen64(filename.c_str(), "w" FOPEN_CLOEXEC_FLAG);
         if (file == nullptr) {
             fprintf(stderr, "fopen %s failed: %s\n", filename.c_str(),
                     strerror(errno));
             abort();
         }
 
-        if (large_file_ftruncate(
-                fileno(file), static_cast<large_file_offset_t>(size)) == -1) {
+        if (utils::ftruncate64(
+                fileno(file), static_cast<utils::off64_t>(size)) == -1) {
             fprintf(stderr, "ftruncate %s %ju failed: %s\n", filename.c_str(),
                     size, strerror(errno));
             fclose(file);


        


More information about the libcxx-commits mailing list