Skip to content

io/ioutil hangs with too big output from os/exec stderr and stdout pipes  #16787

@marek-polewski

Description

@marek-polewski

What version of Go are you using (go version)?

  • 1.6.2
  • 1.6.3
  • 1.7

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/usr/src/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build726085245=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"

What did you do?

Let's use exec.Command to catch both stdout and stderr.
One of the pipes gets around 82855 chars ( magic number is between 65536 - 131072 ). Now ioutil.ReadAll will hang if I try to read from the second pipe before the first one ( full one ).

Here is the simplified example that only cat a file.
Original code was checking error and there is none of them there:

package main

import (
    "fmt"
    "io/ioutil"
    "os/exec"
)

func main() {
    cmd := exec.Command("cat", "file")
    stdout, _ := cmd.StdoutPipe()
    stderr, _ := cmd.StderrPipe()
    cmd.Start()
    be, _ := ioutil.ReadAll(stderr)
    bo, _ := ioutil.ReadAll(stdout)

    cmd.Wait()
    fmt.Printf("%d be size \n", len(be))
    fmt.Printf("%d bo size \n", len(bo))
}

If order of ReadAll would be opposite, this example will run correctly.

What did you expect to see?
Error or information in docs that those pipes should be handled differently.

What did you see instead?
Binary never exits.

Strace :

[pid 18746] select(0, NULL, NULL, NULL, {0, 20}) = 0 (Timeout)
[pid 18746] select(0, NULL, NULL, NULL, {0, 20}) = 0 (Timeout)
[pid 18746] select(0, NULL, NULL, NULL, {0, 20}) = 0 (Timeout)
[pid 18746] select(0, NULL, NULL, NULL, {0, 20}) = 0 (Timeout)
[pid 18746] futex(0xc420056110, FUTEX_WAKE, 1 <unfinished ...>
[pid 18750] <... futex resumed> )       = 0
[pid 18746] <... futex resumed> )       = 1
[pid 18750] futex(0xc420056110, FUTEX_WAIT, 0, NULL <unfinished ...>
[pid 18746] select(0, NULL, NULL, NULL, {0, 20}) = 0 (Timeout)
[pid 18746] futex(0x53fc98, FUTEX_WAIT, 0, {60, 0}

) = -1 ETIMEDOUT (Connection timed out)
[pid 18746] select(0, NULL, NULL, NULL, {0, 20}) = 0 (Timeout)
[pid 18746] futex(0x53fc98, FUTEX_WAIT, 0, {60, 0}

Stack:

goroutine 1 [syscall, locked to thread]:
syscall.Syscall(0x0, 0x6, 0xc829b06000, 0x200, 0x0, 0xc82685daa0, 0x60)
    /usr/local/go/src/syscall/asm_linux_amd64.s:18 +0x5
syscall.read(0x6, 0xc829b06000, 0x200, 0x200, 0xc829b06200, 0x0, 0x0)
    /usr/local/go/src/syscall/zsyscall_linux_amd64.go:783 +0x5f
syscall.Read(0x6, 0xc829b06000, 0x200, 0x200, 0xc829b06000, 0x0, 0x0)
    /usr/local/go/src/syscall/syscall_unix.go:161 +0x4d
os.(*File).read(0xc82a0faac8, 0xc829b06000, 0x200, 0x200, 0x7f4700000001, 0x0, 0x0)
    /usr/local/go/src/os/file_unix.go:228 +0x53
os.(*File).Read(0xc82a0faac8, 0xc829b06000, 0x200, 0x200, 0x200, 0x0, 0x0)
    /usr/local/go/src/os/file.go:95 +0x8a
bytes.(*Buffer).ReadFrom(0xc82026e8a0, 0x7f47d95dc1f8, 0xc82a0faac8, 0x0, 0x0, 0x0)
    /usr/local/go/src/bytes/buffer.go:176 +0x23f
io/ioutil.readAll(0x7f47d95dc1f8, 0xc82a0faac8, 0x200, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/local/go/src/io/ioutil/ioutil.go:33 +0x156
io/ioutil.ReadAll(0x7f47d95dc1f8, 0xc82a0faac8, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/local/go/src/io/ioutil/ioutil.go:42 +0x51

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions