]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 57022] Avoid posix_spawn which fails asynchronously
authorPaul Smith <psmith@gnu.org>
Fri, 27 Dec 2019 06:27:09 +0000 (01:27 -0500)
committerPaul Smith <psmith@gnu.org>
Fri, 27 Dec 2019 06:37:17 +0000 (01:37 -0500)
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 <martin.dorey@hds.com>

Original implementation of the regression tests provided by
Dmitry Goncharov <dgoncharov@users.sf.net>

* 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
tests/scripts/features/exec [new file with mode: 0644]

index af58c1b4688993960764dae77554b42ae807eddb..5daff11e9d57a4a7a918e7a23825962398e25461 100644 (file)
@@ -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 <spawn.h>
+       #include <string.h>
+
+       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 (file)
index 0000000..4b7911b
--- /dev/null
@@ -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;