ferror(stdin)
Web Server forum
Back To The Forum Home!Search!Private Messaging System

Web Server Talk Web Server Talk > Unix and Linux reviews > Free Unix support > Unix Programming > ferror(stdin)




  Last Thread   Next Thread Next
  Show Printable Version Email this Page Subscribe to this Thread      Post New Thread    Post A Reply      

    ferror(stdin)  
Bill Pursell


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM

I have a colleague who likes to write:

while (!feof(stdin) {
fread( ..., stdin);
}

I need to convince him that at the very least he should write
while (!feof(stdin) && !ferror(stdin))...

What is a good way to cause an error to occur on stdin
to put the first loop into an infinite loop and demonstrate
the fragility of the code?  The only thing I can think
of is:
% cat big_file | broken_code &
Go physically remove the disk on which big_file is mounted.

I'd like to be able to do the demonstration without
physical access to the machine.  Any ideas?






[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Erik Max Francis


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM

Bill Pursell wrote:

> I have a colleague who likes to write:
>
> while (!feof(stdin) {
>    fread( ..., stdin);
> }
>
> I need to convince him that at the very least he should write
> while (!feof(stdin) && !ferror(stdin))...

Both are at best incomplete; they require more error testing than you've
shown.  feof and ferror only return true when these conditions have
_already happened_.  In other words, feof doesn't tell you whether
you're at the end of a file; it tells you whether or not you've already
made another read (or other operation) that resulted in an end of file
condition.  (A similar thing is true of ferror.)

This means that the fread call must handle the case where fread returns
0 to indicate an end of file or error conditions.  In those cases, that
is what tells you whether there has been an end of file or an error, so
it doesn't make sense to call feof/ferror in the loop condition, but
rather afterward:

while ((size = fread(..., file)) != 0)
{
.. do something with the chunk of data ...
}

Afterwards, you can call ferror to find out if the last call to fread
failed due to an error, rather than an (expected) end of file.

In practice, feof and ferror are rarely used in a loop condition for
this reason.

--
Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM, Y!M erikmaxfrancis
Sometimes there's no point in giving up.
-- Louis Wu





[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Bill Pursell


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM


Erik Max Francis wrote:
> Bill Pursell wrote:
> 
>
> Both are at best incomplete; they require more error testing than you've
> shown.

Yes.  The difficulty I'm having is not a techinical problem, it's
a people problem.  I first need to work on convincing
him that the code is broken.  Once I've demonstrated
a problem, I can begin to work on the solution.  I definitely
agree that the loop condition needs to be dependent
on the return value of fread(), which at the moment he
doesn't even bother looking at at all.  My plan at
the moment is to see if I can convince him to make
any changes, and then worry about which changes
to prioritize.   It is surprisingly difficult to have this
type of conversation with someone who is allegedly
more senior.  Or rather, more senior in fact and by
implication more experienced.

--
Bill Pursell






[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Maurizio Loreti


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM

"Bill Pursell" <bill.pursell@gmail.com> writes:

> I have a colleague who likes to write:
>
> while (!feof(stdin) {
>    fread( ..., stdin);
> }

This code is WRONG.  From the FAQ list of comp.lang.c:

12.2:   Why does the code

while(!feof(infp)) {
fgets(buf, MAXLINE, infp);
fputs(buf, outfp);
}

copy the last line twice?

A:      In C, end-of-file is only indicated *after* an input routine has
tried to read, and failed.  (In other words, C's I/O is not like
Pascal's.)  Usually, you should just check the return value of
the input routine -- fgets(), for example, returns NULL on end-
of-file.  In virtually all cases, there's no need to use feof()
at all.

References: K&R2 Sec. 7.6 p. 164; ISO Sec. 7.9.3,
Sec. 7.9.7.1,
Sec. 7.9.10.2; H&S Sec. 15.14 p. 382.

--
Maurizio Loreti                         [url]http://www.pd.infn.it/~loreti/mlo.html[/ur
l]
Dept. of Physics, Univ. of Padova, Italy              ROT13: ybergv@cq.vasa.
vg





[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Bill Pursell


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM


Maurizio Loreti wrote:
> "Bill Pursell" <bill.pursell@gmail.com> writes:
> 
>
> This code is WRONG.  From the FAQ list of comp.lang.c:

The code has problems, but it's not WRONG.  It is
true that, assuming that all of the freads succeed
without error, the last read will not get a full amount
of data.  The difficulty I'm having is that
the person writing the code is making 2 assumptions,
1 of which is perfectly valid for the problem at hand.  The
assumptions that are being made are:  1) (which is
valid) we don't care about the last buffer, and 2) (which
is completely ridiculous) all the reads will succeed and
there will never be an error.

I understand that this code is bogus.  I need to convince
someone else of that.  I've tried pointing out that there
is a potential problem, and the response I've received
is, basically, "there's no way an error can occur when
reading stdin."

So the question remains:  how can I easily simulate
an error on an fread(...,stdin)?






[ Post a follow-up to this message ]



    Re: ferror(stdin)  
joe@invalid.address


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM

"Bill Pursell" <bill.pursell@gmail.com> writes:

> Maurizio Loreti wrote: 
>
> The code has problems, but it's not WRONG.  It is true that,
> assuming that all of the freads succeed without error, the last read
> will not get a full amount of data.  The difficulty I'm having is
> that the person writing the code is making 2 assumptions, 1 of which
> is perfectly valid for the problem at hand.  The assumptions that
> are being made are: 1) (which is valid) we don't care about the last
> buffer, and 2) (which is completely ridiculous) all the reads will
> succeed and there will never be an error.
>
> I understand that this code is bogus.  I need to convince someone
> else of that.  I've tried pointing out that there is a potential
> problem, and the response I've received is, basically, "there's no
> way an error can occur when reading stdin."

What's the difference between bogus and wrong?

> So the question remains: how can I easily simulate an error on an
> fread(...,stdin)?

Try making stdin something that fails, for example

#include <stdio.h>
int main()
{
char buf[1024];
while(!feof(stdin))
{
fread(buf, sizeof buf, 1, stdin);
if(ferror(stdin))
{
printf("error on stdin\n");
return 1;
}
}
}

# a.out < /dev/ttyS1
error on stdin

Joe





[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Bill Pursell


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM

joe@invalid.address wrote:
> "Bill Pursell" <bill.pursell@gmail.com> writes:
> 
>
> What's the difference between bogus and wrong?

Good point.  I was just trying to emphasize that the
behavior of the program on the trailing data isn't
important, which is the issue raised in the FAQ.
 
>
> Try making stdin something that fails, for example
<snip>
> # a.out < /dev/ttyS1
> error on stdin

That's a good idea.  I'll try that.

--
Bill Pursell






[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Nils O. Selåsdal


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-16-06 06:43 PM

Bill Pursell wrote:
> I have a colleague who likes to write:
>
> while (!feof(stdin) {
>    fread( ..., stdin);
> }
>
> I need to convince him that at the very least he should write
> while (!feof(stdin) && !ferror(stdin))...

That's wrong too. Depending on the reading function you use
you might read the last line twice, or skip the last thing
read. You don't want to do that ?

Check for errors/eof /after/ an io function says there was
an error or EOF.
fread returns less than requested when it reaches EOF
or an error occurs. getchar returns EOF when an error
or EOF occurs. fgets returns NULL when ... and so on.





[ Post a follow-up to this message ]



    Re: ferror(stdin)  
Geoff Clare


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
09-18-06 06:28 PM

"Bill Pursell" <bill.pursell@gmail.com> wrote, on Sat, 16 Sep 2006:

> So the question remains:  how can I easily simulate
> an error on an fread(...,stdin)?

POSIX requires the following errors to be detected by fread():

[EAGAIN]
The O_NONBLOCK flag is set for the file descriptor underlying
stream and the thread would be delayed in the fgetc() operation.
[EBADF]
The file descriptor underlying stream is not a valid file
descriptor open for reading.
[EINTR]
The read operation was terminated due to the receipt of a signal,
and no data was transferred.
[EIO]
A physical I/O error has occurred, or the process is in a
background process group attempting to read from its controlling
terminal, and either the process is ignoring or blocking the
SIGTTIN signal or the process group is orphaned.
[EOVERFLOW]
The file is a regular file and an attempt was made to read at or
beyond the offset maximum associated with the corresponding stream.

You could set up EAGAIN by executing the "target" program from a
wrapper which sets O_NONBLOCK on stdin, with stdin coming from a pipe.

You could set up EBADF by executing the target program with stdin
closed:

$ cat <&-
cat: -: Bad file descriptor
cat: closing standard input: Bad file descriptor

You can't really do anything with EINTR without knowing details of
the target program's signal handling.

You could set up EIO by executing the target program in the background
with SIGTTIN ignored.  The following works in ksh, but not in bash for
some reason (probably it sets TTIN back to default in the child):

$ trap "" TTIN; /bin/cat &
/bin/cat: -: Input/output error

(I had to specify /bin/cat because ksh93 has cat built in.)

If you have a system that supports a compilation environment with
32-bit off_t and supports files larger than 2GB, you could set up
EOVERFLOW by compiling the target program with 32-bit off_t and
redirecting stdin from a file larger than 2GB.  (It would be best to
set the file offset on stdin to just less than 2GB before executing
the program, to save it having to read the whole file.)

--
Geoff Clare <netnews@gclare.org.uk>






[ Post a follow-up to this message ]



    Sponsored Links  




 





   All times are GMT. The time now is 02:01 PM.      Post New Thread    Post A Reply      
  Last Thread   Next Thread Next


Most Popular forums 

Forum Jump:
Rate This Thread:

Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is OFF
vB code is ON
Smilies are ON
[IMG] code is OFF
 
Medical and Health forum | Computer Games Reviews | Graphics design forum

Back To The Top
Home | Usercp | Faq | Register