[libcxx-commits] [libcxx] [libc++] Support file offsets larger than 2GB in basic_filebuf on 32-bit AIX and 32-bit glibc Linux (PR #215892)
Jake Egan via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Aug 13 17:58:27 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 01/10] [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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 06/10] 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 07/10] 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
>From 6d81cfc2547f17f6eb6a7da7d8c02328e5c57471 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 18:28:50 -0400
Subject: [PATCH 08/10] Address comments
---
libcxx/docs/ReleaseNotes/24.rst | 2 ++
libcxx/include/fstream | 22 ++++++++++------------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index e9a36ae94392f..a41347f544c50 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -51,6 +51,8 @@ Implemented Papers
Improvements and New Features
-----------------------------
+- ``basic_filebuf`` now supports files larger than 2GB on 32-bit AIX and 32-bit glib Linux targets.
+
Deprecations and Removals
-------------------------
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index d9bccae1f4aef..44da8ffa8730e 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -241,6 +241,14 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept;
# endif
+_LIBCPP_HIDE_FROM_ABI inline FILE* __fopen(const char* __name, const char* __mode) {
+# if _LIBCPP_HAS_LARGEFILE_API
+ return ::__libcpp_fopen64(__name, __mode);
+# else
+ return std::fopen(__name, __mode);
+# endif
+}
+
template <class _CharT, class _Traits>
class basic_filebuf : public basic_streambuf<_CharT, _Traits> {
public:
@@ -446,7 +454,6 @@ 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&);
@@ -794,15 +801,6 @@ 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 _LIBCPP_HAS_LARGEFILE_API
- return __libcpp_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_)
@@ -1092,7 +1090,7 @@ int basic_filebuf<_CharT, _Traits>::__fseek(FILE* __file, pos_type __offset, int
# elif _LIBCPP_LIBC_NEWLIB
return fseek(__file, __offset, __whence);
# elif _LIBCPP_HAS_LARGEFILE_API
- return __libcpp_fseeko64(__file, __offset, __whence);
+ return ::__libcpp_fseeko64(__file, __offset, __whence);
# else
return ::fseeko(__file, __offset, __whence);
# endif
@@ -1105,7 +1103,7 @@ typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>
# elif _LIBCPP_LIBC_NEWLIB
return ftell(__file);
# elif _LIBCPP_HAS_LARGEFILE_API
- return __libcpp_ftello64(__file);
+ return ::__libcpp_ftello64(__file);
# else
return ftello(__file);
# endif
>From e9dedb87af50c0bc5a15d06ef4ca89f8887a6b31 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 18:37:07 -0400
Subject: [PATCH 09/10] typo fix
---
libcxx/docs/ReleaseNotes/24.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/docs/ReleaseNotes/24.rst b/libcxx/docs/ReleaseNotes/24.rst
index a41347f544c50..b8b3777201540 100644
--- a/libcxx/docs/ReleaseNotes/24.rst
+++ b/libcxx/docs/ReleaseNotes/24.rst
@@ -51,7 +51,7 @@ Implemented Papers
Improvements and New Features
-----------------------------
-- ``basic_filebuf`` now supports files larger than 2GB on 32-bit AIX and 32-bit glib Linux targets.
+- ``basic_filebuf`` now supports files larger than 2GB on 32-bit AIX and 32-bit glibc Linux targets.
Deprecations and Removals
-------------------------
>From 982c0bd1ce5c60db8be199938f6d0dde1818e2fd Mon Sep 17 00:00:00 2001
From: Jake Egan <Jake.egan at ibm.com>
Date: Thu, 13 Aug 2026 20:58:14 -0400
Subject: [PATCH 10/10] Add std::
Co-authored-by: Hubert Tong <hubert.reinterpretcast at gmail.com>
---
libcxx/include/fstream | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 44da8ffa8730e..adc7c11ded91d 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -809,7 +809,7 @@ basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::open(const char*
if (!__mdstr)
return nullptr;
- return __adopt_file(__fopen(__s, __mdstr), __mode);
+ return __adopt_file(std::__fopen(__s, __mdstr), __mode);
}
template <class _CharT, class _Traits>
More information about the libcxx-commits
mailing list