9

I am unable to find any reference to the specified behavior of fputc() when the stream was created with fopen("/some/path", "r").

I've searched the C11 Draft n1570 pdf looking for any reference with no luck, the fopen() function specification talks about passing unknown characters as the mode parameter which is undefined behavior. But it doesn't say anything about subsequent IO on the created stream.

This is the fwrite() function specification

7.21.8.2 The fwrite function

Synopsis

  1. #include <stdio.h>
    size_t fwrite(const void * restrict ptr,
        size_t size, size_t nmemb, FILE * restrict stream);
    

Description

  1. The fwrite function writes, from the array pointed to by ptr, up to nmemb elements whose size is specified by size, to the stream pointed to by stream. For each object, size calls are made to the fputc function, taking the values (in order) from an array of unsigned char exactly overlaying the object. The file position indicator for the stream (if defined) is advanced by the number of characters successfully written. If an error occurs, the resulting value of the file position indicator for the stream is indeterminate.

Returns

  1. The fwrite function returns the number of elements successfully written, which will be less than nmemb only if a write error is encountered. If size or nmemb is zero, fwrite returns zero and the state of the stream remains unchanged.

It takes us to the fputc() function, so

7.21.7.3 The fputc function

Synopsis

  1. #include <stdio.h>
    int fputc(int c, FILE *stream);
    

Description

  1. The fputc function writes the character specified by c (converted to an unsigned char) to the output stream pointed to by stream, at the position indicated by the associated file position indicator for the stream (if defined), and advances the indicator appropriately. If the file cannot support positioning requests, or if the stream was opened with append mode, the character is appended to the output stream.

Returns

  1. The fputc function returns the character written. If a write error occurs, the error indicator for the stream is set and fputc returns EOF.

As you can see, there is no explanation of the situation I am concerned about.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • 3
    If this doesn't fall under the "omission" wording in section 4 clause 2 ("Undefined behaviour is otherwise indicated in this International standard by the words "undefined behaviour" or by the omission of any explicit definition of behaviour."), then this is might be a shortcoming in the definition of files and streams (7.21.1, 7.21.2). I can't see any relevant definition for `fopen`'s "open a file for reading" wording that would define how non-reading operations behave with the resulting stream. I'd think the behaviour *should* be that they would count as write errors (see cited clauses 3). –  Nov 24 '15 at 09:06
  • @iharob *... It happened to me that I accidentally fprintf()ed to a stream opened with "r", it worked...* I'm curious as to the details where that "worked". I'd think the underlying `open()` (or equivalent) call would be done with flags to match `fopen( "/some/path", "r" );`. – Andrew Henle Nov 24 '15 at 20:53
  • @iharob - Thanks for clarifying that. I was wondering about the platform and/or code where `fputc()` would "work" on a read-only stream given how you state you created it with `fopen()` on a normal file. A strict reading of the POSIX standard listed in the answer doesn't prevent the underlying file descriptor being open for writing even for a read-only stream (perhaps via `fdopen()`, for example). – Andrew Henle Nov 24 '15 at 22:32

1 Answers1

5

This is undefined behavior, the standard does not define the behavior if it is not an output stream. This is from section 4 Conformance which says (emphasis mine):

If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtime constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe ‘‘behavior that is undefined’’.

Now of course this does not prevent the implementation from further defining the behavior and we can see that for POSIX fputc indicates this error through EBADF:

[EBADF]

[CX] [Option Start] The file descriptor underlying stream is not a valid file descriptor open for writing.

Note CX denotes an extension to the C standard.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740