perror() changes the orientation of stderr to byte-oriented mode if stderr is not oriented yet.

Craig Howland howland@LGSInnovations.com
Fri Jul 6 06:59:00 GMT 2018


On 07/05/2018 08:49 AM, Corinna Vinschen wrote:
> On Jul  5 20:35, Takashi Yano wrote:
>> Hi Corinna,
>>
>> Thank you for checking.
>>
>> On Thu, 5 Jul 2018 13:19:21 +0200
>> Corinna Vinschen wrote:
>>> Yes, we need it, the entire operation, flushing and writing, must be
>>> cancel-safe and synchronized with other access to the stderr FILE.
>>>
>>> Comparing with FreeBSD, there's also something missing.  After the
>>> write operation, the offset in the FILE structure is incorrect.
>>> Consequentially the __SOFF flag is reset to 0 last thing before
>>> unlocking the file:
>>>
>>>    stderr->_flags &= ~__SOFF;
>> Do you mean these are necessary for both perror.c and psignal.c?
>> How about psiginfo() case?
> Well, as long as we use the method at hand, I think it's the right thing
> to do.  However...
>
> ...I noticed that FreeBSD handles psignal differently.  It writes the
> output immediately to STDERR_FILENO, rather than to stderr or
> fileno(stderr).  It does also not call fflush or reset the _SOFF flag.
>
> OpenBSD uses this method for perror as well, no syncing with stderr,
> no cancel-safety.
>
> GLibc duplicates the file descriptor in perror, but writes immediately
> to STDERR_FILENO in psiginfo, or uses an internal variation of
> fprintf in psignal (thus potentially changing the orientation).
>
> Ok, I'm a bit more puzzled than before.  What all this is missing is
> *consistency*.
>
> I really wonder how standards-compliant this is.  For all three
> functions POSIX says something like "... shall print a message out on
> stderr ...".  stderr is the stream and it's underlying descriptor, not
> necessarily STDERR_FILENO.
>
> If immediate writing to STDERR_FILENO is ok, we should simply call
> write(STDERR_FILENO) and be done with it.  Just like BSDs and Linux,
> we don't even have to loop until all bytes have been written, none
> of the above does.
>
>
> Thoughts?
>
>
> Corinna
>

      POSIX defines all 3 functions with the same basic requirements, so it 
certainly does seem like whatever we do ought to be done in the same way for all 
3.  (I suppose you could make an argument that perror() is C while the other 2 
are not, allowing a possible difference there.  But that doesn't seem like a 
good idea.)
      I think that we're kind of stuck needing the fflush().  While I'd rather 
just skip it, not calling it can provide end behavior that is clearly different 
than perror()/etc. writing to the stream, itself, instead of calling write(2) 
(even if only when it is not unbuffered).    That is, with a line or 
fully-buffered stream, anything in the stream buffer already at the time 
perror() is called should appear before the perror() output.  If we don't flush, 
the in-buffer data appear after.  The fflush() is what ends up making it look 
like we wrote to the stream using the more usual mechanism instead of write 
directly.  That is, I think that with the fflush(), the end result should be the 
same as if we really were writing through the stream mechanism.  (Although 
there's a complication related to timing, which is why I'm saying "end result" 
instead of "identical results."  See below.)  This means we would be statically 
standard compliant, even if the underlying mechanism is doing an end run around 
the usual internal stream write mechanisms.
      To put this into a different form:

lock stream stderr;
fflush(stderr);
write(fileno(stderr), string);
unlock stream stderr;

should produce the same end effect as

fputs(stderr, string);   /* (effectively what perror() is required to end up 
doing) */

in terms of the sequence of bytes which end up in the file.
      The former can produce a clear timing difference, however, although only 
if the stream is fully buffered:  the fputs() output might not appear until 
something else is written (depending upon where the buffer fill happens to be), 
while the former case forces string out right away.  This seems impossible to 
fix without returning to the full streams mechanism, but then we're back to the 
complex 'don't change the orientation' problem we're trying to avoid.  It seems 
a small enough problem to accept, especially given the mess you're describing 
for the other libraries.
      Along the same lines, since they are supposed to write to the stream, 
strictly fileno(stderr) should be used, since it is possible for STDERR_FILENO 
(a fixed constant) to be inaccurate.  This point really is independent of the 
fflush() question.  (At least something seems easy to answer.)
                 Craig



More information about the Newlib mailing list