diff options
author | Junio C Hamano <gitster@pobox.com> | 2014-09-29 22:17:20 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-09-29 22:17:20 -0700 |
commit | 131f0315c46c30d5a9e6743354808230cf4908c0 (patch) | |
tree | 6ea66a6881020352074d813761e7af5fd0d2ed27 | |
parent | 0bf7dd652cd7b7d3900e6aed73a97cf2c4978fee (diff) | |
parent | 4e6d207c45e6f5c13b38c4a200f0d3339f88ad34 (diff) | |
download | git-131f0315c46c30d5a9e6743354808230cf4908c0.tar.gz |
Merge branch 'pr/use-default-sigpipe-setting'
We used to get confused when a process called us with SIGPIPE
ignored; we do want to die with SIGPIPE when the output is not
read by default, and do ignore the signal when appropriate.
* pr/use-default-sigpipe-setting:
mingw.h: add dummy functions for sigset_t operations
unblock and unignore SIGPIPE
-rw-r--r-- | compat/mingw.h | 7 | ||||
-rw-r--r-- | git.c | 22 | ||||
-rwxr-xr-x | t/t0005-signals.sh | 22 |
3 files changed, 50 insertions, 1 deletions
diff --git a/compat/mingw.h b/compat/mingw.h index df0e3203ab..5e499cfb71 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -69,7 +69,6 @@ struct sigaction { sig_handler_t sa_handler; unsigned sa_flags; }; -#define sigemptyset(x) (void)0 #define SA_RESTART 0 struct itimerval { @@ -116,6 +115,12 @@ static inline int fcntl(int fd, int cmd, ...) } /* bash cannot reliably detect negative return codes as failure */ #define exit(code) exit((code) & 0xff) +#define sigemptyset(x) (void)0 +static inline int sigaddset(sigset_t *set, int signum) +{ return 0; } +#define SIG_UNBLOCK 0 +static inline int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) +{ return 0; } /* * simple adaptors @@ -592,6 +592,26 @@ static int run_argv(int *argcp, const char ***argv) return done_alias; } +/* + * Many parts of Git have subprograms communicate via pipe, expect the + * upstream of a pipe to die with SIGPIPE when the downstream of a + * pipe does not need to read all that is written. Some third-party + * programs that ignore or block SIGPIPE for their own reason forget + * to restore SIGPIPE handling to the default before spawning Git and + * break this carefully orchestrated machinery. + * + * Restore the way SIGPIPE is handled to default, which is what we + * expect. + */ +static void restore_sigpipe_to_default(void) +{ + sigset_t unblock; + + sigemptyset(&unblock); + sigaddset(&unblock, SIGPIPE); + sigprocmask(SIG_UNBLOCK, &unblock, NULL); + signal(SIGPIPE, SIG_DFL); +} int main(int argc, char **av) { @@ -611,6 +631,8 @@ int main(int argc, char **av) */ sanitize_stdfds(); + restore_sigpipe_to_default(); + git_setup_gettext(); trace_command_performance(argv); diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh index 981437b3a8..aeea50c633 100755 --- a/t/t0005-signals.sh +++ b/t/t0005-signals.sh @@ -27,4 +27,26 @@ test_expect_success !MINGW 'signals are propagated using shell convention' ' test_expect_code 143 git sigterm ' +large_git () { + for i in $(test_seq 1 100) + do + git diff --cached --binary || return + done +} + +test_expect_success 'create blob' ' + test-genrandom foo 16384 >file && + git add file +' + +test_expect_success !MINGW 'a constipated git dies with SIGPIPE' ' + OUT=$( ((large_git; echo $? 1>&3) | :) 3>&1 ) + test "$OUT" -eq 141 +' + +test_expect_success !MINGW 'a constipated git dies with SIGPIPE even if parent ignores it' ' + OUT=$( ((trap "" PIPE; large_git; echo $? 1>&3) | :) 3>&1 ) + test "$OUT" -eq 141 +' + test_done |