This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Fwd: Bug#43023: libc 2.1.1-10 makes it impossible to use stdoutreliably


--- begin forwarded text
Subject: Bug#43023: libc 2.1.1-10 makes it impossible to use stdout reliably
Reply-To: Ian Jackson <ian@davenant.greenend.org.uk>, 43023@bugs.debian.org
From: Ian Jackson <ian@davenant.greenend.org.uk>
Date: Sun, 15 Aug 1999 17:05:32 +0100 (BST)
To: submit@bugs.debian.org

Package: libc6
Version: 2.1.1-10
Severity: critical

We all know that correct programs check the return values from all
their stdio writes.

However, stdio buffers things.  In many cases, the data doesn't get
written until the program returns from main or calls exit(3).
Furthermore there exist a number of network filesystems and similar
systems where write errors are not reported until close(2).  So a
straightforward `hello world' program, for example, might well lose
data, even if it checked the return from printf(3).

I think this is a bug or misfeature in stdio, and that the run-time
system should flush and close all its output streams on exit and treat
errors as fatal, causing an error message to stderr and an exit status
of -1.  However, this is not the current behaviour of the libc, and
has never been the behaviour of any libc I've seen, so there may be
some resistance to this course.

Thus any program which uses stdout must call fclose on it and check
the error, before it exits 0 or returns from main.  (Unless it wants
to risk exiting with status 0 after losing output.)  This will
continue to be the case even if the Linux libc is fixed in the way I
suggest, because programs will still need to be made reliable on other
platforms.

However, with glibc 2.1.1-10 this causes a segmentation fault.  This
is very bad.  Not only does it break any existing reliable software,
but it is encouraging people to write more unreliable software (ie, by
making it impossible for them to fclose stdout as they ought to) or
even to make currently-reliable software unreliable (to fix what they
perceive as a bug in the program - that it segfaults on exit).

A demonstration test case involving a simple `hello world' program is
below.

Thanks,
Ian.


The test program:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, const char *const *argv) {
   const char *arg;
   int ac;

   arg= argv[1];
   if (!arg || !(ac= arg[0]) || !strchr("cnd",ac) || arg[1]) {
     fputs("stdioclosetest: need argument c or n\n",stderr);
     exit(2);
   }

   if (fputs("hello\n",stdout) == EOF) { perror("fputs"); exit(1); }

   if (ac == 'c') {
     if (fclose(stdout)) { perror("fclose"); exit(1); }
   }

   fputs("exiting 0\n",stderr);
   exit(0);
}



First, on a glibc 2.0 system:

$ gcc -Wall -o stdioclosetest stdioclosetest.c
$ ./stdioclosetest n; echo $?
hello
exiting 0
0
$ ./stdioclosetest c; echo $?
hello
exiting 0
0
$ ./stdioclosetest n >/dev/full; echo $?
exiting 0
0
$ ./stdioclosetest c >/dev/full; echo $?
fclose: No space left on device
1
$ ldd ./stdioclosetest
         libc.so.6 => /lib/libc.so.6 (0x40016000)
         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
$ dpkg -l libc6
Desired=Unknown/Install/Remove/Purge
| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ Name            Version        Description
+++-===============-==============-============================================
ii  libc6           2.0.7.19981211 GNU C Library: shared libraries
$ ls -al /lib/libc.so.6
lrwxrwxrwx   1 root     root           13 Aug  4 20:26 /lib/libc.so.6 
-> libc-2.0.7.so
$


Now, the same program on a glibc 2.1 system:

-davenant:~/junk> gcc -Wall stdioclosetest.c -o stdioclosetest
-davenant:~/junk> ./stdioclosetest n; echo $?
hello
exiting 0
0
-davenant:~/junk> ./stdioclosetest c; echo $?
hello
Segmentation fault
139
-davenant:~/junk> ./stdioclosetest n >/dev/full; echo $?
exiting 0
0
-davenant:~/junk> ./stdioclosetest c >/dev/full; echo $?
Segmentation fault
139
-davenant:~/junk> strace ./stdioclosetest n >/dev/full
execve("./stdioclosetest", ["./stdioclosetest", "n"], [/* 44 vars */]) = 0
brk(0)                                  = 0x80497ac
open("/etc/ld.so.preload", O_RDONLY)    = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0
mmap(0, 18, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x40015000
close(3)                                = 0
open("/lib/nfslock.so.0", O_RDONLY)     = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=6371, ...}) = 0
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3"..., 4096) = 4096
mmap(0, 8024, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40016000
mprotect(0x40017000, 3928, PROT_NONE)   = 0
mmap(0x40017000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 
3, 0) = 0x40017000
close(3)                                = 0
munmap(0x40015000, 18)                  = 0
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=13432, ...}) = 0
mmap(0, 13432, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40018000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=1170636, ...}) = 0
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3"..., 4096) = 4096
mmap(0, 994172, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4001c000
mprotect(0x40107000, 31612, PROT_NONE)  = 0
mmap(0x40107000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 
3, 0xea000) = 0x40107000
mmap(0x4010c000, 11132, PROT_READ|PROT_WRITE, 
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4010c000
close(3)                                = 0
mprotect(0x4001c000, 962560, PROT_READ|PROT_WRITE) = 0
mprotect(0x4001c000, 962560, PROT_READ|PROT_EXEC) = 0
munmap(0x40018000, 13432)               = 0
personality(PER_LINUX)                  = 0
getpid()                                = 24296
brk(0)                                  = 0x80497ac
brk(0x804994c)                          = 0x804994c
brk(0x804a000)                          = 0x804a000
fstat(1, {st_mode=S_IFCHR|0622, st_rdev=makedev(1, 7), ...}) = 0
mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) 
= 0x40015000
ioctl(1, TCGETS, 0xbffff844)            = -1 ENOTTY (Inappropriate 
ioctl for device)
write(2, "exiting 0\n", 10exiting 0
)             = 10
write(1, "hello\n", 6)                  = -1 ENOSPC (No space left on device)
munmap(0x40015000, 4096)                = 0
_exit(0)                                = ?
-davenant:~/junk> ldd ./stdioclosetest
         /lib/nfslock.so.0 => /lib/nfslock.so.0 (0x40003000)
         libc.so.6 => /lib/libc.so.6 (0x40009000)
         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)
-davenant:~/junk> ll /lib/libc.so.6
lrwxrwxrwx   1 root     root           13 Jun 13 16:02 /lib/libc.so.6 
-> libc-2.1.1.so*
-davenant:~/junk> dpkg -l libc6
Desired=Unknown/Install/Remove/Purge
| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ Name            Version        Description
+++-===============-==============-============================================
ii  libc6           2.1.1-10       GNU C Library: Shared libraries and timezone
-davenant:~/junk>


--
To UNSUBSCRIBE, email to debian-bugs-dist-request@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org
--- end forwarded text


-- 
Joel Klecker (aka Espy)                    Debian GNU/Linux Developer
<URL:mailto:jk@espy.org>                 <URL:mailto:espy@debian.org>
<URL:http://web.espy.org/>               <URL:http://www.debian.org/>

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]