X-Authentication-Warning: delorie.com: mail set sender to djgpp-workers-bounces using -f X-Recipient: djgpp-workers AT delorie DOT com Message-ID: <51E702E0.3010809@gmx.de> Date: Wed, 17 Jul 2013 22:47:28 +0200 From: Juan Manuel Guerrero User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121025 Thunderbird/16.0.2 MIME-Version: 1.0 To: djgpp-workers AT delorie DOT com Subject: Re: Set _IOERR if the file stream has been opened in wrong mode. References: <51E5D0C6 DOT 1060404 AT gmx DOT de> <83y5951a79 DOT fsf AT gnu DOT org> In-Reply-To: <83y5951a79.fsf@gnu.org> Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit X-Provags-ID: V03:K0:ftkZZ2NJScdqmQYssShPyik0w00Gpg+lABccO809f3Ptx+sFy6I 7yQoEiR0Lg8DUS3jVmSOgx9U9f0h6h3CBCxry0Fhy3a0GJnQIcMGQ4c14s8lzdFv4zErgCl URzQwkP4ntxMSbIZHBSvd8EY6zNRiZPCMakXAuJ5ZOMi35lmf6HRAW5fRfwOZ9dd9GFh5az JInHCh0jhTgEZK7/B0iBQ== Reply-To: djgpp-workers AT delorie DOT com Am 17.07.2013 17:24, schrieb Eli Zaretskii: >> Date: Wed, 17 Jul 2013 01:01:26 +0200 >> From: Juan Manuel Guerrero >> >> Please inspect the code snippet below: >> >> #include >> >> int main(void) >> { >> char buffer[1024]; >> FILE *f = fopen("foobar.txt", "w"); >> >> clearerr(f); >> >> if (fgets(buffer, sizeof(buffer), f) == NULL) >> printf("EOF encountered before data\n"); >> >> printf("ferror = %s\n", ferror(f) ? "TRUE" : "FALSE"); >> printf("feof = %s\n", feof(f) ? "TRUE" : "FALSE"); >> >> return 0; >> } >> >> >> The code snippet is not arbitrary (especially the "w" mode instead of the "w+" >> mode in the fopen function) but represents a compilable and working version of >> the code produced by the lua interpreter for the first two lines of the >> following lua code snippet: >> >> local f = io.open("foobar.txt", "w") >> local r, m, c = f:read() >> assert(r == nil and ismsg(m) and type(c) == "number") >> >> >> The above code is part of a test suite and it shall fail because it tries to >> read from a file opened to be written. The second line fails and initializes >> the variables in such a way that the assert is not triggert (the data is a >> error message and the file descriptor, but that is of no importance here). >> This is the way the test shall work and this is the way the code works if lua >> has been compiled on linux. If lua is compiled using any version of djgpp, >> the second line: >> local r, m, c = f:read() >> behaves in a different way (it does not fail, among other things) and the >> variables are initialized with nonsense data making the following assertion >> to be triggert and thus aborting the complete test suite. >> >> The reason for the different behavior of lua's :read() function is the >> different way the ferror function has been implemented on linux and djgpp. >> >> The issue concerns the fread, fwrite, __putc and __getc functions only. >> These functions manipulate the file stream FILE *. Functions like read, >> _read and dos_read are not involved because they work with the file descriptor. >> If these functions fail due to accessing the file with wrong file mode, >> they set the appropriate dos error number. >> Of course, ferror can only fail for those functions that use the file stream. >> >> The patch below will fix the issue for read and write functions. >> As usual, suggestions, objections, comments are welcome. > What standard mandates that reading from a file stream open in "w" > mode shall set the error flag for the stream? > > DJGPP currently sets the EOF flag, not the error flag. Why is that > wrong? According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fgets.html RETURN VALUE Upon successful completion, fgets() shall return s. If the stream is at end-of-file, the end-of-file indicator for the stream shall be set and fgets() shall return a null pointer. If a read error occurs, the error indicator for the stream shall be set, fgets() shall return a null pointer. According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fputs.html RETURN VALUE Upon successful completion, fputs() shall return a non-negative number. Otherwise, it shall return EOF, set an error indicator for the stream. According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fread.html RETURN VALUE Upon successful completion, fread() shall return the number of elements successfully read which is less than nitems only if a read error or end-of-file is encountered. If size or nitems is 0, fread() shall return 0 and the contents of the array and the state of the stream remain unchanged. Otherwise, if a read error occurs, the error indicator for the stream shall be set According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fwrite.html RETURN VALUE The fwrite() function shall return the number of elements successfully written, which may be less than nitems if a write error is encountered. If size or nitems is 0, fwrite() shall return 0 and the state of the stream remains unchanged. Otherwise, if a write error occurs, the error indicator for the stream shall be set, For IEEE Std 1003.1-2001-conforming systems all the functions also shall set errno. It is a matter of fact that the sample code posted in the previous mail behaves as described by me for linux and cygwin. And this behavior is exploited by other programs like lua. I have inspected __getc, __putc, fwrite and fread and neither of them set EOF. In the best case some of them may return EOF to the calling context to signal a failure but the _flag member (error indicator for the stream) is never set neither to _IOEOF nor to _IOERR AFAIK. I have not tried it mingw but I presume it will behave the same way than linux and cygwin. It may be objectionable if __getc and __putc were the right places to fix the issue. I will move the fix into fgets and fputs, the same way I have done for fwrite and fread. By fixing it in the auxiliary functions __getc and __putc, my intention was to have it fixed every where and for all times. BTW as can be seen for fgets if the stream is at end-of-file, the end-of-file indicator for the stream shall be set apart from returning a NULL pointer. So there is much work to be done. IMHO it is better to try to fix the library than to clobber the source code of some program to get it compiled with djgpp or the day may come when djgpp become completely useless and obsolete. Regards, Juan M. Guerrero