Tested x86_64-linux (with --enable-cstdio=stdio_pure and without).
I intend to commit this next week.
This fixes most of the fstream failures seen with stdio_pure, although
there are still a few that fail (about half of them time out):
FAIL: 27_io/basic_filebuf/imbue/char/13171-2.cc execution test
FAIL: 27_io/basic_filebuf/seekoff/45628-2.cc execution test
FAIL: 27_io/basic_filebuf/seekoff/char/26777.cc execution test
FAIL: 27_io/basic_filebuf/seekoff/char/4.cc execution test
FAIL: 27_io/basic_filebuf/seekoff/wchar_t/4.cc execution test
FAIL: 27_io/basic_filebuf/sputbackc/char/1-io.cc execution test
FAIL: 27_io/basic_filebuf/underflow/char/10097.cc execution test
FAIL: 27_io/basic_filebuf/underflow/wchar_t/5.cc execution test
FAIL: 27_io/objects/wchar_t/12.cc execution test
-- >8 --
When configured with --enable-cstdio=stdio_pure we need to consistently
use fseek and not mix seeks on the file descriptor with reads and writes
on the FILE stream.
There are also a number of bugs related to error handling and return
values, because fread and fwrite return 0 on error, not -1, and fseek
returns 0 on success, not the file offset.
libstdc++-v3/ChangeLog:
PR libstdc++/110574
* acinclude.m4 (GLIBCXX_CHECK_LFS): Check for fseeko and ftello
and define _GLIBCXX_USE_FSEEKO_FTELLO.
* config.h.in: Regenerate.
* configure: Regenerate.
* config/io/basic_file_stdio.cc (xwrite) [_GLIBCXX_USE_STDIO_PURE]:
Check for fwrite error correctly.
(__basic_file<char>::xsgetn) [_GLIBCXX_USE_STDIO_PURE]: Check for
fread error correctly.
(get_file_offset): New function.
(__basic_file<char>::seekoff) [_GLIBCXX_USE_STDIO_PURE]: Use
fseeko if available. Use get_file_offset instead of return value
of fseek.
(__basic_file<char>::showmanyc): Use get_file_offset.
---
libstdc++-v3/acinclude.m4 | 16 ++++++
libstdc++-v3/config.h.in | 3 +
libstdc++-v3/config/io/basic_file_stdio.cc | 66 ++++++++++++++++------
libstdc++-v3/configure | 66 ++++++++++++++++++++++
4 files changed, 133 insertions(+), 18 deletions(-)
@@ -497,6 +497,22 @@ AC_DEFUN([GLIBCXX_CHECK_LFS], [
if test $glibcxx_cv_LFS = yes; then
AC_DEFINE(_GLIBCXX_USE_LFS, 1, [Define if LFS support is available.])
fi
+
+ AC_CACHE_CHECK([for fseeko and ftello], glibcxx_cv_posix_lfs, [
+ GCC_TRY_COMPILE_OR_LINK(
+ [#include <stdio.h>
+ ],
+ [FILE* fp;
+ fseeko(fp, 0, SEEK_CUR);
+ ftello(fp);
+ ],
+ [glibcxx_cv_posix_lfs=yes],
+ [glibcxx_cv_posix_lfs=no])
+ ])
+ if test $glibcxx_cv_posix_lfs = yes; then
+ AC_DEFINE(_GLIBCXX_USE_FSEEKO_FTELLO, 1, [Define if fseeko and ftello are available.])
+ fi
+
CXXFLAGS="$ac_save_CXXFLAGS"
AC_LANG_RESTORE
])
@@ -988,6 +988,9 @@
/* Define if fchmodat is available in <sys/stat.h>. */
#undef _GLIBCXX_USE_FCHMODAT
+/* Define if fseeko and ftello are available. */
+#undef _GLIBCXX_USE_FSEEKO_FTELLO
+
/* Defined if gettimeofday is available. */
#undef _GLIBCXX_USE_GETTIMEOFDAY
@@ -129,14 +129,15 @@ namespace
{
#ifdef _GLIBCXX_USE_STDIO_PURE
const std::streamsize __ret = fwrite(__s, 1, __nleft, __file);
+ if (__ret == 0 && ferror(__file))
+ break;
#else
const std::streamsize __ret = write(__fd, __s, __nleft);
-#endif
if (__ret == -1L && errno == EINTR)
continue;
if (__ret == -1L)
break;
-
+#endif
__nleft -= __ret;
if (__nleft == 0)
break;
@@ -330,13 +331,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__basic_file<char>::xsgetn(char* __s, streamsize __n)
{
streamsize __ret;
- do
#ifdef _GLIBCXX_USE_STDIO_PURE
- __ret = fread(__s, 1, __n, this->file());
+ __ret = fread(__s, 1, __n, this->file());
+ if (__ret == 0 && ferror(this->file()))
+ __ret = -1;
#else
+ do
__ret = read(this->fd(), __s, __n);
-#endif
while (__ret == -1L && errno == EINTR);
+#endif
return __ret;
}
@@ -375,20 +378,52 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
+ namespace
+ {
+ inline streamoff
+ get_file_offset(__basic_file<char>* __f)
+ {
+#ifdef _GLIBCXX_USE_STDIO_PURE
+# ifdef _GLIBCXX_USE_FSEEKO_FTELLO
+ return ftello(__f->file());
+# else
+ return ftell(__f->file());
+# endif
+#elif defined(_GLIBCXX_USE_LFS)
+ return lseek64(__f->fd(), 0, (int)ios_base::cur);
+#else
+ return lseek(__f->fd(), 0, (int)ios_base::cur);
+#endif
+ }
+ }
+
streamoff
__basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way) throw ()
{
-#ifdef _GLIBCXX_USE_LFS
+#ifdef _GLIBCXX_USE_STDIO_PURE
+#ifdef _GLIBCXX_USE_FSEEKO_FTELLO
+ if _GLIBCXX17_CONSTEXPR (sizeof(off_t) > sizeof(long))
+ {
+ if (fseeko(this->file(), __off, __way))
+ return -1;
+ }
+ else
+#endif
+ {
+ if (__off > numeric_limits<long>::max()
+ || __off < numeric_limits<long>::min())
+ return -1;
+ if (fseek(this->file(), __off, __way))
+ return -1;
+ }
+ return __way == ios_base::beg ? __off : std::get_file_offset(this);
+#elif defined(_GLIBCXX_USE_LFS)
return lseek64(this->fd(), __off, __way);
#else
if (__off > numeric_limits<off_t>::max()
- || __off < numeric_limits<off_t>::min())
+ || __off < numeric_limits<off_t>::min())
return -1L;
-#ifdef _GLIBCXX_USE_STDIO_PURE
- return fseek(this->file(), __off, __way);
-#else
return lseek(this->fd(), __off, __way);
-#endif
#endif
}
@@ -425,19 +460,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
const int __err = fstat64(this->fd(), &__buffer);
if (!__err && _GLIBCXX_ISREG(__buffer.st_mode))
{
- const streamoff __off = __buffer.st_size - lseek64(this->fd(), 0,
- ios_base::cur);
+ const streamoff __off = __buffer.st_size - std::get_file_offset(this);
return std::min(__off, streamoff(numeric_limits<streamsize>::max()));
}
#else
struct stat __buffer;
const int __err = fstat(this->fd(), &__buffer);
if (!__err && _GLIBCXX_ISREG(__buffer.st_mode))
-#ifdef _GLIBCXX_USE_STDIO_PURE
- return __buffer.st_size - fseek(this->file(), 0, ios_base::cur);
-#else
- return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur);
-#endif
+ return __buffer.st_size - std::get_file_offset(this);
#endif
#endif
return 0;
@@ -19940,6 +19940,72 @@ $as_echo "$glibcxx_cv_LFS" >&6; }
$as_echo "#define _GLIBCXX_USE_LFS 1" >>confdefs.h
fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fseeko and ftello" >&5
+$as_echo_n "checking for fseeko and ftello... " >&6; }
+if ${glibcxx_cv_posix_lfs+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test x$gcc_no_link = xyes; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+
+int
+main ()
+{
+FILE* fp;
+ fseeko(fp, 0, SEEK_CUR);
+ ftello(fp);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ glibcxx_cv_posix_lfs=yes
+else
+ glibcxx_cv_posix_lfs=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ if test x$gcc_no_link = xyes; then
+ as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5
+fi
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+
+int
+main ()
+{
+FILE* fp;
+ fseeko(fp, 0, SEEK_CUR);
+ ftello(fp);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ glibcxx_cv_posix_lfs=yes
+else
+ glibcxx_cv_posix_lfs=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_posix_lfs" >&5
+$as_echo "$glibcxx_cv_posix_lfs" >&6; }
+ if test $glibcxx_cv_posix_lfs = yes; then
+
+$as_echo "#define _GLIBCXX_USE_FSEEKO_FTELLO 1" >>confdefs.h
+
+ fi
+
CXXFLAGS="$ac_save_CXXFLAGS"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'