Mail Archives: djgpp/1997/05/22/09:32:59
From: | Christopher Croughton <crough45 AT amc DOT de>
|
Message-Id: | <97May22.152830gmt+0100.16662@internet01.amc.de>
|
Subject: | ANSI function 'tmpfile' opens file in wrong mode
|
To: | djgpp AT delorie DOT com
|
Date: | Thu, 22 May 1997 14:32:06 +0100
|
Mime-Version: | 1.0
|
On 24th March I submitted the following bug report. No response
to it (except a non-portable workaround from Roger Burton West,
who brought the problem to my attention in the first place).
Does anyone read bug reports? In case not, this is the report:
----------------------------------------------------------------------------
When Created: 03/24/1997 10:01:23
In version: 2.01
By whom: crough45 AT amc DOT de
Abstract: ANSI function 'tmpfile' opens file in wrong mode
Function 'tmpfile' in the DJGPP library distribution seems to open
the file in a way contrary to that stated in the ANSI C specification.
In X3.159.1989 it states:
The tmpfile function creates a temporary binary file that will
automatically be removed when it is closed or at program termination.
... The file is opened for update with "wb+" mode.
(Para. 7.9.4.3, ellipsis mine.)
Is there a later version of the ANSI/ISO specification which changes
this behaviour?
The source in djlsr201.zip, however, has:
f = fopen(temp_name, (_fmode & O_TEXT) ? "wt+" : "wb+");
Which (since _fmode defaults to text) opens it by default in text mode.
While this doesn't make any difference on Unix, on MSDOS it has a drastic
effect - all CRs (0x0D) are deleted and the file is terminated by a ^Z
(0x1A).
This will (and does) break ANSI-conforming programs which use a temporary
file in unpredictable ways - such files are commonly used to store binary
data such as pointers and file offsets, which are very likely to contain
bytes with those values.
I don't have the GCC distribution sources to hand, but it seems possible
that this has been inherited from the standard GCC library and has just
never shown up on Unix...
It's easy to test what difference it makes - just open the tmpfile,
write all the characters from 0 to 255 using putc/fputc, rewind and
read them back. As an example:
#include <stdio.h>
int main()
{
FILE *fp = tmpfile();
int i, n;
if (!fp)
{
perror("temporary file");
exit(1);
}
for (i = 0; i < 256; i++)
putc(i, fp);
rewind(fp);
for (i = 0; i < 256; i++)
{
n = getc(fp);
if (i != n)
printf("expecting %.2X, got %.2X\n", i, n);
}
fclose(fp);
}
It should just exit without messages if it was OK; under DJGPP v2.01 it
produces messages for every character after 0D (CR), and the file is
terminated on reading 1A.
(Incidentally, Borland C v4.02 has the correct behaviour; I haven't tested it
with any other DOS compilers.)
----------------------------------------------------------------------------
The fix to the library is trivial - always do the open with "wb+" - but
it does mean getting the library sources and recompiling (and therefore
fixing all the other bugs which cause it not to compile). Because of
this it means that any distributed code will fail to work without the
patched library.
What is involved in getting a corrected library distributed?
(Is this a serious problem? Well, it's caused a lot of time wasting trying
to track down 'bugs' in the application program which were in fact in the
library, and it's made more than one person dubious about trying to
distribute their source code...)
If you want a context diff:
*** tmpfile.c Sun Jun 04 02:47:02 1995
--- tmpfile.new Thu May 22 15:24:30 1997
***************
*** 21,27 ****
if (!n_t_r)
return 0;
! f = fopen(temp_name, (_fmode & O_TEXT) ? "wt+" : "wb+");
if (f)
{
f->_flag |= _IORMONCL;
--- 21,27 ----
if (!n_t_r)
return 0;
! f = fopen(temp_name, "wb+");
if (f)
{
f->_flag |= _IORMONCL;
Chris
- Raw text -