Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does POSIX mean when it says stderr is expected to be open for reading and writing?

POSIX's page on stderr, stdin, stdout - standard I/O streams says this:

The stderr stream is expected to be open for reading and writing.

How strong is "expected to be"? Is violating it Undefined Behavior? And whose responsibility is it, the system's or the application's?

Consider this program:

#include <stdio.h>

int main(void) {
    printf("feof is %d and ferror is %d\n", feof(stderr), ferror(stderr));
    printf("fgetc is %d\n", fgetc(stderr));
    printf("feof is %d and ferror is %d\n", feof(stderr), ferror(stderr));
}

When I run that without redirecting stderr (so it's pointing to my terminal just like stdin is), it immediately outputs this without waiting for any input:

feof is 0 and ferror is 0
fgetc is -1
feof is 0 and ferror is 1

Does that mean my system isn't POSIX-compliant?

Also, if it's my responsibility, then suppose I have a file with permissions 620, and that I'm in the group but not the owner. Does this mean that someprogram 2>saidfile is Undefined Behavior, since you couldn't read from stderr no matter what in that case?

like image 238
Joseph Sible-Reinstate Monica Avatar asked May 27 '20 21:05

Joseph Sible-Reinstate Monica


People also ask

What is stderr and stdout?

Your screen is the standard output, sometimes denoted as stdout . By default, commands take input from the standard input and send the results to standard output. Standard error, sometimes denoted as stderr, is where error messages go. By default, this is your screen.

Where is stderr defined?

Stderr, also known as standard error, is the default file descriptor where a process can write error messages. In Unix-like operating systems, such as Linux, macOS X, and BSD, stderr is defined by the POSIX standard. Its default file descriptor number is 2. In the terminal, standard error defaults to the user's screen.

What is stdin stdout stderr in C?

In computer programming, standard streams are interconnected input and output communication channels between a computer program and its environment when it begins execution. The three input/output (I/O) connections are called standard input (stdin), standard output (stdout) and standard error (stderr).


2 Answers

The Austin Group (the joint working group that maintains the POSIX standard) discussed the defect that was reported about the "expected to be" wording during the 2020-12-07 and 2020-12-10 telecons and agreed that the wording in POSIX Issue 7 (2018 edition) is problematic. The wording will be changed in the next version of the POSIX standard as follows (copied from the bug comment):

On page 65 before line 1912 (XBD "interactive shell") insert a new definition and renumber the remaining:

Interactive Device

A terminal device.

Note: This definition is intended to align with the ISO C standard's use of "interactive device".

On page 496 lines 17224-17228 (XSH 2.5 Standard I/O Streams) and page 2017 lines 64723-64727 (XSH stderr, stdin, stdout DESCRIPTION) change:

At program start-up, three streams shall be predefined and need not be opened explicitly: standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). When opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.

to:

At program start-up, three streams shall be predefined and already open: stdin (standard input, for conventional input) for reading, stdout (standard output, for conventional output) for writing, and stderr (standard error, for diagnostic output) for writing. When opened, stderr shall not be fully buffered; stdin and stdout shall be fully buffered if and only if [CX]the file descriptor associated with the stream is determined not to be associated with an interactive device.[/CX]

On page 2017 line 64733 (XSH stdin DESCRIPTION), change:

The stderr stream is expected to be open for reading and writing.

to:

These file descriptors are often all associated with a single open file description which has access mode O_RDWR (e.g., in the case of a terminal device for a login shell). However, the stderr, stdin, and stdout streams need not be opened for both reading and writing at program start-up in this case.

On page 2017 line 64747 (stdin SEE ALSO) add isatty().

Special thanks to Rich Felker for reporting the defect.

like image 172
Richard Hansen Avatar answered Oct 19 '22 17:10

Richard Hansen


POSIX elaborates on this in the specification for execve:

If file descriptor 0, 1, or 2 would otherwise be closed after a successful call to one of the exec family of functions, implementations may open an unspecified file for the file descriptor in the new process image. If a standard utility or a conforming application is executed with file descriptor 0 not open for reading or with file descriptor 1 or 2 not open for writing, the environment in which the utility or application is executed shall be deemed non-conforming, and consequently the utility or application might not behave as described in this standard.

For your own applications, they should be prepared for the possibility that the implementation opens new stdin/out/err for them if they try to exec with any of them closed, and can set their own rules (including deeming it a contract violation resulting in catastrophically wrong behavior) for how they handle it if the standard file descriptors are not open when they start.

For standard utilities, the above text covers it.

The document you cited just specifies that they're associated with those file descriptors. I agree it's not sufficiently clear, but the reasonable interpretation would be that, if the corresponding file descriptors are not open or not open for the appropriate modes at application entry, the results are those specified for that condition (typically EBADF) under the relevant functions. For example, fgetc specifies:

[EBADF]

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

Regarding the "expected to be" text:

The stderr stream is expected to be open for reading and writing.

I don't think "expected to be" is defined anywhere in the standard. However, the word stream is used here, not file/file-descriptor, so I would read that as the FILE mode (as in fopen modes) for the stderr stream is such that neither read nor write functions on it produce undefined behavior as long as the rules about switching between them are honored. Without this text, e.g. in plain without POSIX on top, fgetc(stderr) would potentially produce undefined behavior.

like image 23
R.. GitHub STOP HELPING ICE Avatar answered Oct 19 '22 17:10

R.. GitHub STOP HELPING ICE