Windows, JNI: WaitableProcess supports inv. HANDLE

WaitableProcess and AutoAttributeList support
INVALID_HANDLE_VALUE for some or all of the std_*
handles of the subprocess.

AutoAttributeList initializes the inheritable
HANDLE array only for the valid HANDLEs.

WaitableProcess forbids HANDLE inheritance if all
std_* handles are invalid.

Closes #8115.

PiperOrigin-RevId: 244844487
diff --git a/src/java_tools/junitrunner/javatests/com/google/testing/junit/runner/BUILD b/src/java_tools/junitrunner/javatests/com/google/testing/junit/runner/BUILD
index fa0e7e0..ee22122 100644
--- a/src/java_tools/junitrunner/javatests/com/google/testing/junit/runner/BUILD
+++ b/src/java_tools/junitrunner/javatests/com/google/testing/junit/runner/BUILD
@@ -25,7 +25,7 @@
         "//third_party:jsr305",
         "//third_party:jsr330_inject",
         "//third_party:junit4",
-        "//third_party:mockito2",
+        "//third_party:mockito",
         "//third_party:truth",
     ],
 )
diff --git a/src/main/native/windows/process.cc b/src/main/native/windows/process.cc
index 48e54bc..7aa6092 100644
--- a/src/main/native/windows/process.cc
+++ b/src/main/native/windows/process.cc
@@ -130,7 +130,7 @@
           /* lpCommandLine */ mutable_commandline.get(),
           /* lpProcessAttributes */ NULL,
           /* lpThreadAttributes */ NULL,
-          /* bInheritHandles */ TRUE,
+          /* bInheritHandles */ attr_list->InheritAnyHandles() ? TRUE : FALSE,
           /* dwCreationFlags */ CREATE_NO_WINDOW  // Don't create console
                                                   // window
               | CREATE_NEW_PROCESS_GROUP  // So that Ctrl-Break isn't propagated
