This is the mail archive of the newlib@sourceware.org mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Reading a write-only file doesn't set error condition (was Re: Cygwin fread on Write-Only File Descriptor returns undefined state)


Corinna Vinschen wrote:
Thanks for the testcase.  This looks like a small flaw in newlib.
I redirected to the newlib list.

On Jun 13 22:29, Linda Walsh wrote:

I think I've run into a problem involving fread.
I open a test file (fopen) with Write-Only access ("w"),
immediately after that, I do an fread on the file handle
of some number of bytes.


I expect fread to return an error. But it doesn't. It returns 0 as the number of bytes read, and the
error value remains unset when querying with ferror.


In addition to fread not setting the error value, a value
of zero is returned.  Zero is to be returned, *only* on
end-of-file or error.  However, in the test case, neither


That's not correct.  Any value less than size*nitems indicates either
EOF or an error.  The programmer is responsible to test with feof() or
ferror() to distinguish between these two cases.  See

http://www.opengroup.org/onlinepubs/009695399/functions/fread.html


value is returned.  Theoretically, this shouldn't happen
(i.e. it's an undefined "set" of return values).

test program follows:
-------------------
#include <stdio.h>
main (int argc, char * argv[]) {

FILE * output_handle=fopen("/tmp/tmpfile","w");
if (!output_handle) {
printf ("can't open output file /tmp/tmpfile\n");
exit (1);
}


char mybuff[4];
int retval=fread(mybuff, sizeof(char), 4, output_handle);
if (!retval) {
int eof=feof(output_handle);
int err=ferror(output_handle);
printf ("(retval,eof,err) = (%d,%d,%d)\n",retval,eof,err);
if (!eof && ! err) printf ("Undefined error: fread returned zero, but there is no eof or error\n");
exit(2);
} else
printf ("Unexpected success in fread: Read %d chars\n",retval);
exit(0);
}


I debugged your testcase and the problem appears to be in __srefill(),
defined in newlib/libc/stdio/refill.c:

  /* if not already reading, have to be reading and writing */
  if ((fp->_flags & __SRD) == 0)
    {
      if ((fp->_flags & __SRW) == 0)
        return EOF;

So, what happens is that EOF is returned if the file is not readable.
Errno isn't set and the error condition on the file pointer isn't set
either.

Testing the same situation on Linux, errno is set to EBADF and the
error indicator is set on the file pointer, while the EOF condition
stays clear.

So, I'd like to propose the below patch.  I assume a similar patch
should be ok for __sfvwrite, too, isn't it?  There's a call to
cantwrite() which only returns EOF but which probably should also
set the error condition and errno.


This opens a can of worms. You can't just use _REENT to set errno. One has to provide _r versions of the read/write functions. I have just made a patch and am verifying it builds for x86-linux. I will post the patch when I am ready to check it in.


-- Jeff J.


* libc/stdio/refill.c (__srefill): Return error condition when trying to read a file not opened for reading.

Index: libc/stdio/refill.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/refill.c,v
retrieving revision 1.6
diff -u -p -r1.6 refill.c
--- libc/stdio/refill.c 8 Feb 2005 01:33:17 -0000 1.6
+++ libc/stdio/refill.c 14 Jun 2006 08:19:28 -0000
@@ -19,6 +19,7 @@
#include <_ansi.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/errno.h>
#include "local.h"
static int
@@ -55,7 +56,11 @@ _DEFUN(__srefill, (fp),
if ((fp->_flags & __SRD) == 0)
{
if ((fp->_flags & __SRW) == 0)
- return EOF;
+ {
+ _REENT->_errno = EBADF;
+ fp->_flags |= __SERR;
+ return EOF;
+ }
/* switch to reading */
if (fp->_flags & __SWR)
{



Corinna




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]