lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


The C language standard (I specifically checked in the C99
document) is silent on what the macro stdin means after calling
fclose(stdin).  It is a macro because in some implementations
(especially those with thread-safe runtime libraries) it is
allowed that stdin not be an l-value; it is only required that it
evaluate to an an expression of type FILE*, not that it be
possible to modify it.

Reading between the lines, the standard is pretty clear that
continuing to operate on a FILE after calling fclose() is not
valid. Effectively, continued use of a FILE* after calling
fclose() is similar to continued use a malloc()ed pointer after
calling free(). You might get lucky, but that doesn't make it valid.

In classic implementations, stdin, stdout, and stderr are just
references to the first three slots in the array of FILEs passed
out by fopen().  If one of those files is fclose()ed, then that
slot is likely to get reused by the next call to fopen(),
sometimes with surprising effects.

I clipped the lua code from the quoted message to simplify the
discussion to just the underlying operations on stdin.  The lua
code has the same kind of effect on stdin, just at arm's length.
I've interpolated my understanding of what is happening at some
points in this fragment:

At 02:00 PM 4/17/2007, David Manura wrote:
>It's more directly seen with this test case:
>....
>#include <stdio.h>
>int main()
>{
>  FILE * f;
>  int c;
>  fclose(stdin);

At this point stdin is not well defined.

>  f = fopen("in.txt", "r");

In many libc implementations, f==stdin is likely to be true.

>  while((c = fgetc(stdin)) != -1) fputc(c, stdout); /* prints
>                                                  in.txt ! */

Calling fgetc(stdin) after fclose(stdin) is the fundamental error.

>  return 0;
>}

In lua, since dofile() without any arguments is defined to read
from stdin, stdin *must* be a valid stream open for reading.
After a call io.input():close() (which effectivle does
fclose(stdin)), that is no longer true.  After a subsequent call
to io.open() (which is effectively fopen()), stdin *might* refer
to a valid input stream again, but it is almost certainly not the
one you expected.

This, by the way, is the reason for the standard's inclusion of
the function freopen(). Without that function, it would not be
possible to portably reassign stdin to a different open file.

Ross Berteig                               Ross@CheshireEng.com
Cheshire Engineering Corp.           http://www.CheshireEng.com/
+1 626 351 5493
+1 626 351 8645 FAX