On 06/18/2012 06:01 PM, Rich Felker wrote: > > 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.
And that's where I disagree - the POSIX folks _specifically_ recommend the closeout approach of an atexit() handler: http://austingroupbugs.net/view.php?id=555 "Since after the call to fclose() any use of stream results in undefined behavior, fclose() should not be used on stdin, stdout, or stderr except immediately before process termination (see XBD 3.297 on page 81), so as to avoid triggering undefined behavior in other standard interfaces that rely on these streams. If there are any atexit() handlers registered by the application, such a call to fclose() should not occur until the last handler is finishing. Once fclose() has been used to close stdin, stdout, or stderr, there is no standard way to reopen any of these streams." > 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. But our argument is that __fpending (well, 'fpending') _should_ be portable, and I am in the process of proposing it for standardization in the next version of POSIX because it is so useful. > > 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. Any program that treats stdout as just like any other file risks closing stdout too early, and then causing undefined behavior in the rest of the program when some other standard interface accidentally ends up using fd 1. The atexit() handler is the easiest way to guarantee that things are closed properly on all normal exit paths. > >> '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, But the implicit close by exit(), while properly repositioning stdin (on working implementations; glibc is broken but I fixed cygwin to be working), has the drawback of silently eating errors if something went wrong. If you WANT to detect read errors, and consolidate the error detection into a single ferror() location rather than littering the rest of your code with harder-to-maintain checks, then closein is the way to go. If you don't want to detect read errors in a central location, then yes, avoiding the use of the closein module should have no effect on a compliant environment; but it is still necessary to work around broken environments such as glibc. > 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? tests/test-closein.{c,sh} are sufficient to test the closein module; if you comment out the atexit() call, it will be sufficient to demonstrate that glibc leaves stdin at the wrong file offset on exit(); it is also sufficient to demonstrate that even with a compliant exit(), the implicit close of exit() eats errors and does not affect error status, whereas the use of the closein module _does_ detect read errors at a central location. -- Eric Blake ebl...@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
signature.asc
Description: OpenPGP digital signature