]> Savannah Git Hosting - gnulib.git/commitdiff
ftello: Work around bug in macOS >= 10.15.
authorBruno Haible <bruno@clisp.org>
Sun, 21 Mar 2021 02:46:05 +0000 (03:46 +0100)
committerBruno Haible <bruno@clisp.org>
Sun, 21 Mar 2021 02:46:05 +0000 (03:46 +0100)
Reported by Martin Storsjö <martin@martin.st> in
<https://lists.gnu.org/archive/html/bug-gnulib/2020-12/msg00002.html>.

* m4/ungetc.m4 (gl_FUNC_UNGETC_WORKS): On macOS, don't define
FUNC_UNGETC_BROKEN. Instead, set gl_ftello_broken_after_ungetc to yes.
* m4/ftello.m4 (gl_FUNC_FTELLO): Invoke gl_FUNC_UNGETC_WORKS, and
arrange to provide the workaround if ftello is broken after ungetc.
* lib/ftello.c: Include <errno.h>, intprops.h.
(ftello) [FTELLO_BROKEN_AFTER_UNGETC]: Implement from scratch.
* modules/ftello (Files): Add m4/ungetc.m4.
(Depends-on): Add intprops.
* doc/posix-functions/ftello.texi: Mention the macOS bug.

ChangeLog
doc/posix-functions/ftello.texi
lib/ftello.c
m4/ftello.m4
m4/ungetc.m4
modules/ftello

index 8f7cf2516262fefeb34959289651756811336e8f..77bf17513be4402a6a8d6c5206ea318c05c9480a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2021-03-20  Bruno Haible  <bruno@clisp.org>
+
+       ftello: Work around bug in macOS >= 10.15.
+       Reported by Martin Storsjö <martin@martin.st> in
+       <https://lists.gnu.org/archive/html/bug-gnulib/2020-12/msg00002.html>.
+       * m4/ungetc.m4 (gl_FUNC_UNGETC_WORKS): On macOS, don't define
+       FUNC_UNGETC_BROKEN. Instead, set gl_ftello_broken_after_ungetc to yes.
+       * m4/ftello.m4 (gl_FUNC_FTELLO): Invoke gl_FUNC_UNGETC_WORKS, and
+       arrange to provide the workaround if ftello is broken after ungetc.
+       * lib/ftello.c: Include <errno.h>, intprops.h.
+       (ftello) [FTELLO_BROKEN_AFTER_UNGETC]: Implement from scratch.
+       * modules/ftello (Files): Add m4/ungetc.m4.
+       (Depends-on): Add intprops.
+       * doc/posix-functions/ftello.texi: Mention the macOS bug.
+
 2021-03-20  Bruno Haible  <bruno@clisp.org>
 
        math C++ tests: Fix compilation error on macOS 11.2.
index 2561c5d65e83420da47f0a763a7f603edbbc6d13..eab591fca0508449cf439b24ce694c020f4b7a1c 100644 (file)
@@ -20,6 +20,11 @@ This function produces incorrect results after @code{putc} that followed a
 @code{getc} call that reached EOF on some platforms:
 Solaris 11 2010-11.
 @item
+This function, when invoked after @code{ungetc}, throws away the @code{ungetc}
+buffer, changes the stream's file position, and returns the wrong position on
+some platforms:
+macOS 10.15 and newer.
+@item
 This function fails on seekable stdin, stdout, and stderr: cygwin <= 1.5.24.
 @item
 On platforms where @code{off_t} is a 32-bit type, @code{ftello} does not work
index c5a4e0c22c7fb50b0db9cdf47bff07828d4aff97..da13694a032534b89b48d25b9d1dbbc35139c25c 100644 (file)
@@ -19,6 +19,9 @@
 /* Specification.  */
 #include <stdio.h>
 
+#include <errno.h>
+#include "intprops.h"
+
 /* Get lseek.  */
 #include <unistd.h>
 
