[libcxx-commits] [libcxx] [libc++][AIX] Support file offsets larger than 2GB in basic_filebuf on 32-bit (PR #215892)
Jake Egan via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Aug 13 12:48:18 PDT 2026
https://github.com/jakeegan updated https://github.com/llvm/llvm-project/pull/215892
>From 66dc8c61e1dc71c55d0b5209a25d5cf7487fd25a Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Wed, 12 Aug 2026 15:55:22 -0400
Subject: [PATCH 1/7] [libc++][AIX] Support file offsets larger than 2GB in
basic_filebuf on 32-bit
---
libcxx/include/fstream | 16 +++++++++++++++-
.../ifstream.members/offset_range.pass.cpp | 6 +++---
2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 0023191166c3b..f170a353ae52e 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -432,6 +432,7 @@ private:
_LIBCPP_HIDE_FROM_ABI static int __fseek(FILE* __file, pos_type __offset, int __whence);
_LIBCPP_HIDE_FROM_ABI static pos_type __ftell(FILE* __file);
+ _LIBCPP_HIDE_FROM_ABI static FILE* __fopen(const char* __name, const char* __mode);
_LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
@@ -779,6 +780,15 @@ const wchar_t* basic_filebuf<_CharT, _Traits>::__make_mdwstring(ios_base::openmo
}
# endif
+template <class _CharT, class _Traits>
+FILE* basic_filebuf<_CharT, _Traits>::__fopen(const char* __name, const char* __mode) {
+# if defined(_AIX) && !defined(__64BIT__)
+ return fopen64(__name, __mode);
+# else
+ return std::fopen(__name, __mode);
+# endif
+}
+
template <class _CharT, class _Traits>
basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char* __s, ios_base::openmode __mode) {
if (__file_)
@@ -787,7 +797,7 @@ basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char*
if (!__mdstr)
return nullptr;
- return __adopt_file(std::fopen(__s, __mdstr), __mode);
+ return __adopt_file(__fopen(__s, __mdstr), __mode);
}
template <class _CharT, class _Traits>
@@ -1067,6 +1077,8 @@ int basic_filebuf<_CharT, _Traits>::__fseek(FILE* __file, pos_type __offset, int
return _fseeki64(__file, __offset, __whence);
# elif _LIBCPP_LIBC_NEWLIB
return fseek(__file, __offset, __whence);
+# elif defined(_AIX) && !defined(__64BIT__)
+ return fseeko64(__file, __offset, __whence);
# else
return ::fseeko(__file, __offset, __whence);
# endif
@@ -1078,6 +1090,8 @@ typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>
return _ftelli64(__file);
# elif _LIBCPP_LIBC_NEWLIB
return ftell(__file);
+# elif defined(_AIX) && !defined(__64BIT__)
+ return ftello64(__file);
# else
return ftello(__file);
# endif
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp
index d176059ff87bf..7a11378541c1d 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp
@@ -18,10 +18,10 @@
//
// XFAIL: target={{i686|arm.*}}-{{.+}}-android{{.*}}
-// By default, off_t is typically a 32-bit integer on ARMv7 Linux systems and
-// 32-bit AIX, meaning it can represent file sizes up to 2GB (2^31 bytes) only.
+// By default, off_t is typically a 32-bit integer on ARMv7 Linux systems,
+// meaning it can represent file sizes up to 2GB (2^31 bytes) only.
//
-// UNSUPPORTED: target=armv7-unknown-linux-gnueabihf, target=powerpc-{{.+}}-aix{{.*}}
+// UNSUPPORTED: target=armv7-unknown-linux-gnueabihf
#include <fstream>
#include <iostream>
>From 1d78235e18f43900abaca22b64b7586e21b64ac1 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Wed, 12 Aug 2026 16:39:50 -0400
Subject: [PATCH 2/7] Fix formatting
---
libcxx/include/fstream | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index f170a353ae52e..a47b899857e4e 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -782,11 +782,11 @@ const wchar_t* basic_filebuf<_CharT, _Traits>::__make_mdwstring(ios_base::openmo
template <class _CharT, class _Traits>
FILE* basic_filebuf<_CharT, _Traits>::__fopen(const char* __name, const char* __mode) {
-# if defined(_AIX) && !defined(__64BIT__)
+# if defined(_AIX) && !defined(__64BIT__)
return fopen64(__name, __mode);
-# else
+# else
return std::fopen(__name, __mode);
-# endif
+# endif
}
template <class _CharT, class _Traits>
>From 388377c7de8650e4579f27d56ddfe5787eff68ee Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 15:00:07 -0400
Subject: [PATCH 3/7] Address some comments
---
libcxx/include/fstream | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index a47b899857e4e..948c3b59fd155 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -217,6 +217,14 @@ typedef basic_fstream<wchar_t> wfstream;
# pragma GCC system_header
# endif
+#if defined(_AIX)
+// On AIX, fopen64/fseeko64/ftello64 are not guaranteed to always be declared, so we declare them here.
+// They are not POSIX-reserved names, so we use __asm__ to guard them against a user #define.
+extern "C" FILE* __libcpp_aix_fopen64(const char*, const char*) __asm__("fopen64");
+extern "C" long long __libcpp_aix_ftello64(FILE*) __asm__("ftello64");
+extern "C" int __libcpp_aix_fseeko64(FILE*, long long, int) __asm__("fseeko64");
+#endif
+
_LIBCPP_PUSH_MACROS
# include <__undef_macros>
@@ -782,8 +790,8 @@ const wchar_t* basic_filebuf<_CharT, _Traits>::__make_mdwstring(ios_base::openmo
template <class _CharT, class _Traits>
FILE* basic_filebuf<_CharT, _Traits>::__fopen(const char* __name, const char* __mode) {
-# if defined(_AIX) && !defined(__64BIT__)
- return fopen64(__name, __mode);
+# if defined(_AIX)
+ return __libcpp_aix_fopen64(__name, __mode);
# else
return std::fopen(__name, __mode);
# endif
@@ -1077,8 +1085,8 @@ int basic_filebuf<_CharT, _Traits>::__fseek(FILE* __file, pos_type __offset, int
return _fseeki64(__file, __offset, __whence);
# elif _LIBCPP_LIBC_NEWLIB
return fseek(__file, __offset, __whence);
-# elif defined(_AIX) && !defined(__64BIT__)
- return fseeko64(__file, __offset, __whence);
+# elif defined(_AIX)
+ return __libcpp_aix_fseeko64(__file, __offset, __whence);
# else
return ::fseeko(__file, __offset, __whence);
# endif
@@ -1090,8 +1098,8 @@ typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>
return _ftelli64(__file);
# elif _LIBCPP_LIBC_NEWLIB
return ftell(__file);
-# elif defined(_AIX) && !defined(__64BIT__)
- return ftello64(__file);
+# elif defined(_AIX)
+ return __libcpp_aix_ftello64(__file);
# else
return ftello(__file);
# endif
>From befa51c9456fdf9cc99de26b31df78559c470274 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 15:02:53 -0400
Subject: [PATCH 4/7] Fix formatting
---
libcxx/include/fstream | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 948c3b59fd155..95d8b1212d54f 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -217,13 +217,13 @@ typedef basic_fstream<wchar_t> wfstream;
# pragma GCC system_header
# endif
-#if defined(_AIX)
+# if defined(_AIX)
// On AIX, fopen64/fseeko64/ftello64 are not guaranteed to always be declared, so we declare them here.
// They are not POSIX-reserved names, so we use __asm__ to guard them against a user #define.
extern "C" FILE* __libcpp_aix_fopen64(const char*, const char*) __asm__("fopen64");
extern "C" long long __libcpp_aix_ftello64(FILE*) __asm__("ftello64");
extern "C" int __libcpp_aix_fseeko64(FILE*, long long, int) __asm__("fseeko64");
-#endif
+# endif
_LIBCPP_PUSH_MACROS
# include <__undef_macros>
>From 515442a987ec1f83a3459daab75efd6d3d43c1bb Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 15:40:58 -0400
Subject: [PATCH 5/7] Try fixing glibc on Linux
---
libcxx/include/fstream | 28 +++++++++++--------
.../ifstream.members/offset_range.pass.cpp | 5 ----
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 95d8b1212d54f..0503c13f0d6d4 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -217,12 +217,18 @@ typedef basic_fstream<wchar_t> wfstream;
# pragma GCC system_header
# endif
-# if defined(_AIX)
-// On AIX, fopen64/fseeko64/ftello64 are not guaranteed to always be declared, so we declare them here.
+# if defined(_AIX) || ((defined(__linux__) && defined(__GLIBC__))
+# define _LIBCPP_HAS_LARGEFILE_API 1
+# else
+# define _LIBCPP_HAS_LARGEFILE_API 0
+# endif
+
+# if _LIBCPP_HAS_LARGEFILE_API
+// On AIX and glibc on Linux, fopen64/fseeko64/ftello64 are not guaranteed to always be declared, so we declare them here.
// They are not POSIX-reserved names, so we use __asm__ to guard them against a user #define.
-extern "C" FILE* __libcpp_aix_fopen64(const char*, const char*) __asm__("fopen64");
-extern "C" long long __libcpp_aix_ftello64(FILE*) __asm__("ftello64");
-extern "C" int __libcpp_aix_fseeko64(FILE*, long long, int) __asm__("fseeko64");
+extern "C" FILE* __libcpp_fopen64(const char*, const char*) __asm__("fopen64");
+extern "C" long long __libcpp_ftello64(FILE*) __asm__("ftello64");
+extern "C" int __libcpp_fseeko64(FILE*, long long, int) __asm__("fseeko64");
# endif
_LIBCPP_PUSH_MACROS
@@ -790,8 +796,8 @@ const wchar_t* basic_filebuf<_CharT, _Traits>::__make_mdwstring(ios_base::openmo
template <class _CharT, class _Traits>
FILE* basic_filebuf<_CharT, _Traits>::__fopen(const char* __name, const char* __mode) {
-# if defined(_AIX)
- return __libcpp_aix_fopen64(__name, __mode);
+# if _LIBCPP_HAS_LARGEFILE_API
+ return __libcpp_fopen64(__name, __mode);
# else
return std::fopen(__name, __mode);
# endif
@@ -1085,8 +1091,8 @@ int basic_filebuf<_CharT, _Traits>::__fseek(FILE* __file, pos_type __offset, int
return _fseeki64(__file, __offset, __whence);
# elif _LIBCPP_LIBC_NEWLIB
return fseek(__file, __offset, __whence);
-# elif defined(_AIX)
- return __libcpp_aix_fseeko64(__file, __offset, __whence);
+# elif _LIBCPP_HAS_LARGEFILE_API
+ return __libcpp_fseeko64(__file, __offset, __whence);
# else
return ::fseeko(__file, __offset, __whence);
# endif
@@ -1098,8 +1104,8 @@ typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>
return _ftelli64(__file);
# elif _LIBCPP_LIBC_NEWLIB
return ftell(__file);
-# elif defined(_AIX)
- return __libcpp_aix_ftello64(__file);
+# elif _LIBCPP_HAS_LARGEFILE_API
+ return __libcpp_ftello64(__file);
# else
return ftello(__file);
# endif
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp
index 7a11378541c1d..9a9824bd5287f 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/offset_range.pass.cpp
@@ -18,11 +18,6 @@
//
// XFAIL: target={{i686|arm.*}}-{{.+}}-android{{.*}}
-// By default, off_t is typically a 32-bit integer on ARMv7 Linux systems,
-// meaning it can represent file sizes up to 2GB (2^31 bytes) only.
-//
-// UNSUPPORTED: target=armv7-unknown-linux-gnueabihf
-
#include <fstream>
#include <iostream>
#include <cassert>
>From 87cb0e9221354871c0bf0b9fc77e2f957164c47c Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 15:44:58 -0400
Subject: [PATCH 6/7] Fix formatting
---
libcxx/include/fstream | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 0503c13f0d6d4..ca1fa9299b301 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -224,8 +224,8 @@ typedef basic_fstream<wchar_t> wfstream;
# endif
# if _LIBCPP_HAS_LARGEFILE_API
-// On AIX and glibc on Linux, fopen64/fseeko64/ftello64 are not guaranteed to always be declared, so we declare them here.
-// They are not POSIX-reserved names, so we use __asm__ to guard them against a user #define.
+// On AIX and glibc on Linux, fopen64/fseeko64/ftello64 are not guaranteed to always be declared, so we declare them
+// here. They are not POSIX-reserved names, so we use __asm__ to guard them against a user #define.
extern "C" FILE* __libcpp_fopen64(const char*, const char*) __asm__("fopen64");
extern "C" long long __libcpp_ftello64(FILE*) __asm__("ftello64");
extern "C" int __libcpp_fseeko64(FILE*, long long, int) __asm__("fseeko64");
>From 75df5b718048b47c200dcffa63166cad725d5d1d Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 15:47:31 -0400
Subject: [PATCH 7/7] Remove extra (
---
libcxx/include/fstream | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index ca1fa9299b301..d9bccae1f4aef 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -217,7 +217,7 @@ typedef basic_fstream<wchar_t> wfstream;
# pragma GCC system_header
# endif
-# if defined(_AIX) || ((defined(__linux__) && defined(__GLIBC__))
+# if defined(_AIX) || (defined(__linux__) && defined(__GLIBC__))
# define _LIBCPP_HAS_LARGEFILE_API 1
# else
# define _LIBCPP_HAS_LARGEFILE_API 0
More information about the libcxx-commits
mailing list