-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Description
Consider https://gist.github.com/felixge/452a5a192e217a2a51c0
I get a similar stack trace:
goroutine 1 [chan receive]:
os/exec.(*Cmd).Wait(0xc82008a000, 0x0, 0x0)
/usr/lib/go/src/os/exec/exec.go:385 +0x2c9
os/exec.(*Cmd).Run(0xc82008a000, 0x0, 0x0)
/usr/lib/go/src/os/exec/exec.go:258 +0x64
os/exec.(*Cmd).CombinedOutput(0xc82008a000, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/lib/go/src/os/exec/exec.go:424 +0x310
main.main()
/home/tycho/bug.go:22 +0x130
goroutine 6 [syscall]:
syscall.Syscall(0x0, 0x4, 0xc820090000, 0x200, 0x0, 0x0, 0x40eea9)
/usr/lib/go/src/syscall/asm_linux_amd64.s:18 +0x5
syscall.read(0x4, 0xc820090000, 0x200, 0x200, 0x40f078, 0x0, 0x0)
/usr/lib/go/src/syscall/zsyscall_linux_amd64.go:783 +0x5f
syscall.Read(0x4, 0xc820090000, 0x200, 0x200, 0xc82002e4e8, 0x0, 0x0)
/usr/lib/go/src/syscall/syscall_unix.go:160 +0x4d
os.(*File).read(0xc820030038, 0xc820090000, 0x200, 0x200, 0xc820090000, 0x0, 0x0)
/usr/lib/go/src/os/file_unix.go:211 +0x53
os.(*File).Read(0xc820030038, 0xc820090000, 0x200, 0x200, 0x0, 0x0, 0x0)
/usr/lib/go/src/os/file.go:95 +0x8a
bytes.(*Buffer).ReadFrom(0xc82001a150, 0x7fa3eff92210, 0xc820030038, 0x0, 0x0, 0x0)
/usr/lib/go/src/bytes/buffer.go:173 +0x23f
io.copyBuffer(0x7fa3eff921c0, 0xc82001a150, 0x7fa3eff92210, 0xc820030038, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/lib/go/src/io/io.go:375 +0x180
io.Copy(0x7fa3eff921c0, 0xc82001a150, 0x7fa3eff92210, 0xc820030038, 0x0, 0x0, 0x0)
/usr/lib/go/src/io/io.go:351 +0x64
os/exec.(*Cmd).writerDescriptor.func1(0x0, 0x0)
/usr/lib/go/src/os/exec/exec.go:232 +0x8b
os/exec.(*Cmd).Start.func1(0xc82008a000, 0xc82000e300)
/usr/lib/go/src/os/exec/exec.go:340 +0x1d
created by os/exec.(*Cmd).Start
/usr/lib/go/src/os/exec/exec.go:341 +0x96d
which for me is roughly:
Line 340 in c4fa25f
| c.errch <- fn() |
Based on a cursory glance through the code, it seems like what is happening is that the std{in,out,err} reading/writing goroutines are blocking on reading the stdin of the process, which isn't closed when the child exits, because the grandchild shares the same fds (and doesn't close them). Wait() attempts to address this with a call to closeDescriptors, but it is after a blocking wait on the goroutines exiting, so it doesn't work either.
The behavior I'd expect is that CombinedOutput() reports exactly what the child task printed, and returns when it exits. At least in the example above, I think it can be resolved by closing the stdin fd for the child once the child exits (but before waiting on the goroutines). However, I haven't tried it and I can imagine other cases where it would still hang.