@@ -40,13 +43,79 @@ ftello (FILE *fp)
 # endif
 #endif
 {
-#if LSEEK_PIPE_BROKEN
+#if FTELLO_BROKEN_AFTER_UNGETC /* macOS >= 10.15 */
+  /* The system's ftello() is completely broken, because it calls __sflush,
+     which makes side effects on the stream.  */
+
+  /* Handle non-seekable files first.  */
+  if (fp->_file < 0 || fp->_seek == NULL)
+    {
+      errno = ESPIPE;
+      return -1;
+    }
+
+  /* Determine the current offset, ignoring buffered and pushed-back bytes.  */
+  off_t pos;
+
+  if (fp->_flags & __SOFF)
+    pos = fp->_offset;
+  else
+    {
+      pos = fp->_seek (fp->_cookie, 0, SEEK_CUR);
+      if (pos < 0)
+        return -1;
+      if (fp->_flags & __SOPT)
+        {
+          fp->_offset = pos;
+          fp->_flags |= __SOFF;
+        }
+    }
+
+  if (fp->_flags & __SRD)
+    {
+      /* Now consider buffered and pushed-back bytes from ungetc.  */
+      if (fp->_ub._base != NULL)
+        /* Considering the buffered bytes, we are at position
+             pos - fp->_ur.
+           Considering also the pushed-back bytes, we are at position
+             pos - fp->_ur - fp->_r.  */
+        pos = pos - fp->_ur - fp->_r;
+      else
+        /* Considering the buffered bytes, we are at position
+             pos - fp->_r.  */
+        pos = pos - fp->_r;
+      if (pos < 0)
+        {
+          errno = EIO;
+          return -1;
+        }
+    }
+  else if ((fp->_flags & __SWR) && fp->_p != NULL)
+    {
+      /* Consider the buffered bytes.  */
+      off_t buffered = fp->_p - fp->_bf._base;
+
+      /* Compute pos + buffered, with overflow check.  */
+      off_t sum;
+      if (! INT_ADD_OK (pos, buffered, &sum))
+        {
+          errno = EOVERFLOW;
+          return -1;
+        }
+      pos = sum;
+    }
+
+  return pos;
+
+#else
+
+# if LSEEK_PIPE_BROKEN
   /* mingw gives bogus answers rather than failure on non-seekable files.  */
   if (lseek (fileno (fp), 0, SEEK_CUR) == -1)
     return -1;
-#endif
+# endif
 
-#if FTELLO_BROKEN_AFTER_SWITCHING_FROM_READ_TO_WRITE /* Solaris */
+# if FTELLO_BROKEN_AFTER_SWITCHING_FROM_READ_TO_WRITE /* Solaris */
   /* The Solaris stdio leaves the _IOREAD flag set after reading from a file
      reaches EOF and the program then starts writing to the file.  ftello
      gets confused by this.  */
@@ -66,9 +135,9 @@ ftello (FILE *fp)
         }
       return pos;
     }
-#endif
+# endif
 
-#if defined __SL64 && defined __SCLE /* Cygwin */
+# if defined __SL64 && defined __SCLE /* Cygwin */
   if ((fp->_flags & __SL64) == 0)
     {
       /* Cygwin 1.5.0 through 1.5.24 failed to open stdin in 64-bit
@@ -80,6 +149,9 @@ ftello (FILE *fp)
       fp->_seek64 = tmp->_seek64;
       fclose (tmp);
     }
-#endif
+# endif
+
   return ftello (fp);
+
+#endif
 }
index 1a0f7bcb64081ffc4211c9578b7753d44745d3bd..65bec396908c5664211e77aa133c51a2123d97f4 100644 (file)
@@ -1,4 +1,4 @@
-# ftello.m4 serial 13
+# ftello.m4 serial 14
 dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -130,6 +130,15 @@ main (void)
           ;;
       esac
     fi
+    if test $REPLACE_FTELLO = 0; then
+      dnl Detect bug on macOS >= 10.15.
+      gl_FUNC_UNGETC_WORKS
+      if test $gl_ftello_broken_after_ungetc = yes; then
+        REPLACE_FTELLO=1
+        AC_DEFINE([FTELLO_BROKEN_AFTER_UNGETC], [1],
+          [Define to 1 if the system's ftello function has the macOS bug.])
+      fi
+    fi
   fi
 ])
 
index b648fea37cfe1e95877d1845b1579322a71c2b2d..dd5d1ddc892cf8e8f6741f31c11409c62a6b57fe 100644 (file)
@@ -1,4 +1,4 @@
-# ungetc.m4 serial 9
+# ungetc.m4 serial 10
 dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -55,11 +55,19 @@ AC_DEFUN_ONCE([gl_FUNC_UNGETC_WORKS],
          esac
         ])
     ])
+  gl_ftello_broken_after_ungetc=no
   case "$gl_cv_func_ungetc_works" in
     *yes) ;;
     *)
-      AC_DEFINE([FUNC_UNGETC_BROKEN], [1],
-        [Define to 1 if ungetc is broken when used on arbitrary bytes.])
+      dnl On macOS >= 10.15, where the above program fails with exit code 6,
+      dnl we fix it through an ftello override.
+      case "$host_os" in
+        darwin*) gl_ftello_broken_after_ungetc=yes ;;
+        *)
+          AC_DEFINE([FUNC_UNGETC_BROKEN], [1],
+            [Define to 1 if ungetc is broken when used on arbitrary bytes.])
+          ;;
+      esac
       ;;
   esac
 ])
index 6de0859f8e60ef61d76581eb8a54618c4d18a37c..fc6bafbc64888f9d5f8416c20442f8c9c6b67e93 100644 (file)
@@ -6,6 +6,7 @@ lib/ftello.c
 lib/stdio-impl.h
 m4/fseeko.m4
 m4/ftello.m4
+m4/ungetc.m4
 
 Depends-on:
 stdio
@@ -13,6 +14,7 @@ extensions
 largefile
 sys_types
 lseek           [test $HAVE_FTELLO = 0 || test $REPLACE_FTELLO = 1]
+intprops        [test $HAVE_FTELLO = 0 || test $REPLACE_FTELLO = 1]
 # Just to guarantee consistency between ftell() and ftello().
 ftell