On Tue, Jun 19, 2012 at 01:28:24AM +0200, Bruno Haible wrote: > Rich Felker wrote in > <http://www.openwall.com/lists/musl/2012/06/18/8>: > > I've already discussed on this list why using an atexit function for > > closing stdin or stdout is the heart of the problem and the source of > > all the complexity. If the main program just closed the stream at the > > natural point in the normal program flow, it would be trivial to do > > correctly and portably. > > Here's how this 'closein' module came about: > > Jim, maintainer of coreutils (a set of ca. 100 programs), noticed that > the programs failed to report an error when writing to a full disk. Not only > $ cat file1 file2 > /full-partition/output > but also > $ id -u > /full-partition/output > or > $ sort --help > /full-partition/output > > The problem is that not only the "normal program flow" needs to be > considered, but all program flows from the start of main() to exit(). > He could have changed the source code of all 100 programs so that this > bug would be fixed, but that would not give a guarantee that the bug would > not be reintroduced as new code branches are added in existing programs, > or as new programs are being written. So he searched for a solution that > would prevent the bug from reappearing and also not increase the maintenance > burden, and came up with 'closeout'. > > Jim made a presentation about this: > http://www.gnu.org/ghm/2011/paris/#sec-2-1 > http://www.irill.org/events/ghm-gnu-hackers-meeting/videos/jim-meyering-goodbye-world-the-perils-of-relying-on-output-streams-in-c
Yes, I've seen it; it was discussed on our list. I wasn't aware of the specific historic details, but I figured this was probably the general story for how the idea came to be. If the "closeout" approach works best for coreutils, that's the business of the coreutils' maintainers, not my business. However, as I discussed on the musl list, I think it's bad design, and I would highly recommend other projects not follow it. Conceptually, you're turning something that's a local variable (stdout is global, but if it's only used from one point as a generic FILE standing in for something that would otherwise have been obtained by fopen, it's conceptually local) into a global, and thereby losing the _local_ information of whether it was used in the first place, which has to be recovered with the non-portable __fpending. If on the other hand programs just handle stdout as "yet another FILE", the same code that checks for write errors and reports failure for explicitly-opened files would also check and report write errors on stdout. It's not longer a special-case. And special-cases are where errors like to hide. > 'closein' is similar - an attempt to fix an issue that affects many programs, > once and for all. By Eric Blake. I think closein is just a no-op for conformant implementations. exit implicitly closes all streams, including stdin, and per POSIX, fclose has the following effect: If the file is not already at EOF, and the file is one capable of seeking, the file offset of the underlying open file description shall be adjusted so that the next operation on the open file description deals with the byte after the last one read from or written to the stream being closed. As such, close_stdin's attempt to fix-up the file position seems to be redundant. Incidentally, I suspect musl is _not_ currently handling this case correctly. Does gnulib have some tests that assert the required behavior, which I could use to test the current behavior and any efforts to fix it if it's wrong? (If it is broken in musl, it's due to stdin being a special case in musl. Alas, special cases are where errors like to hide...) Rich