]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 63157] Ensure temporary files are removed when signaled
authorPaul Smith <psmith@gnu.org>
Sat, 15 Oct 2022 20:34:54 +0000 (16:34 -0400)
committerPaul Smith <psmith@gnu.org>
Sat, 15 Oct 2022 22:39:32 +0000 (18:39 -0400)
Original patch from Dmitry Goncharov <dgoncharov@users.sf.net>.
When handling a fatal signal ensure the temporary files for
stdin and the jobserver fifo (if in use) are deleted.

* src/makeint.h (temp_stdin_unlink): Declare a new method.
* src/main.c (temp_stdin_unlink): Delete the stdin temporary file
if it exists.  If the unlink fails and we're not handling a signal
then show an error.
(main): Call temp_stdin_unlink() instead of unlinking by hand.
* src/commands.c (fatal_error_signal): Invoke cleanup methods if
we're handling a fatal signal.
* tests/scripts/features/output-sync: Test signal handling during
output sync and jobserver with FIFO.
* tests/scripts/features/temp_stdin: Test signal handling when
makefiles are read from stdin.

src/commands.c
src/main.c
src/makeint.h
tests/scripts/features/output-sync
tests/scripts/features/temp_stdin

index 13d98ff96272032cb25bf112a2ba8b3e34fcfdd0..4b8fda51b4154d0830e6325c59fe2b99178f8626 100644 (file)
@@ -16,6 +16,7 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "makeint.h"
 #include "filedef.h"
+#include "os.h"
 #include "dep.h"
 #include "variable.h"
 #include "job.h"
@@ -532,6 +533,10 @@ fatal_error_signal (int sig)
      It is blocked now while we run this handler.  */
   signal (sig, SIG_DFL);
 
+  temp_stdin_unlink ();
+  osync_clear ();
+  jobserver_clear ();
+
   /* A termination signal won't be sent to the entire
      process group, but it means we want to kill the children.  */
 
index afca065647a8db9d03758996322b837b1ff7361c..05b11c6388d8df1aaad65539af625dfe6426e38d 100644 (file)
@@ -1137,6 +1137,23 @@ reset_jobserver (void)
   jobserver_auth = NULL;
 }
 
+void
+temp_stdin_unlink ()
+{
+  /* This function is called from a signal handler.  Keep async-signal-safe.
+     If there is a temp file from reading from stdin, get rid of it.  */
+  if (stdin_offset >= 0)
+    {
+      const char *nm = makefiles->list[stdin_offset];
+      int r = 0;
+
+      stdin_offset = -1;
+      EINTRLOOP(r, unlink (nm));
+      if (r < 0 && errno != ENOENT && !handling_fatal_signal)
+        perror_with_name (_("unlink (temporary file): "), nm);
+    }
+}
+
 #ifdef _AMIGA
 int
 main (int argc, char **argv)
@@ -2776,9 +2793,7 @@ main (int argc, char **argv, char **envp)
 #endif
           jobserver_post_child(1);
 
-          /* Get rid of any stdin temp file.  */
-          if (stdin_offset >= 0)
-            unlink (makefiles->list[stdin_offset]);
+          temp_stdin_unlink ();
 
           _exit (127);
         }
@@ -2804,15 +2819,7 @@ main (int argc, char **argv, char **envp)
         }
     }
 
-  /* If there is a temp file from reading a makefile from stdin, get rid of
-     it now.  */
-  if (stdin_offset >= 0)
-    {
-      const char *nm = makefiles->list[stdin_offset];
-      if (unlink (nm) < 0 && errno != ENOENT)
-        perror_with_name (_("unlink (temporary file): "), nm);
-      stdin_offset = -1;
-    }
+  temp_stdin_unlink ();
 
   /* If there were no command-line goals, use the default.  */
   if (goals == 0)
@@ -3731,13 +3738,7 @@ die (int status)
         print_version ();
 
       /* Get rid of a temp file from reading a makefile from stdin.  */
