[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#841386: libc6: perror() changes orientation of non-oriented stderr when it is redirected



Package: libc6
Version: 2.24-3
Severity: important
Tags: patch

Dear Maintainer,

This bug can be seen by compiling the following program and then running

    $ ./a.out 2>/dev/null

The output is

    initial fwide: 0
    fwide: -1

The attached patch fixes this, so that the output becomes

    initial fwide: 0
    fwide: 0


#include <stdio.h>
#include <wchar.h>
#include <errno.h>
int main(void)
{
  printf("initial fwide: %d\n", fwide(stderr, 0));
  errno = EINVAL;
  perror(""); /* note, that prior to this call stderr was not oriented */
  printf("fwide: %d\n", fwide(stderr, 0));
  return 0;
}

Cheers,
Igor

P.S. I posted a <a href="https://sourceware.org/bugzilla/show_bug.cgi?id=20677";>bugreport to upstream</a>
I can only guess why this 100% *small* bug has not been fixed ...

-- System Information:
Debian Release: stretch/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 4.7.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages libc6 depends on:
ii  libgcc1  1:6.2.0-6

libc6 recommends no packages.

Versions of packages libc6 suggests:
ii  debconf [debconf-2.0]  1.5.59
pn  glibc-doc              <none>
ii  libc-l10n              2.24-3
ii  locales                2.24-3

-- debconf information excluded
diff -ur glibc-2.24.orig/stdio-common/perror.c glibc-2.24/stdio-common/perror.c
--- glibc-2.24.orig/stdio-common/perror.c	2016-08-02 09:01:36.000000000 +0700
+++ glibc-2.24/stdio-common/perror.c	2016-10-18 08:59:48.996440346 +0700
@@ -22,9 +22,15 @@
 #include <wchar.h>
 #include "libioP.h"
 
-static void
-perror_internal (FILE *fp, const char *s, int errnum)
+/* Print a line on stderr consisting of the text in S, a colon, a space,
+   a message describing the meaning of the contents of `errno' and a newline.
+   If S is NULL or "", the colon and space are omitted.  */
+void
+perror (const char *s)
 {
+  int errnum = errno;
+  int fd = -1;
+
   char buf[1024];
   const char *colon;
   const char *errstring;
@@ -36,48 +42,30 @@
 
   errstring = __strerror_r (errnum, buf, sizeof buf);
 
-  (void) __fxprintf (fp, "%s%s%s\n", s, colon, errstring);
-}
-
-
-/* Print a line on stderr consisting of the text in S, a colon, a space,
-   a message describing the meaning of the contents of `errno' and a newline.
-   If S is NULL or "", the colon and space are omitted.  */
-void
-perror (const char *s)
-{
-  int errnum = errno;
-  FILE *fp;
-  int fd = -1;
-
-
   /* The standard says that 'perror' must not change the orientation
      of the stream.  What is supposed to happen when the stream isn't
-     oriented yet?  In this case we'll create a new stream which is
-     using the same underlying file descriptor.  */
-  if (__builtin_expect (_IO_fwide (stderr, 0) != 0, 1)
-      || (fd = __fileno (stderr)) == -1
-      || (fd = __dup (fd)) == -1
-      || (fp = fdopen (fd, "w+")) == NULL)
-    {
-      if (__glibc_unlikely (fd != -1))
-	__close (fd);
+     oriented yet?  In this case we'll write directly to the same
+     underlying file descriptor.
 
-      /* Use standard error as is.  */
-      perror_internal (stderr, s, errnum);
-    }
+     TODO: implement this feature for streams which are not backed by a POSIX
+     file descriptor (e.g., fopencookie and fmemopen).  */
+
+  if (__builtin_expect (_IO_fwide (stderr, 0) != 0, 1)
+      || (fd = __fileno (stderr)) == -1)
+    /* Use standard error as is.  */
+    (void) __fxprintf (stderr, "%s%s%s\n", s, colon, errstring);
   else
     {
-      /* We don't have to do any special hacks regarding the file
-	 position.  Since the stderr stream wasn't used so far we just
-	 write to the descriptor.  */
-      perror_internal (fp, s, errnum);
-
-      if (_IO_ferror_unlocked (fp))
-	stderr->_flags |= _IO_ERR_SEEN;
-
-      /* Close the stream.  */
-      fclose (fp);
+      /* Streams without orientation have never had any output directed at
+         them, so they are definitely still in the initial shift state with an
+         empty buffer (if the stream is buffered). Thus, in the case when
+         stderr has no orientation, we may safely use "__write", considering
+         the fact that "__write" has no internal buffer.  */
+
+      __write(fd, s, strlen(s));
+      __write(fd, colon, strlen(colon));
+      __write(fd, errstring, strlen(errstring));
+      __write(fd, "\n", 1);
     }
 }
 libc_hidden_def (perror)

Reply to: