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: