Writing large inputs to STDIN of a child process fails

I have the following program that attempts to spawn a new process on Linux and write a bunch of stuff into the child process via STDIN.

use std::io::Write;
use std::process::{Command, Stdio};

fn gpg_decrypt(file: Vec<u8>) -> Result<(), ()> {
    println!("start");
    let mut proc = Command::new("gpg")
        .args(&[
            "--quiet",
            "--output",
            "-",
            "--trust-model",
            "always",
            "--decrypt",
        ])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .map_err(|e| {
            eprintln!("error spawning process: {}", e);
        })?;

    proc.stdin
        .take()
        .unwrap()
        .write_all(file.as_slice())
        .map_err(|e| {
            eprintln!("error writing to child process: {}", e);
        })?;

    println!("xxx");
    
    let output = proc.wait_with_output().map_err(|e| {
        eprintln!("error getting output: {}", e);
    })?;

    println!("output: {:?}", output);
    Ok(())
}

fn main() {
    let bytes = std::fs::read("foo.tar.gpg").unwrap();
    gpg_decrypt(bytes).unwrap();
    println!("Hello, world!");
}

The program does not work when a 600K file is sent to STDIN. It also does not work if I attempt to chunk the writes as follows:

    {
        let mut total = 0;
        let stdin = proc.stdin.as_mut().unwrap();
        for c in file.as_slice().chunks(1024) {
            println!("total: {}", total);
            stdin
                .write_all(c)
                .map_err(|e| {
                    eprintln!("error writing to child process: {}", e);
                })?;
            stdin.flush().unwrap();
            total += 1024;
        }

Running the program under strace tells me that the write hangs after a certain limit.

Is there anything I am doing wrong?

Can you be more specific about how it doesn’t work? In particular, does it emit any kind of error, terminate unexpectedly, or hang forever?

One potential problem is that you’re not reading the child’s output as you’re giving it the input data. If it’s unable to write output due to a full pipe, it will probably stop accepting input until the situation is resolved. Your program then blocks trying to write into itsfull input buffer, and you have a deadlock: Each process is waiting for the other to consume some data from the pipe buffer before continuing.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.