libc6's printf and fprintf don't return -1 on closed stdout/stderr.
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
GLibC |
Fix Released
|
Medium
|
|||
glibc (Ubuntu) |
Fix Released
|
Medium
|
Unassigned |
Bug Description
Following a thread on the <email address hidden> mailing list,
http://
I've found that libc doesn't return error indicators from functions
dealing with stdout or stderr FILE pointers as described in the man
pages.
Consider
$ cat closed.c
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
FILE *fp;
fp = fdopen(4, "w");
if (getenv("LINEBUF")) setlinebuf(stdout);
fprintf(fp, "getchar=%d\n", getchar());
fprintf(fp, "puts=%d\n", puts("test puts"));
fprintf(fp, "printf=%d\n", printf("test printf\n"));
fprintf(fp, "fprintf=%d\n", fprintf(stdout, "test fprintf out\n"));
fprintf(fp, "fprintf=%d\n", fprintf(stderr, "test fprintf err\n"));
return 0;
}
$ echo x | ./closed 4>/dev/tty
getchar=120
test puts
puts=10
test printf
printf=12
test fprintf out
fprintf=17
test fprintf err
fprintf=17
$
OK so far.
$ ./closed 4>&1 <&- >&- 2>&-
getchar=-1
puts=10
printf=12
fprintf=17
fprintf=-1
$
stdin and stderr accesses correctly return errors. stdout doesn't because
strace(1) shows no write(2)s occur until the buffer's flushed on exit. Then
the write fails.
write(1, "puts\nprintf\
That's why closed.c has the setlinebuf().
$ LINEBUF= ./closed 4>&1 <&- >&- 2>&-
getchar=-1
puts=-1
printf=12
fprintf=17
fprintf=-1
$
Now puts() fails, good. But not printf() or fprintf() to stdout.
That's despite the writes happening straight away and returning -1.
write(1, "test puts\n", 10) = -1 EBADF (Bad file descriptor)
write(4, "puts=-1\n", 8) = 8
write(1, "test printf\n", 12) = -1 EBADF (Bad file descriptor)
write(4, "printf=12\n", 10) = 10
write(1, "test fprintf out\n", 17) = -1 EBADF (Bad file descriptor)
write(4, "fprintf=17\n", 11) = 11
write(2, "test fprintf err\n", 17) = -1 EBADF (Bad file descriptor)
write(4, "fprintf=-1\n", 11) = 11
The fine man page says
Return value
Upon successful return, these functions return the number of
characters printed (not including the trailing â\0â used to end
output to strings). The functions snprintf and vsnprintf do not
write more than size bytes (including the trailing â\0â). If
the output was truncated due to this limit then the return value
is the number of characters (not including the trailing â\0â)
which would have been written to the final string if enough
space had been available. Thus, a return value of size or more
means that the output was truncated. (See also below under
NOTES.) If an output error is encountered, a negative value is
returned.
yet no negative value is returned. This could cause programs that
carefully check they're creating output to get the wrong end of the
stick.
Jim Meyering, in private email, confirms Solaris 5.9 works as expected.
Platform details:
$ ldd closed
$ dpkg -S /lib/tls/
libc6-i686: /lib/tls/
$ apt-show-versions -p libc6-i686
libc6-
Changed in glibc: | |
status: | Unknown → Fix Released |
Changed in glibc: | |
assignee: | jbailey → nobody |
Changed in glibc: | |
importance: | Unknown → Medium |
checked of Fedora core 4
A recent report of an app we develope caused me to check the fprintf call. My
understanding is that on an error (like EFBIG from the write syscall) the
fprintf should return a negative value. Instead I'm seeing values greater than 0
returned, which would match the length of the string returned.
It may only be that 1 errno value, I haven't checked all possiblilities but I
thought I should let you know.
karl.