diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2023-07-06 17:10:41 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2023-07-12 21:04:13 +0100 |
commit | 2f6bbc9a7d9a62423c576e13dc46323fe16ba5aa (patch) | |
tree | db52364f1ac7727290c016d724bb0c24b60127f9 | |
parent | 519b29c9e53d110d165059faa8a300c74450235a (diff) | |
download | gcc-2f6bbc9a7d9a62423c576e13dc46323fe16ba5aa.zip gcc-2f6bbc9a7d9a62423c576e13dc46323fe16ba5aa.tar.gz gcc-2f6bbc9a7d9a62423c576e13dc46323fe16ba5aa.tar.bz2 |
libstdc++: Fix --enable-cstdio=stdio_pure [PR110574]
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.
-rw-r--r-- | libstdc++-v3/acinclude.m4 | 16 | ||||
-rw-r--r-- | libstdc++-v3/config.h.in | 3 | ||||
-rw-r--r-- | libstdc++-v3/config/io/basic_file_stdio.cc | 66 | ||||
-rwxr-xr-x | libstdc++-v3/configure | 66 |
4 files changed, 133 insertions, 18 deletions
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 823832f..b25378e 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -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 ]) diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index 91eca6e..1c2224c 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -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 diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc index 7de9d98..27c2ad2 100644 --- a/libstdc++-v3/config/io/basic_file_stdio.cc +++ b/libstdc++-v3/config/io/basic_file_stdio.cc @@ -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,21 +378,53 @@ _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 } int @@ -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; diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index c8d5508..36f217c 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -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' |