Skip to content

os/exec: broken pipe writing into djpeg  #9173

@bradfitz

Description

@bradfitz
Go's os/exec seems to have a problem piping into the djpeg program.

To reproduce, at least on Linux:

1) $ apt-get install libjpeg-turbo-progs
2) Download the attached image (7.8 MB, which seems to matter, or its JPEG structure
matters)
3) Run boat.go: http://play.golang.org/p/cHra0dvPr6

ante:tmp $ go run boat.go
2014/11/26 14:26:46 Process state: exit status 0 (success = true)
2014/11/26 14:26:46 Stdout: 11943953 bytes
2014/11/26 14:26:46 Stderr: ""
2014/11/26 14:26:46 cmd.Wait = write |1: broken pipe

Of note:

The djpeg process ends successfully, and outputs its resultant image to stdout.

But djpeg seems to end before reading all of its input, causing a SIGPIPE to the
goroutine trying to write all the data to it. strace says:

21770 <... write resumed> )             = 4096
21772 read(5,  <unfinished ...>
21770 write(1,
"2\10\0002\10\0007\t\0007\t\0008\t\0007\10\0009\n\0008\7\0008\7\0<\t\0=\n\0>\v\0@\f\0?\v\0E\r\0F\16\0J\16\0M\16\0T\22\0Z\24\0]\24\0]\23\0^
\23\0f\30\0o\36\0n\32\0{$\0\205)\0\2212\0\236<\0\2369\0\2405\0\2423\0\254:\0\272C\0\317W\0\351m\0\342g\0\344h\0\336e\0\334d\0\356w\0\363}\0\377\207\0\377
\213\0\377\220\0\377\221\0\377\222\0\377\221\0\377\224\0\377\224\0\377\220\0\377\217\0\377\223\0\377\227\0\377\234\0\377\244\0\377\264\0\377\276\0\377\30
5\0\377\311\0\377\312\0\377\301\0\377\266\0\377\243\0\377\226\0\377\201"..., 4096
<unfinished ...>
21772 <... read resumed>
"\4\v\2\5\v\2\5\v\2\5\v\2\5\n\1\4\n\1\4\v\0\4\v\0\4\f\1\5\r\2\6\17\5\6\21\5\7\21\5\7\23\4\7\22\3\10\22\3\10\22\3\10\21\2\7\21\2\
7\21\2\7\17\3\7\20\4\10\17\5\6\20\6\7\20\6\7\20\6\7\20\6\7\20\6\7\22\6\6\22\6\6\24\6\6\24\6\6\22\6\6\23\7\7\21\5\7\20\4\6\17\3\5\17\3\5\r\3\4\f\2\3\r\3\4
\f\2\3\v\2\3\n\1\2\n\1\2\n\1\2\v\2\3\f\3\4\f\3\4\r\4\5\17\5\6\20\6\7\22\6\6\24\6\6\25\7\6\31\7\7\33\10\4\37\7\5!\10\3#\7\3&\t\3'\10\3*\t\4-\n\6,\t\5*\t\4
'"..., 4840960) = 4096
21770 <... write resumed> )             = 4096
21768 <... select resumed> )            = 0 (Timeout)
21770 write(1, "\7\3\32\7\3\31\7\3\31\7\3\27\10\5\27\10\5", 17 <unfinished
...>
21772 read(5,  <unfinished ...>
21770 <... write resumed> )             = 17
21772 <... read resumed>
"2\10\0002\10\0007\t\0007\t\0008\t\0007\10\0009\n\0008\7\0008\7\0<\t\0=\n\0>\v\0@\f\0?\v\0E\r\0F\16\0J\16\0M\16\0T\22\0Z\24\0]\2
4\0]\23\0^\23\0f\30\0o\36\0n\32\0{$\0\205)\0\2212\0\236<\0\2369\0\2405\0\2423\0\254:\0\272C\0\317W\0\351m\0\342g\0\344h\0\336e\0\334d\0\356w\0\363}\0\377
\207\0\377\213\0\377\220\0\377\221\0\377\222\0\377\221\0\377\224\0\377\224\0\377\220\0\377\217\0\377\223\0\377\227\0\377\234\0\377\244\0\377\264\0\377\27
6\0\377\305\0\377\311\0\377\312\0\377\301\0\377\266\0\377\243\0\377\226\0\377\201"...,
4836864) = 4113
21770 exit_group(0)                     = ?
21772 read(5,  <unfinished ...>
21768 select(0, NULL, NULL, NULL, {0, 20} <unfinished ...>
21772 <... read resumed> "", 4832751)   = 0
21771 <... write resumed> )             = 16384
21772 --- SIGCHLD (Child exited) @ 0 (0) ---
21771 --- SIGPIPE (Broken pipe) @ 0 (0) ---
21772 rt_sigreturn(0x11 <unfinished ...>
21771 rt_sigreturn(0xd <unfinished ...>
21772 <... rt_sigreturn resumed> )      = 0
21771 <... rt_sigreturn resumed> )      = 16384
21769 <... read resumed> "", 512)       = 0
21772 futex(0xc208020b58, FUTEX_WAIT, 0, NULL <unfinished ...>
21771 write(4,
"\320\272\232\376k\3375]\303\23\222s\232\350-\265\375B\35>8e-*\216\273\2115\340Q\251\316\365=\372\270w\rN\206\312\366K\233r\321)R\6p\5G|\3
42\342\300\227\373\303\257=k*\362J\3461\2475Qhqo\2435\345\336-\321\244'?*\212\307}\"t\274uTl\251
\203\317\326\276S\33\213\214*8\263\356\362\374\33\2355;\
31\222Gq\25\323\0\33\203\3152k\233\270\234lc\327\247\255c\32\221\234N\207Ft\246\333?\377\325\374\264\203R\270\23\3(\301\34\327Og\251\31\\n\373\247\257\32
6\277\25\305PR\367\217\333\360\265\332vf\270\322WUF).$\7\345^\231\253\326\336\27\271\213L/\""...,
16384 <unfinished ...>
21769 futex(0xc208020458, FUTEX_WAIT, 0, NULL <unfinished ...>
21771 <... write resumed> )             = -1 EPIPE (Broken pipe)
21768 <... select resumed> )            = 0 (Timeout)
21771 --- SIGPIPE (Broken pipe) @ 0 (0) ---
21768 futex(0x593ac0, FUTEX_WAIT, 0, {60, 0} <unfinished ...>
21771 rt_sigreturn(0xd <unfinished ...>
21767 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0,
{ru_utime={0, 496000}, ru_stime={0, 36000}, ...}) = 21770
21771 <... rt_sigreturn resumed> )      = -1 EPIPE (Broken pipe)


... note you can see the djpeg exit_group(0), then the SIGPIPE and the wait4 call return.

We can work around this in Go by knowing that this program does this and ignoring the
return value from cmd.Run() or cmd.Wait() and only looking at the
cmd.ProcessState.Success. But is that best?

Or are we doing something wrong?

Should Go ignore the Stdin copy error if the program ended successfully?

Camlistore bug: http://camlistore.org/issue/550
Upstream djpeg bug from Mathieu: http://sourceforge.net/p/libjpeg-turbo/bugs/80/

Attachments:

  1. PA190470.JPG (7781878 bytes)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions