Akim Demaille <akim <at> lrde.epita.fr> writes: > Reading the code, I don't see why the child should be affected here, > but it is.
It is due to a bug in gnulib. | if (pipe_stdin) | if (pipe (ofd) < 0 | || (ofd[1] = fd_safer (ofd[1])) < 0) This has the effect of setting ofd to {1,5} if exactly one of stdin/stdout were closed. Then, in the child: | if (pipe_stdin) | { | close (ofd[0]); | close (ofd[1]); | } we blindly closed both descriptors. This is only safe if BOTH fd's were moved past 2, rather than just ofd[1] (a similar bug exists for ifd). There are several possible fixes (such as being more complex with the posix_spawn fd manipulation, or making the close of ofd[0] conditional on whether it is a standard fd), but I think the simplest is just replacing the existing two calls to pipe/fd_safer with the simpler one-line call to pipe_safer. I'll commit a patch later today, which also adds a pipe-test module using your test-pipe.c as a starting point (but avoiding the use of m4, which is not guaranteed to be available on all client machines of packages using the pipe module). And this gnulib bug means that m4 has a regression in 1.4.13 (which uses create_pipe_in) when compared to 1.4.11 (which used popen) (although in the create_pipe_in case, the bug requires closing 2 of the std descriptors, not just one as in create_pipe_out or create_pipe_bidi): $ echo 'esyscmd(echo hi >&2)dnl' > oops.m4 $ m4-1.4.11 <&- >&- oops.m4 hi $ m4-1.4.13 oops.m4 <&- >&- /bin/m4: esyscmd subprocess failed $ echo $? 0 Even worse, m4 1.4.13 isn't setting the exit status to nonzero on this failure. Looks like I have a reason to release m4 1.4.14 now. -- Eric Blake