bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: rationale for closein


From: Rich Felker
Subject: Re: rationale for closein
Date: Mon, 18 Jun 2012 23:30:51 -0400
User-agent: Mutt/1.5.21 (2010-09-15)

On Mon, Jun 18, 2012 at 08:17:25PM -0600, Eric Blake wrote:
> 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:

Yes, they also recommend invoking extremely serious UB (aliasing
violation, which GCC _will_ miscompile) when using dlsym to obtain a
function pointer...

With that said, they have a good point, but it's also arguable that
random parts of the program should not be using stdin/stdout.
Conceptually, these streams "belong to" the main program flow, and
except in really simple programs, they probably should not be used
explicitly (either by name, or by calling stdio functions that
explicitly use them) except in main or a similar function; other
functions should just get a FILE * from the caller.

> 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.

Are you proposing that it be called __fpending or fpending?

> 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

If you're not trating stdout special at all, just as an ordinary
stream like any other, then accessing it after closing it is a major
logic bug in your program equivalent to accessing a FILE* obtained by
fopen after calling fclose on it.

With that said, in order to avoid the situation, the way I would
actually deal with it is with minimal special-casing, something like:

fflush(f);
if (ferror(f)) report_error();
if (f!=stdout) fclose(f);

I'm aware that this does not detect errors from the actual close
syscall, but I'm unconvinced that it's beneficial to do so; after a
successful flush, I consider it the operating system's data loss, not
the application's, if the data fails to end up on permanent storage.
Even if close() returned zero, you could still get this situation with
hardware failures, etc.

> 1.  The atexit() handler is the easiest way to guarantee that things are
> closed properly on all normal exit paths.

But it also runs on failure exit paths, which is probably undesirable
for many programs. Unless you use extra global-var hacks to disable it
from running..

> >> '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

Anywhere you read, you could hit EOF, so you already need to be
testing for that. Once you get to the "we can't read anymore" code,
it's trivial to check ferror(f). And again it can be done in general
without any special attention to whether the file is stdin.

> > 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

OK. I'll see if I can fix this on our side.

Rich



reply via email to

[Prev in Thread] Current Thread [Next in Thread]