-      if (stdin_offset >= 0)
-        {
-          const char *nm = makefiles->list[stdin_offset];
-          if (unlink (nm) < 0 && errno != ENOENT)
-            perror_with_name (_("unlink (temporary file): "), nm);
-          stdin_offset = -1;
-        }
+      temp_stdin_unlink ();
 
       /* Wait for children to die.  */
       err = (status != 0);
index 2da2a6fd4204bc2c643f6d5950b18408bdc618f0..89a5f7708e38cb158bb0d612fda4ff1300a036bc 100644 (file)
@@ -545,6 +545,7 @@ void out_of_memory () NORETURN;
                                  (_f), (_n), (_s))
 
 void decode_env_switches (const char*, size_t line);
+void temp_stdin_unlink (void);
 void die (int) NORETURN;
 void pfatal_with_name (const char *) NORETURN;
 void perror_with_name (const char *, const char *);
index 1d09174f294e574c4d4158bd3ef3ec911151fa21..292ef8ff4699cbc1ef4a25c01f56adbfb143520d 100644 (file)
@@ -338,5 +338,28 @@ all:: ; @./foo bar baz
               '-O', "#MAKE#: ./foo: $ERR_no_such_file\n#MAKE#: *** [#MAKEFILE#:2: all] Error 127\n", 512);
 }
 
+if ($port_type eq 'UNIX') {
+# POSIX doesn't require sh to set PPID so test this
+my $cmd = create_command();
+add_options($cmd, '-f', '/dev/null', '-E', q!all:;@echo $$PPID!);
+my $fout = 'ppidtest.out';
+run_command_with_output($fout, @$cmd);
+$_ = read_file_into_string($fout);
+chomp($_);
+if (/^[0-9]+$/) {
+use POSIX ();
+# SV 63157.
+# Test that make removes temporary files, even when a signal is received.
+# The general test_driver postprocessing will ensure the temporary file used
+# to synchronize output and the jobserver fifo are both removed.
+run_make_test(q!
+pid:=$(shell echo $$PPID)
+all:; @kill -TERM $(pid)
+!, '-O -j2', "", POSIX::SIGTERM);
+}
+
+unlink($fout);
+}
+
 # This tells the test driver that the perl test script executed properly.
 1;
index 8c7a47a085a8eb44094dbb97dbcd5e935b72120e..32a6873185468a6cac91c6707fa51145b5cb1ae7 100644 (file)
@@ -46,6 +46,35 @@ force:
               '-R --debug=b -f-', "/Re-executing.+?--temp-stdin=\Q$temppath\E/");
 
 if ($port_type eq 'UNIX') {
+# POSIX doesn't require sh to set PPID so test this
+my $cmd = create_command();
+add_options($cmd, '-f', '/dev/null', '-E', q!all:;@echo $$PPID!);
+my $fout = 'ppidtest.out';
+run_command_with_output($fout, @$cmd);
+$_ = read_file_into_string($fout);
+chomp($_);
+if (/^[0-9]+$/) {
+use POSIX ();
+
+# sv 63157.
+# Test that make removes the temporary file which holds make code from stdin,
+# even when a signal is received.
+# include bye.mk and bye.mk: rule is needed to cause make to keep the temporary
+# file for re-exec. Without re-exec make will remove the file before the signal
+# arrives.
+&utouch(-600, 'bye.mk');
+close(STDIN);
+open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!";
+run_make_test(q!
+include bye.mk
+pid:=$(shell echo $$PPID)
+all:;
+bye.mk: force; @kill -TERM $(pid)
+force:
+!, '-f-', "", POSIX::SIGTERM);
+}
+unlink($fout);
+
 # sv 62118,62145.
 # Test that a stdin temp file is removed, when execvp fails to re-exec make.
 # In order to cause execvp to fail, copy the tested make binary to the temp