Subject: Re: bug#63024: Crash during `guix import pypi -r'

From: Ludovic Courtès <[email-masked]>
Date: Wed, 03 May 2023 11:04:14 +0200

Hey,

Ludovic Courtès <[email-masked]> skribis:

> Looks like we shoudn’t dup(4, 1) in the child process, because 4 is the
> other end of our sleep pipe.  :-)

How about this patch, Josselin?

Ludo’.

diff --git a/libguile/posix.c b/libguile/posix.c
index 3adc743c4..2d55d985c 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1388,11 +1388,27 @@ do_spawn (char *exec_file, char **exec_argv, char **exec_env,
     }
 
   /* Move the fds out of the way, so that duplicate fds or fds equal
-     to 0, 1, 2 don't trample each other */
+     to 0, 1, 2 don't trample each other.  Since 'system*' might give
+     us -1 for IN, OUT, or ERR, open /dev/null when that's the case.  */
+
+  if (in < 0)
+    posix_spawn_file_actions_addopen (&actions, fd_slot[0],
+                                      "/dev/null", O_RDONLY | O_CLOEXEC, 0);
+  else
+    posix_spawn_file_actions_adddup2 (&actions, in, fd_slot[0]);
+
+  if (out < 0)
+    posix_spawn_file_actions_addopen (&actions, fd_slot[1],
+                                      "/dev/null", O_WRONLY | O_CLOEXEC, 0);
+  else
+    posix_spawn_file_actions_adddup2 (&actions, out, fd_slot[1]);
+
+  if (err < 0)
+    posix_spawn_file_actions_addopen (&actions, fd_slot[2],
+                                      "/dev/null", O_WRONLY | O_CLOEXEC, 0);
+  else
+    posix_spawn_file_actions_adddup2 (&actions, err, fd_slot[2]);
 
-  posix_spawn_file_actions_adddup2 (&actions, in, fd_slot[0]);
-  posix_spawn_file_actions_adddup2 (&actions, out, fd_slot[1]);
-  posix_spawn_file_actions_adddup2 (&actions, err, fd_slot[2]);
   posix_spawn_file_actions_adddup2 (&actions, fd_slot[0], 0);
   posix_spawn_file_actions_adddup2 (&actions, fd_slot[1], 1);
   posix_spawn_file_actions_adddup2 (&actions, fd_slot[2], 2);
diff --git a/test-suite/tests/posix.test b/test-suite/tests/posix.test
index d5cf47cda..18dad8902 100644
--- a/test-suite/tests/posix.test
+++ b/test-suite/tests/posix.test
@@ -374,7 +374,17 @@
                     (system* "sh" "-c" "echo bong >&2"))))))))
 
       (and (zero? (status:exit-val status))
-           (call-with-input-file file get-string-all)))))
+           (call-with-input-file file get-string-all))))
+
+  (pass-if-equal "https://bugs.gnu.org/63024"
+      0
+    (if (file-exists? "/proc/self/fd/0")          ;on GNU/Linux?
+        (parameterize ((current-output-port (%make-void-port "w0")))
+          (system* "guile" "-c"
+                   (object->string
+                    '(exit (string=? "/dev/null"
+                                     (readlink "/proc/self/fd/1"))))))
+        (throw 'unresolved))))
 
 ;;
 ;; spawn