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

Closed
@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

    A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions