Yes, even freopen().
Once you call fclose() on a FILE*, the implementation may (and probably
will) free() it. This may result in the underlying memory being
unmapped, resulting in subsequent access causing a segfault. And even if
it isn't, the memory may be re-used for something else; it could even
look identical to a valid FILE while not actually being one (this isn't
as unlikely as it seems; given that neither free() nor malloc() will
typically overwrite the memory, if whatever re-uses the memory only
modifies portions of it, the remainder will have the same contents as
when it was a valid FILE).
What convinces me ultimately is 7.19.3p4, especially the parenthesized
part:
----v----
[...] The value of a pointer to a FILE object is indeterminate after the
associated file is closed (including the standard text streams). [...]
----^----
The stream might not be associated with a file.
Yes, that was my exact point originally: the wording suggests there are at
least some cases where a stream not associated with a file can be used
with freopen(). Like, an fclose[d](stdout). But now I'm asking, how?
Re-quoting 7.19.3p4:
----v----
A file may be disassociated from a controlling stream by closing the file.
Output streams are flushed (any unwritten buffer contents are transmitted
to the host environment) before the stream is disassociated from the file.
The value of a pointer to a FILE object is indeterminate after the
associated file is closed (including the standard text streams). [...]
----^----
If the stream is not associated with a file (because it was closed), then
the pointer to the FILE object can't be evaluated at all. (I may have an
actual pointer object that aliases stdout.) You can't pass the value of
that pointer to freopen(). This means two things: (1) a standard text
stream, once closed, is completely lost for the rest of the program, (2)
if the quoted sentence of 7.19.5.4p4,
----v----
The freopen function first attempts to close any file that is associated
with the specified stream.
----^----
is meant as "the freopen function first attempts to close *the* file that
is associated with the specified stream (*if there is any*)"
then the parenthesized part is a no-op, because it can never happen. A
stream that is not associated with a file cannot be operated on by
freopen().
It's conceivable that an implementation could disassociate the stream
from its file if EOF or certain errors occur,
I don't think so. See clearerr(), and the part above which suggests (to me
at least) that the only way of disassociation is fclose().
or the stream might never have been associated with a file in the first
place (e.g. GNU libc allows you to create streams which read or write
blocks of memory).
Yes, exactly, you can create a TCP socket and put an (advisably
unbuffered) stdio stream on top of it with fdopen(), but I'm convinced
"file" in the quoted language doesn't refer to "regular file" in the
UNIX(R) sense. See 7.19.2p1:
----v----
Input and output, whether to or from physical devices such as terminals
and tape drives, or whether to or from files supported on structured
storage devices, are mapped into logical data /streams/ [...]
----^----
and 7.19.3p1:
----v----
A stream is associated with an external file (which may be a physical
device) by opening a file, which may involve creating a new file. [...]
----^----
In short,
- you can't use freopen() on fclose()'d streams at all (that answers my
original question, thanks everyone),
- disassociation is only achieved by fclose(),
- therefore a correct program can't call freopen() on a stream that is not
associated with a file,
- therefore the wording of 7.19.5.4p4 seems to imply a case that actually
can't occur.
Or, there's a tiny bit of chance that I went wrong somewhere
Cheers,
lacos