Windows: Don't leak any handles from Bazel client to Bazel server

Explicitly specify which handles to inherit

Fixes https://github.com/bazelbuild/bazel/issues/4193
Fixes https://github.com/bazelbuild/bazel/issues/2182
Fixes https://github.com/bazelbuild/bazel/issues/2248

Change-Id: Ifa0201a6764c633016784c245d480542966efc6d
PiperOrigin-RevId: 177564007
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index ff8ec2f..e18e3db 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -57,6 +57,7 @@
 // Add 4 characters for potential UNC prefix and a couple more for safety.
 static const size_t kWindowsPathBufferSize = 0x8010;
 
+using bazel::windows::AutoAttributeList;
 using bazel::windows::AutoHandle;
 using bazel::windows::CreateJunction;
 
@@ -551,13 +552,27 @@
   }
   AutoHandle stderr_file(stderr_handle);
 
-  PROCESS_INFORMATION processInfo = {0};
-  STARTUPINFOA startupInfo = {0};
+  // Create an attribute list with length of 1
+  AutoAttributeList lpAttributeList(1);
 
-  startupInfo.hStdInput = devnull;
-  startupInfo.hStdError = stdout_file;
-  startupInfo.hStdOutput = stderr_handle;
-  startupInfo.dwFlags |= STARTF_USESTDHANDLES;
+  HANDLE handlesToInherit[2] = {stdout_file, stderr_handle};
+  if (!UpdateProcThreadAttribute(
+          lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+          handlesToInherit, 2 * sizeof(HANDLE), NULL, NULL)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ExecuteDaemon(%s): UpdateProcThreadAttribute", exe.c_str());
+  }
+
+  PROCESS_INFORMATION processInfo = {0};
+  STARTUPINFOEXA startupInfoEx = {0};
+
+  startupInfoEx.StartupInfo.cb = sizeof(startupInfoEx);
+  startupInfoEx.StartupInfo.hStdInput = devnull;
+  startupInfoEx.StartupInfo.hStdOutput = stdout_file;
+  startupInfoEx.StartupInfo.hStdError = stderr_handle;
+  startupInfoEx.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+  startupInfoEx.lpAttributeList = lpAttributeList;
+
   CmdLine cmdline;
   CreateCommandLine(&cmdline, exe, args_vector);
 
@@ -567,10 +582,11 @@
       /* lpProcessAttributes */ NULL,
       /* lpThreadAttributes */ NULL,
       /* bInheritHandles */ TRUE,
-      /* dwCreationFlags */ DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP,
+      /* dwCreationFlags */ DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP |
+          EXTENDED_STARTUPINFO_PRESENT,
       /* lpEnvironment */ NULL,
       /* lpCurrentDirectory */ NULL,
-      /* lpStartupInfo */ &startupInfo,
+      /* lpStartupInfo */ &startupInfoEx.StartupInfo,
       /* lpProcessInformation */ &processInfo);
 
   if (!ok) {
diff --git a/src/main/native/windows/util.h b/src/main/native/windows/util.h
index 730a1d4..5a647a4 100644
--- a/src/main/native/windows/util.h
+++ b/src/main/native/windows/util.h
@@ -49,6 +49,30 @@
   HANDLE handle_;
 };
 
+struct AutoAttributeList {
+  AutoAttributeList(DWORD dwAttributeCount) {
+    SIZE_T size = 0;
+    InitializeProcThreadAttributeList(NULL, dwAttributeCount, 0, &size);
+    lpAttributeList =
+        reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(malloc(size));
+    InitializeProcThreadAttributeList(lpAttributeList, dwAttributeCount, 0,
+                                      &size);
+  }
+
+  ~AutoAttributeList() {
+    if (lpAttributeList) {
+      DeleteProcThreadAttributeList(lpAttributeList);
+      free(lpAttributeList);
+    }
+    lpAttributeList = NULL;
+  }
+
+  operator LPPROC_THREAD_ATTRIBUTE_LIST() const { return lpAttributeList; }
+
+ private:
+  LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
+};
+
 #define WSTR1(x) L##x
 #define WSTR(x) WSTR1(x)