From e64674b718600bd4fad0b5ac1cc37eb89fba5ef7 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Fri, 27 Dec 2019 01:27:09 -0500 Subject: [PATCH] [SV 57022] Avoid posix_spawn which fails asynchronously Avoid using posix_spawn implementations that fail asynchronously when the spawned program can't be invoked: this means instead of getting an error such as "No such file or directory" we get just "Exit 127". Original implementation of the configure.ac macro provided by Martin Dorey Original implementation of the regression tests provided by Dmitry Goncharov * configure.ac: Test whether posix_spawn fails asynchronously. In a cross-compilation environment, assume that it does not. If we detect that it does, fall back to fork/exec. * tests/scripts/features/exec: Add regression tests for different shebang invocation methods. --- configure.ac | 23 +++++++++++++- tests/scripts/features/exec | 63 +++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/scripts/features/exec diff --git a/configure.ac b/configure.ac index af58c1b4..5daff11e 100644 --- a/configure.ac +++ b/configure.ac @@ -371,7 +371,28 @@ AC_ARG_ENABLE([posix-spawn], AS_CASE([/$ac_cv_header_spawn/$ac_cv_func_posix_spawn/], [*/no/*], [make_cv_posix_spawn=no]) -AS_CASE([/$make_cv_posix_spawn/$user_posix_spawn/], +AS_IF([test "$make_cv_posix_spawn" = yes], + AC_CACHE_CHECK([for posix_spawn that fails synchronously], + [make_cv_synchronous_posix_spawn], + [make_cv_synchronous_posix_spawn=no + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + #include + + extern char **environ; + + int main() { + char* path = strdup("./non-existent"); + char *argv[[2]]; + argv[[0]] = path; + argv[[1]] = 0; + return posix_spawn(0, path, 0, 0, argv, environ); + }]])], + [make_cv_synchronous_posix_spawn=no], + [make_cv_synchronous_posix_spawn=yes], + [make_cv_synchronous_posix_spawn="no (cross-compiling)"])])) + +AS_CASE([/$user_posix_spawn/$make_cv_posix_spawn/$make_cv_synchronous_posix_spawn/], [*/no/*], [make_cv_posix_spawn=no], [AC_DEFINE(USE_POSIX_SPAWN, 1, [Define to 1 to use posix_spawn().]) ]) diff --git a/tests/scripts/features/exec b/tests/scripts/features/exec new file mode 100644 index 00000000..4b7911be --- /dev/null +++ b/tests/scripts/features/exec @@ -0,0 +1,63 @@ +# -*-perl-*- + +use warnings; + +my $description = "Test that make can execute binaries as well as scripts with" + ." various shabangs and without a shebang"; +my $details = "The various shells that this test uses are the default " + ."/bin/sh, $origENV{SHELL} and the perl interpreter that is " + ." executing this test program. The shells are used for the value" + ." of SHELL inside the test makefile and also as a shebang in the" + ." executed script. There is also a test which executes a script" + ." that has no shebang."; + +# Only bother with this on UNIX systems +$port_type eq 'UNIX' or return -1; + +my $usersh = $origENV{SHELL}; +my $answer = 'hello, world'; + +my @shebangs = ('', '#!/bin/sh', "#!$usersh", "#!$perl_name"); +my @shells = ('', 'SHELL=/bin/sh', "SHELL=$usersh"); + +# tests [0-11] +# Have a makefile with various SHELL= exec a shell program with varios +# shebangs or without a shebang at all. +my $stem = './exec.cmd'; +my $k = 0; +for my $shebang (@shebangs) { + for my $shell (@shells) { + my $cmd = $k ? "$stem.$k" : $stem; + ++$k; + unlink $cmd; + open(CMD,"> $cmd"); + print CMD "$shebang\n"; + print CMD "printf \"$answer\\n\";\n"; + close(CMD); + chmod 0700, $cmd; + + run_make_test(q! +all:; @$(CMD) +!, "$shell CMD=$cmd", "$answer\n"); + + rmfiles($cmd); + } +} + +# tests [12-14] +# Exec a binary from a makefile that has SHELL=. +for my $shell (@shells) { + run_make_test(q! +all:; @#PERL# -e 'printf "$(ANSWER)\n"'; +!, "$shell ANSWER='$answer'", "$answer\n"); +} + +# test 15 +# Use perl as a shell. +run_make_test(q! +SHELL = #PERL# +.SHELLFLAGS = -e +all:; @printf "$(ANSWER)\n"; +!, "ANSWER='$answer'", "$answer\n"); + +1;