From 4a88129ae4332cbf3833c00f79100610ca2e576d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 21 Aug 2013 14:27:30 -0700 Subject: [PATCH] * callproc.c: Fix race that killed background processes. (call_process): New arg TEMPFILE_INDEX. Callers changed. Record deleted process-id in critical section, not afterwards. Don't mistakenly kill process created by a call-process invocation that discards output and does not wait. Fixes: debbugs:15144 --- src/ChangeLog | 8 ++++++++ src/callproc.c | 45 ++++++++++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index cb552c9d9d5..8983b6abd64 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2013-08-21 Paul Eggert + + * callproc.c: Fix race that killed background processes (Bug#15144). + (call_process): New arg TEMPFILE_INDEX. Callers changed. + Record deleted process-id in critical section, not afterwards. + Don't mistakenly kill process created by a call-process invocation + that discards output and does not wait. + 2013-08-21 Dmitry Antipov Fix compilation with GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE diff --git a/src/callproc.c b/src/callproc.c index 2a9162cb5cc..fca4216b5f7 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -102,7 +102,7 @@ enum CALLPROC_FDS }; -static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int); +static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int, ptrdiff_t); /* Block SIGCHLD. */ @@ -248,14 +248,20 @@ usage: (call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS) * report_file_error ("Opening process input file", infile); record_unwind_protect_int (close_file_unwind, filefd); UNGCPRO; - return unbind_to (count, call_process (nargs, args, filefd)); + return unbind_to (count, call_process (nargs, args, filefd, -1)); } /* Like Fcall_process (NARGS, ARGS), except use FILEFD as the input file. + + If TEMPFILE_INDEX is nonnegative, it is the specpdl index of an + unwinder that is intended to remove the input temporary file; in + this case NARGS must be at least 2 and ARGS[1] is the file's name. + At entry, the specpdl stack top entry must be close_file_unwind (FILEFD). */ static Lisp_Object -call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd) +call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, + ptrdiff_t tempfile_index) { Lisp_Object buffer, current_dir, path; bool display_p; @@ -661,7 +667,22 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd) child_errno = errno; if (pid > 0) - synch_process_pid = pid; + { + synch_process_pid = pid; + + if (INTEGERP (buffer)) + { + if (tempfile_index < 0) + record_deleted_pid (pid, Qnil); + else + { + eassert (1 < nargs); + record_deleted_pid (pid, args[1]); + clear_unwind_protect (tempfile_index); + } + synch_process_pid = 0; + } + } unblock_child_signal (); unblock_input (); @@ -1030,7 +1051,7 @@ If you quit, the process is killed with SIGINT, or SIGKILL if you quit again. usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS) */) (ptrdiff_t nargs, Lisp_Object *args) { - struct gcpro gcpro1, gcpro2; + struct gcpro gcpro1; Lisp_Object infile, val; ptrdiff_t count = SPECPDL_INDEX (); Lisp_Object start = args[0]; @@ -1061,8 +1082,7 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r record_unwind_protect_int (close_file_unwind, fd); } - val = infile; - GCPRO2 (infile, val); + GCPRO1 (infile); if (nargs > 3 && !NILP (args[3])) Fdelete_region (start, end); @@ -1079,16 +1099,7 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r } args[1] = infile; - val = call_process (nargs, args, fd); - - if (!empty_input && 4 < nargs - && (INTEGERP (CONSP (args[4]) ? XCAR (args[4]) : args[4]))) - { - record_deleted_pid (synch_process_pid, infile); - synch_process_pid = 0; - clear_unwind_protect (count); - } - + val = call_process (nargs, args, fd, empty_input ? -1 : count); RETURN_UNGCPRO (unbind_to (count, val)); } -- 2.11.4.GIT