From 6932da3096f8149e0fffe2aba0ab8c444a598476 Mon Sep 17 00:00:00 2001
From: Kien Nguyen <kien.n.quang@gmail.com>
Date: Sun, 4 Aug 2024 04:29:35 -0700
Subject: [PATCH 4/6] init_ntproc: Use SetHandleInformation to set NOINHERIT
 when possible

---
 src/w32.c | 123 ++++++++++++++++++++++++++++++------------------------
 1 file changed, 68 insertions(+), 55 deletions(-)

diff --git a/src/w32.c b/src/w32.c
index 31ffa301c2f..f531274ce92 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -7783,10 +7783,6 @@ init_winsock (int load_now)
   if (winsock_lib != NULL)
     return TRUE;
 
-  pfn_SetHandleInformation
-    = (void *) get_proc_addr (GetModuleHandle ("kernel32.dll"),
-                                     "SetHandleInformation");
-
   winsock_lib = LoadLibrary ("Ws2_32.dll");
 
   if (winsock_lib != NULL)
@@ -10471,6 +10467,10 @@ init_ntproc (int dumping)
      Conveniently, init_environment is called before us, so
      PRELOAD_WINSOCK can be set in the registry. */
 
+  pfn_SetHandleInformation
+    = (void *) get_proc_addr (GetModuleHandle ("kernel32.dll"),
+                                     "SetHandleInformation");
+
   /* Always initialize this correctly. */
   winsock_lib = NULL;
 
@@ -10480,60 +10480,73 @@ init_ntproc (int dumping)
   /* Initial preparation for subprocess support: replace our standard
      handles with non-inheritable versions. */
   {
-    HANDLE parent;
-    HANDLE stdin_save =  INVALID_HANDLE_VALUE;
-    HANDLE stdout_save = INVALID_HANDLE_VALUE;
-    HANDLE stderr_save = INVALID_HANDLE_VALUE;
-
-    parent = GetCurrentProcess ();
-
-    /* ignore errors when duplicating and closing; typically the
-       handles will be invalid when running as a gui program. */
-    DuplicateHandle (parent,
-		     GetStdHandle (STD_INPUT_HANDLE),
-		     parent,
-		     &stdin_save,
-		     0,
-		     FALSE,
-		     DUPLICATE_SAME_ACCESS);
-
-    DuplicateHandle (parent,
-		     GetStdHandle (STD_OUTPUT_HANDLE),
-		     parent,
-		     &stdout_save,
-		     0,
-		     FALSE,
-		     DUPLICATE_SAME_ACCESS);
-
-    DuplicateHandle (parent,
-		     GetStdHandle (STD_ERROR_HANDLE),
-		     parent,
-		     &stderr_save,
-		     0,
-		     FALSE,
-		     DUPLICATE_SAME_ACCESS);
-
-    fclose (stdin);
-    fclose (stdout);
-    fclose (stderr);
-
-    if (stdin_save != INVALID_HANDLE_VALUE)
-      _open_osfhandle ((intptr_t) stdin_save, O_TEXT);
+    /* For UCRT, the _fdopen will try to find free stream from
+       _IOB_ENTRIES (= 3), thus we can't reopen the standard handles
+       with it. Using SetHandleInformation to make the handle not
+       inheritable to child process is a better way. */
+    if (pfn_SetHandleInformation)
+    {
+      pfn_SetHandleInformation (GetStdHandle(STD_INPUT_HANDLE), HANDLE_FLAG_INHERIT, 0);
+      pfn_SetHandleInformation (GetStdHandle(STD_OUTPUT_HANDLE), HANDLE_FLAG_INHERIT, 0);
+      pfn_SetHandleInformation (GetStdHandle(STD_ERROR_HANDLE), HANDLE_FLAG_INHERIT, 0);
+    }
     else
-      _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
-    _fdopen (0, "r");
+    {
+      HANDLE parent;
+      HANDLE stdin_save =  INVALID_HANDLE_VALUE;
+      HANDLE stdout_save = INVALID_HANDLE_VALUE;
+      HANDLE stderr_save = INVALID_HANDLE_VALUE;
+
+      parent = GetCurrentProcess ();
+
+      /* ignore errors when duplicating and closing; typically the
+	 handles will be invalid when running as a gui program. */
+      DuplicateHandle (parent,
+		       GetStdHandle (STD_INPUT_HANDLE),
+		       parent,
+		       &stdin_save,
+		       0,
+		       FALSE,
+		       DUPLICATE_SAME_ACCESS);
+
+      DuplicateHandle (parent,
+		       GetStdHandle (STD_OUTPUT_HANDLE),
+		       parent,
+		       &stdout_save,
+		       0,
+		       FALSE,
+		       DUPLICATE_SAME_ACCESS);
+
+      DuplicateHandle (parent,
+		       GetStdHandle (STD_ERROR_HANDLE),
+		       parent,
+		       &stderr_save,
+		       0,
+		       FALSE,
+		       DUPLICATE_SAME_ACCESS);
+
+      fclose (stdin);
+      fclose (stdout);
+      fclose (stderr);
+
+      if (stdin_save != INVALID_HANDLE_VALUE)
+	_open_osfhandle ((intptr_t) stdin_save, O_TEXT);
+      else
+	_open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
+      _fdopen (0, "r");
 
-    if (stdout_save != INVALID_HANDLE_VALUE)
-      _open_osfhandle ((intptr_t) stdout_save, O_TEXT);
-    else
-      _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
-    _fdopen (1, "w");
+      if (stdout_save != INVALID_HANDLE_VALUE)
+	_open_osfhandle ((intptr_t) stdout_save, O_TEXT);
+      else
+	_open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
+      _fdopen (1, "w");
 
-    if (stderr_save != INVALID_HANDLE_VALUE)
-      _open_osfhandle ((intptr_t) stderr_save, O_TEXT);
-    else
-      _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
-    _fdopen (2, "w");
+      if (stderr_save != INVALID_HANDLE_VALUE)
+	_open_osfhandle ((intptr_t) stderr_save, O_TEXT);
+      else
+	_open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
+      _fdopen (2, "w");
+    }
   }
 
   /* unfortunately, atexit depends on implementation of malloc */
-- 
2.46.0.windows.1

