[SV 63157] Ensure temporary files are removed when signaled

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.
This commit is contained in:
Paul Smith 2022-10-15 16:34:54 -04:00
parent 383eb3a923
commit 18c4b508ef
5 changed files with 78 additions and 19 deletions

View 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. */

View 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);

View 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 *);

View 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;

View 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