Stdout is closed but a write_all to stdout succeeds

Hi,

I wrote this Program that closes the StdOut FD and after that tries to write to StdOut.
My question is why the match statement chooses the Ok(_) branch.

If I run the program with strace I get this output:

write(1, "test", 4)                     = -1 EBADF (Bad file descriptor)
write(2, "Success\n", 8)                = 8

Shouldn't rust execute the Err branch? What am I missing?

The source

use std::io::Write;
use std::os::unix::io::{AsRawFd, FromRawFd};

fn main() {
    let id = std::io::stdout().as_raw_fd();
    let f = unsafe {
        std::fs::File::from_raw_fd(id);
    };
    drop(f);

    let out = std::io::stdout();
    {
        let mut out = out.lock();
        out.write_all(b"test").unwrap();
        let out_res = out.flush();
        match out_res {
            Ok(_) => eprintln!("Success"),
            Err(_) => eprintln!("Failed"),
        }
    }
}

This is an explicit design decision -- see RFC 1014.

1 Like

Ok. That makes sense. But wouldn't this be handeld in the print! macro and not in the Write trait implementation?

Also the Doc states

Macro [std]::[println]

Panics if writing to io::stdout fails.

I suppose this could have been done only for the macros, but the design given in the RFC was to hide this within io::stdout et al. It's not for all Write use, just for these special file handles.

The macro panic you've quoted never occurs for EBADF, because io::stdout doesn't fail for that.

1 Like