Sender: crough45 AT amc DOT de Message-Id: <97Oct6.134924gmt+0100.11652@internet01.amc.de> Date: Mon, 6 Oct 1997 12:54:05 +0100 From: Chris Croughton Mime-Version: 1.0 To: demmer AT LSTM DOT Ruhr-UNI-Bochum DOT De Cc: djgpp AT delorie DOT com Subject: Re: Flaw in tmpfile() ? Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Precedence: bulk Thomas Demmer wrote: > I just stumbled across a little flaw in tmpfile(). It opens > the file according to the current setting of _fmode either > int text or binary mode. IMHO this should at least be mentioned > in the docs ;-) No, it should be corrected. I raised this as a bug (it's contrary to the ANSI C specification) as bug number 143 (look in the bug tracking system on www.delorie.com, and added a patch. It was accepted that this was a bug and a violation of the ANSI spec., but I've seen no sign of an updated library. I don't know the mechanism for releasing new versions of the library - perhaps I'm expected to put my recompiled version on the web? I reproduce the bug report here: ---------------------------------------------------------------------- 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 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.) Workaround added on 05/17/1997 11:53:18 By whom: rburtonw AT nyx DOT net After opening a tmpfile(), call setmode(fileno(tmpfilehandle))=O_BINARY; Note added on 05/22/1997 09:05:47 By whom: crough45 AT amc DOT de That 'workaround' is not portable - UNIX supports neither O_BINARY nor setmode (it needs neither, of course). Solution added on 05/26/1997 10:59:20 By whom: crough45 AT amc DOT de *** src/libc/ansi/stdio/tmpfile.c~ Sun Jun 04 02:47:02 1995 --- src/libc/ansi/stdio/tmpfile.c 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;