From 949c0464a9f429e7778dbcf8ff78fc2d02911609 Mon Sep 17 00:00:00 2001 From: Dmitry Goncharov Date: Sat, 23 Apr 2022 15:33:41 -0400 Subject: [PATCH] [SV 62145] Remove a stdin temp file on re-exec failure. If the re-exec fails, be sure to remove a temp makefile that was created to read from stdin. * src/job.c (exec_command): Return on failure. (child_execute_job): Call exit if exec_command returns. * src/job.h (exec_command): Don't mark as NORETURN. * src/main.c (main): Unlink stdin temporary file if re-exec fails. * tests/run_make_tests.pl: Get value for ERR_nonexe_file/ERR_exe_dir. * tests/scripts/features/temp_stdin: Test that temp file unlink works. --- src/job.c | 16 +---- src/job.h | 4 +- src/main.c | 9 ++- tests/run_make_tests.pl | 4 +- tests/scripts/features/temp_stdin | 106 ++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 tests/scripts/features/temp_stdin diff --git a/src/job.c b/src/job.c index 8d1bdefb..6060cad8 100644 --- a/src/job.c +++ b/src/job.c @@ -2309,6 +2309,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) /* Run the command. */ exec_command (argv, child->environment); + _exit (127); #else /* USE_POSIX_SPAWN */ @@ -2452,12 +2453,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv) /* Replace the current process with one running the command in ARGV, with environment ENVP. This function does not return. */ -/* EMX: This function returns the pid of the child process. */ -# ifdef __EMX__ pid_t -# else -void -# endif exec_command (char **argv, char **envp) { #ifdef VMS @@ -2524,14 +2520,12 @@ exec_command (char **argv, char **envp) } } - /* return child's exit code as our exit code */ + /* Use the child's exit code as our exit code */ exit (exit_code); #else /* !WINDOWS32 */ -# ifdef __EMX__ - pid_t pid; -# endif + pid_t pid = -1; /* Be the user, permanently. */ child_access (); @@ -2630,11 +2624,7 @@ exec_command (char **argv, char **envp) break; } -# ifdef __EMX__ return pid; -# else - _exit (127); -# endif #endif /* !WINDOWS32 */ #endif /* !VMS */ } diff --git a/src/job.h b/src/job.h index 7c50f045..c32e84b0 100644 --- a/src/job.h +++ b/src/job.h @@ -81,10 +81,8 @@ pid_t child_execute_job (struct childbase *child, int good_stdin, char **argv); #ifdef _AMIGA void exec_command (char **argv) NORETURN; -#elif defined(__EMX__) -int exec_command (char **argv, char **envp); #else -void exec_command (char **argv, char **envp) NORETURN; +pid_t exec_command (char **argv, char **envp); #endif void unblock_all_sigs (void); diff --git a/src/main.c b/src/main.c index 66086029..fc94b084 100644 --- a/src/main.c +++ b/src/main.c @@ -2655,10 +2655,13 @@ main (int argc, char **argv, char **envp) #endif exec_command ((char **)nargv, environ); #endif - - /* We shouldn't get here but just in case. */ jobserver_post_child(1); - break; + + /* Get rid of any stdin temp file. */ + if (stdin_offset >= 0) + unlink (makefiles->list[stdin_offset]); + + _exit (127); } if (any_failed) diff --git a/tests/run_make_tests.pl b/tests/run_make_tests.pl index f64ff8f0..155cd2ba 100644 --- a/tests/run_make_tests.pl +++ b/tests/run_make_tests.pl @@ -141,14 +141,14 @@ $ERR_command_not_found = undef; $ERR_read_only_file = "$!"; } - $_ = `./file.out 2>/dev/null`; + $_ = `./file.out 2>&1`; if ($? == 0) { print "Executed non-executable file! Skipping related tests.\n"; } else { $ERR_nonexe_file = "$!"; } - $_ = `./. 2>/dev/null`; + $_ = `./. 2>&1`; if ($? == 0) { print "Executed directory! Skipping related tests.\n"; } else { diff --git a/tests/scripts/features/temp_stdin b/tests/scripts/features/temp_stdin new file mode 100644 index 00000000..a00b9848 --- /dev/null +++ b/tests/scripts/features/temp_stdin @@ -0,0 +1,106 @@ +# -*-mode: perl-*- + +$description = "Test handling of temporary file created from stdin."; + +use File::Temp qw /tempdir/; + +sub check_tempfile +{ + my ($tdir) = @_; + my @left = glob $tdir . '/Gm*'; + scalar @left == 0 && return; + my $answer = "temporary file $left[0] is left behind\n"; + compare_output($answer, &get_logfile(1)); +} + +create_file('input.mk', "world:=1\n"); +create_file('bye.mk', "moon:=2\n"); + +# sv 62118,62145. +# Test that makes leaves no temp file when make code is piped to stdin and -v, +# -h or an invalid option is specified. +my @opts = ('-v', '-h', '--nosuchopt'); +my @exit_codes = (0, 0, 512); +for my $i (0 .. $#opts) { + my $tdir = tempdir(CLEANUP => 1); + $ENV{'TMPDIR'} = $tdir; + $ENV{'TMP'} = $tdir; + close(STDIN); + open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; + run_make_test(q! +all:; $(info hello world) +!, + "$opts[$i] -f-", "/uilt for /", $exit_codes[$i]); + check_tempfile($tdir); +} + +# sv 62118,62145. +# Test that a stdin temp file is removed. +my $tdir = tempdir(CLEANUP => 1); +$ENV{'TMPDIR'} = $tdir; +$ENV{'TMP'} = $tdir; +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; +run_make_test(q! +all:; $(info world=$(world)) +!, + '-f-', "world=1\n#MAKE#: 'all' is up to date.\n"); +check_tempfile($tdir); + +# sv 62118,62145. +# Test that a stdin temp file is removed, even when make re-execs. +# Also test that make nohors TMPDIR to create the temp file. +my $tdir = tempdir(CLEANUP => 1); +$ENV{'TMPDIR'} = $tdir; +$ENV{'TMP'} = $tdir; +# Ensure touching bye.mk causes re-exec. +&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 +all:; $(info hello) +$(MAKE_RESTARTS)bye.mk: force; touch $@ +force: +!, + '-R --debug=b -f-', "/Re-executing.+?--temp-stdin=\Q$tdir\E/"); +check_tempfile($tdir); + +if ($port_type eq 'UNIX') { +# 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 +# directory and take away the 'x' bit. +use File::Copy; + +my $tdir = tempdir(CLEANUP => 1); +$ENV{'TMPDIR'} = $tdir; +$ENV{'TMP'} = $tdir; +my $makecopy = "$tdir/make"; +copy("$mkpath", $makecopy); +# Set file mode bits, because perl copy won't. +chmod 0750, $makecopy; + +my @make_orig = @make_command; +@make_command = ($makecopy); + +# Ensure touching bye.mk causes re-exec. +&utouch(-600, 'bye.mk'); +close(STDIN); +open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; +run_make_test(" +include bye.mk +all:; \$(info hello) +\$(MAKE_RESTARTS)bye.mk: force; touch \$@ && chmod -x $makecopy +force: +", + "-f-", "touch bye.mk && chmod -x $makecopy\nmake: $makecopy: $ERR_nonexe_file\n", 32512); +check_tempfile($tdir); + +@make_command = @make_orig; +} + +unlink('input.mk', 'bye.mk'); + +# This tells the test driver that the perl test script executed properly. +1;