diff --git a/src/main/native/windows/util.cc b/src/main/native/windows/util.cc
index f3182c2..829fd5c 100644
--- a/src/main/native/windows/util.cc
+++ b/src/main/native/windows/util.cc
@@ -73,12 +73,20 @@
 bool AutoAttributeList::Create(HANDLE stdin_h, HANDLE stdout_h, HANDLE stderr_h,
                                std::unique_ptr<AutoAttributeList>* result,
                                wstring* error_msg) {
+  if (stdin_h == INVALID_HANDLE_VALUE && stdout_h == INVALID_HANDLE_VALUE &&
+      stderr_h == INVALID_HANDLE_VALUE) {
+    result->reset(new AutoAttributeList());
+    return true;
+  }
+
   static constexpr DWORD kAttributeCount = 1;
 
   SIZE_T size = 0;
   // According to MSDN, the first call to InitializeProcThreadAttributeList is
   // expected to fail.
   InitializeProcThreadAttributeList(NULL, kAttributeCount, 0, &size);
+  SetLastError(ERROR_SUCCESS);
+
   std::unique_ptr<uint8_t[]> data(new uint8_t[size]);
   LPPROC_THREAD_ATTRIBUTE_LIST attrs =
       reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(data.get());
@@ -94,10 +102,11 @@
 
   std::unique_ptr<AutoAttributeList> attr_list(
       new AutoAttributeList(std::move(data), stdin_h, stdout_h, stderr_h));
-  if (!UpdateProcThreadAttribute(attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
-                                 attr_list->handles_.handle_array,
-                                 StdHandles::kHandleCount * sizeof(HANDLE),
-                                 NULL, NULL)) {
+  if (!UpdateProcThreadAttribute(
+          attrs, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+          attr_list->handles_.ValidHandles(),
+          attr_list->handles_.ValidHandlesCount() * sizeof(HANDLE), NULL,
+          NULL)) {
     if (error_msg) {
       DWORD err = GetLastError();
       *error_msg = MakeErrorMessage(WSTR(__FILE__), __LINE__,
@@ -109,14 +118,40 @@
   return true;
 }
 
+AutoAttributeList::StdHandles::StdHandles()
+    : valid_handles_(0),
+      stdin_h_(INVALID_HANDLE_VALUE),
+      stdout_h_(INVALID_HANDLE_VALUE),
+      stderr_h_(INVALID_HANDLE_VALUE) {
+  valid_handle_array_[0] = INVALID_HANDLE_VALUE;
+  valid_handle_array_[1] = INVALID_HANDLE_VALUE;
+  valid_handle_array_[2] = INVALID_HANDLE_VALUE;
+}
+
+AutoAttributeList::StdHandles::StdHandles(HANDLE stdin_h, HANDLE stdout_h,
+                                          HANDLE stderr_h)
+    : valid_handles_(0),
+      stdin_h_(stdin_h),
+      stdout_h_(stdout_h),
+      stderr_h_(stderr_h) {
+  valid_handle_array_[0] = INVALID_HANDLE_VALUE;
+  valid_handle_array_[1] = INVALID_HANDLE_VALUE;
+  valid_handle_array_[2] = INVALID_HANDLE_VALUE;
+  if (stdin_h != INVALID_HANDLE_VALUE) {
+    valid_handle_array_[valid_handles_++] = stdin_h;
+  }
+  if (stdout_h != INVALID_HANDLE_VALUE) {
+    valid_handle_array_[valid_handles_++] = stdout_h;
+  }
+  if (stderr_h != INVALID_HANDLE_VALUE) {
+    valid_handle_array_[valid_handles_++] = stderr_h;
+  }
+}
+
 AutoAttributeList::AutoAttributeList(std::unique_ptr<uint8_t[]>&& data,
                                      HANDLE stdin_h, HANDLE stdout_h,
                                      HANDLE stderr_h)
-    : data_(std::move(data)) {
-  handles_.stdin_h = stdin_h;
-  handles_.stdout_h = stdout_h;
-  handles_.stderr_h = stderr_h;
-}
+    : data_(std::move(data)), handles_(stdin_h, stdout_h, stderr_h) {}
 
 AutoAttributeList::~AutoAttributeList() {
   DeleteProcThreadAttributeList(*this);
@@ -129,21 +164,25 @@
 void AutoAttributeList::InitStartupInfoExA(STARTUPINFOEXA* startup_info) const {
   ZeroMemory(startup_info, sizeof(STARTUPINFOEXA));
   startup_info->StartupInfo.cb = sizeof(STARTUPINFOEXA);
-  startup_info->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-  startup_info->StartupInfo.hStdInput = handles_.stdin_h;
-  startup_info->StartupInfo.hStdOutput = handles_.stdout_h;
-  startup_info->StartupInfo.hStdError = handles_.stderr_h;
-  startup_info->lpAttributeList = *this;
+  if (InheritAnyHandles()) {
+    startup_info->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+    startup_info->StartupInfo.hStdInput = handles_.StdIn();
+    startup_info->StartupInfo.hStdOutput = handles_.StdOut();
+    startup_info->StartupInfo.hStdError = handles_.StdErr();
+    startup_info->lpAttributeList = *this;
+  }
 }
 
 void AutoAttributeList::InitStartupInfoExW(STARTUPINFOEXW* startup_info) const {
   ZeroMemory(startup_info, sizeof(STARTUPINFOEXW));
   startup_info->StartupInfo.cb = sizeof(STARTUPINFOEXW);
-  startup_info->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
-  startup_info->StartupInfo.hStdInput = handles_.stdin_h;
-  startup_info->StartupInfo.hStdOutput = handles_.stdout_h;
-  startup_info->StartupInfo.hStdError = handles_.stderr_h;
-  startup_info->lpAttributeList = *this;
+  if (InheritAnyHandles()) {
+    startup_info->StartupInfo.dwFlags = STARTF_USESTDHANDLES;
+    startup_info->StartupInfo.hStdInput = handles_.StdIn();
+    startup_info->StartupInfo.hStdOutput = handles_.StdOut();
+    startup_info->StartupInfo.hStdError = handles_.StdErr();
+    startup_info->lpAttributeList = *this;
+  }
 }
 
 static void QuotePath(const wstring& path, wstring* result) {
diff --git a/src/main/native/windows/util.h b/src/main/native/windows/util.h
index 1cd2dab..2766017 100644
--- a/src/main/native/windows/util.h
+++ b/src/main/native/windows/util.h
@@ -66,26 +66,36 @@
 
 class AutoAttributeList {
  public:
+  AutoAttributeList() {}
+
   static bool Create(HANDLE stdin_h, HANDLE stdout_h, HANDLE stderr_h,
                      std::unique_ptr<AutoAttributeList>* result,
-                     wstring* error_msg = nullptr);
+                     std::wstring* error_msg = nullptr);
   ~AutoAttributeList();
 
+  bool InheritAnyHandles() const { return handles_.ValidHandlesCount() > 0; }
+
   void InitStartupInfoExA(STARTUPINFOEXA* startup_info) const;
 
   void InitStartupInfoExW(STARTUPINFOEXW* startup_info) const;
 
  private:
-  struct StdHandles {
-    static constexpr size_t kHandleCount = 3;
-    union {
-      HANDLE handle_array[kHandleCount];
-      struct {
-        HANDLE stdin_h;
-        HANDLE stdout_h;
-        HANDLE stderr_h;
-      };
-    };
+  class StdHandles {
+   public:
+    StdHandles();
+    StdHandles(HANDLE stdin_h, HANDLE stdout_h, HANDLE stderr_h);
+    size_t ValidHandlesCount() const { return valid_handles_; }
+    HANDLE* ValidHandles() { return valid_handle_array_; }
+    HANDLE StdIn() const { return stdin_h_; }
+    HANDLE StdOut() const { return stdout_h_; }
+    HANDLE StdErr() const { return stderr_h_; }
+
+   private:
+    size_t valid_handles_;
+    HANDLE valid_handle_array_[3];
+    HANDLE stdin_h_;
+    HANDLE stdout_h_;
+    HANDLE stderr_h_;
   };
 
   AutoAttributeList(std::unique_ptr<uint8_t[]>&& data, HANDLE stdin_h,