Skip to content

Cannot read from STDIN with read_to_string if reading before piping Rust program writes to STDOUT in another Rust program #141714

Open
@kiseitai3

Description

@kiseitai3

Using std::io::read_to_string, stdin().read_to_string, or stdin().read_to_end() blocks on nonexisting buffer and ignores incoming buffer. This happens if I pipe a program compiled with Rust to itself. For example, ./target/debug/rumtk-v2-interface --port 55556 --local | ./target/debug/rumtk-v2-interface --daemon --outbound --port 55555 --local. Reading using the buffer methods work well assuming I am able to piece together the buffer before converting to UTF-8 String. Flushing STDOUT from the piping program does not force the STDIN read to succeed.

I tried this code. Only read_some_stdin works:

pub fn read_stdin_() -> RUMResult<RUMString> {
        let mut stdin_handle = stdin().lock();
        let has_data = match stdin_handle.has_data_left() {
            Ok(flag) => flag,
            Err(e) => return Err(format_compact!("No data in STDIN: {}", e)),
        };
        println!("{}", &has_data);
        if has_data {
            match std::io::read_to_string(stdin_handle) {
                Ok(s) => {
                    println!("{}", &s);
                    Ok(s.into())
                }
                Err(e) => Err(format_compact!("Error reading from STDIN: {}", e)),
            }
        } else {
            Ok(RUMString::default())
        }
    }

    pub fn read_stdin() -> RUMResult<RUMString> {
        let mut buf: Vec<u8> = Vec::new();
        match stdin().read_to_end(&mut buf) {
            Ok(s) => {
                println!("{}", &s);
                Ok(buf.to_rumstring())
            }
            Err(e) => Err(format_compact!("Error reading from STDIN: {}", e)),
        }
    }

    pub fn read_some_stdin(input: &mut StdinLock) -> RUMResult<RUMString> {
        let mut buf: [u8; 1024] = [0; 1024];
        match input.read_exact(&mut buf) {
            Ok(_) => Ok(buf.as_slice().to_rumstring()),
            Err(e) => Err(format_compact!(
                "Error reading 1024 bytes from STDIN: {}",
                e
            )),
        }
    }

I expected to see this happen: Have the stdout buffer pass to the stdin buffer of a Rust program piped to itself via the terminal. I expected to receive the buffer when reading or at least get an error I could handle/ignore if a read is empty.

Instead, this happened: Nothing happens even though program can read from stdin and write to stdout in isolated tests.

This is similar to forum? issue: [How to handle Stdin hanging when there is no input](https://users.rust-lang.org/t/how-to-handle-stdin-hanging-when-there-is-no-input/93512).

I am currently not sure why the issue happened after looking at the std library's STDIN source code, but I am not experienced in the codebase so it could be a me issue.

Image

Thanks for your work on Rust and thank you for your help!

Meta

rustc --version --verbose:

rustc 1.86.0-nightly (4a4309466 2025-02-02)
binary: rustc
commit-hash: 4a43094662727040d8522163f295b19d1aed0e49
commit-date: 2025-02-02
host: x86_64-unknown-linux-gnu
release: 1.86.0-nightly
LLVM version: 19.1.7

Backtrace

<backtrace>

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions