[go: up one dir, main page]

Menu

#368 joe causes subprocesses to ignore SIGPIPE, causing lockup

v4.4
closed-fixed
nobody
None
v4.3
5
2018-01-10
2017-04-03
No

joe, as of at least version 4.2, causes processes it creates to ignore SIGPIPE.
Why is this a bug? Consider yes, a program that repeats lines until terminated by a signal. Type ^K R and try something like:
!yes | head -n 10
Expected behaviour: ten lines containing y are inserted.
Actual behaviour: yes ignores the SIGPIPE sent by head when it's got its ten lines, so yes never stops and simply keeps writing y into the void forever, locking up joe in the process. You now have to open another terminal and kill joe.

Proof of cause: type ^K R and type:
!sh -c 'kill -s PIPE $$; echo IGNORED'
The word IGNORED is inserted into the document.

Discussion

  • Martijn Dekker

    Martijn Dekker - 2017-04-03

    Um, killing 'yes' instead of 'joe' from that other terminal might be a wiser course of action. Duh. Nonetheless, my report stands.

     
  • John J. Jordan

    John J. Jordan - 2017-04-03

    What environment are you using? I can confirm your second repro does write "IGNORED", and it looks like 3.7 exhibits this behavior as well. But I was unable to get a runaway 'yes' process or any sort of lockup.

     
  • Joe Allen

    Joe Allen - 2017-05-01

    Maybe this is shell dependant? JOE disables SIGPIPE, but maybe some shells re-enable it for their sub-processes.

    Which shell are you using?

     
  • Martijn Dekker

    Martijn Dekker - 2017-10-01

    I'm using bash 3.2.57 on Mac OS X 10.11 (El Capitan) which is also the default /bin/sh.

     
  • Martijn Dekker

    Martijn Dekker - 2017-10-01

    I cannot reproduce this on Linux using the 'yes' command; evidently, Linux 'yes' also checks if writing to stdout succeeds and exits if it doesn't, whereas 'yes' on the Mac just keeps trying forever and depends on SIGPIPE to be terminated.

    But the following does reproduce the bug on Linux. Type ^K R and type:

    !sh -c 'while :; do echo y; done' | head -n 10
    

    and watch your terminal fill with an endless succession of "broken pipe" errors from sh, until you manually kill that sh command from another terminal.

     

    Last edit: Martijn Dekker 2017-10-01
  • Joe Allen

    Joe Allen - 2017-12-22

    This is now fixed in Mercurial.

    The issue was with popen only, shell windows already did the right thing.

    Interestingly, python had this exact same problem.

    I'm not entirely happy with the solution: I've surrounding the call to popen with signal(SIGPIPE, SIG_DFL) and signal(SIGPIPE_SIG_IGN); This would certainly lead to a race condition if JOE was multi-threaded, and even though it isn't, I'm not 100% sure that there is no issue. Probably better to make my own version of popen that restores the default signal handling after the fork(). Actually I think libc should be doing that.

     
  • Joe Allen

    Joe Allen - 2017-12-22

    Well I'm finding that I want the default handling for SIGINT as well, getting closer to rewriting popen().

     
  • Joe Allen

    Joe Allen - 2017-12-22

    Yeah, I've implemented the custom popen and now you can hit ^C in a stuck shell command, for example try this:

    ^K R ! while true; do echo hi 1>&2; echo hi; sleep 1; done

    You can now hit ^C to terminate the loop.

     
  • Joe Allen

    Joe Allen - 2018-01-10
    • status: open --> closed-fixed
     

Log in to post a comment.