Skip to content

os/exec: close read end of stdout/stderr pipe when copy loop stops #10400

@pstibrany

Description

@pstibrany

Writer set to exec.Cmd.Stdout (or Stderr) may fail. When that happens, underlying pipe is not closed, and command continues to run without noticing that something is wrong.

Here is an example. This little program starts "ls -lR /", which (usually) runs for a long time and produces lot of output. When our brokenWriter returns error, ls command continues to run. Buffer associated with the pipe in the kernel eventually gets filled, which in turn blocks ls, which will then never finish.

I think the solution is to close underlying pr pipe when goroutine created by Cmd.writerDescriptor detects error, similar to what goroutine in stdin method does

package main

import "os"
import "os/exec"
import "io"
import "log"
import "fmt"

type brokenWriter struct {
    w io.Writer
    c int
}

func (bw *brokenWriter) Write(data []byte) (int, error) {
    if bw.c > 0 {
        bw.c = bw.c - 1
        return bw.w.Write(data)
    }
    log.Println("returning error from broken writer")
    return 0, fmt.Errorf("broken writer")
}

func main() {
    cmd := exec.Command("ls", "-lR", "/")

    cmd.Stdout = &brokenWriter{os.Stdout, 1}

    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions