1

Is the following program a valid C program?

#include <stdio.h>

int main()
{
    fwrite("x", 1, 1, stderr);
    fflush(stderr);
    fgetc(stderr);
    fwrite("y", 1, 1, stderr);
    return 0;
}

Notice that I try to read from stderr.

When I compile it in Visual C++ 2008, and run it, I get the following output:

xy

which makes sense. However, when I redirect stderr to a file (test.exe 2> foo.txt), I get a "Debug Assertion Failed" window with the message: "Inconsistent Stream Count. Flush between consecutive read and write". Adding a fflush between the read and write does fix the problem. (This happens in debug build. In release builds, the second write silently fails).

Is this behavior correct, or is this a compiler library bug? I couldn't find anywhere any rules describing when reads or writes are illegal in C.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
Amnon
  • 7,652
  • 2
  • 26
  • 34
  • 4
    Reading from an output stream is undefined behaviour. And what on earth would you expect it to do? –  Jul 08 '10 at 18:50
  • 1
    One note that it would not be a compiler bug but a library implementation bug. – R Samuel Klatchko Jul 08 '10 at 18:52
  • 1
    @NeilButterworth - I don't believe reading an output stream should cause UB. According to the Opengroup, this should just cause `fgetc` to fail and set errno to `EBADF` (see http://www.opengroup.org/onlinepubs/009695399/functions/fgetc.html) – R Samuel Klatchko Jul 08 '10 at 18:53
  • @Neil: if reading from stderr is undefined behavior, that's the answer. Do you have a reference for it? (I would expect it to fail in a defined way). – Amnon Jul 08 '10 at 18:59
  • @Amnon Can't find it - maybe I'm imagining it. The standard does not seem to specify explicitly what happens if you read from an output stream . It certainly does not specify that errno is set to EBADF, however. –  Jul 08 '10 at 19:10
  • I believe Neil's right (the result is UB), but I don't think there's a reference for it -- the standard simply doesn't attempt to define the result of reading from a stream opened only for output, so the result is UB. If you want to get technical, the reference is §4/2: "Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior." – Jerry Coffin Jul 08 '10 at 19:16

1 Answers1

3

C99 says in 7.19.5.3 (fopen), paragraph 6:

When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function [...], and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

Congratulations for discovering this corner case in practice. The library implementation is completely correct, since you violate the shall quoted above.

And by the way, it is not uncommon to read from stderr. This is useful when stdin and stdout are redirected and no terminal is available. Although C99 doesn't guarantee it to be readable, I remember some cases on POSIX-like systems where this had actually been done.

Roland Illig
  • 40,703
  • 10
  • 88
  • 121
  • 1
    I don't see how this addresses the question at all. –  Jul 08 '10 at 19:21
  • It answers the question 99%. Theoretically the "unless" clause at the end may imply that a failed read doesn't count, but I don't think anybody thought of this case, hence it's undefined. – Amnon Jul 08 '10 at 19:38
  • @Amnon It says "When a file is opened with update mode" - what makes you think stderr is opened in that mode? And you cannot call positioning functions on stderr. –  Jul 08 '10 at 19:43
  • `stderr` is one of the three streams that is already opened when `main` starts. To explain the behavior, I assumed that `stderr` had been opened as if by calling `fopen`. I didn't find a reference that reading from a write-only stream leads to undefined behavior, so I happended to read the documentation of `fopen`, and I felt this could explain the behavior well enough. – Roland Illig Jul 08 '10 at 19:52
  • Why shouldn't I be able to call positioning functions on `stderr`? 7.19.9.4p2 explicitly mentions the effect of calling `ftell` on a text stream. – Roland Illig Jul 08 '10 at 19:54
  • @Neil: there's nothing stopping the user from running the program with stderr redirected to a r/w stream. Anyway, I'm now convinced that the code is too borderline (I thought that any sequence of file operations on an valid file handle was defined-- even if it was defined to set error flags). – Amnon Jul 08 '10 at 19:56
  • @Roland text stream != stderr. –  Jul 08 '10 at 20:09