@@ -244,6 +244,67 @@ static tb_void_t tb_process_args_append(tb_string_ref_t result, tb_char_t const*
244244 if (wrap_quote ) tb_string_chrcat (result , '\"' );
245245}
246246
247+ static tb_bool_t tb_process_is_win7_or_lower (tb_noarg_t )
248+ {
249+ // Cache the result: -1 means uninitialized, 0 means false, 1 means true
250+ static tb_long_t s_is_win7_or_lower = -1 ;
251+ if (s_is_win7_or_lower != -1 )
252+ return s_is_win7_or_lower == 1 ;
253+ tb_kernel32_ref_t kernel32 = tb_kernel32 ();
254+ if (!kernel32 || !kernel32 -> VerifyVersionInfoW || !kernel32 -> VerSetConditionMask )
255+ {
256+ s_is_win7_or_lower = 0 ;
257+ return tb_false ;
258+ }
259+ OSVERSIONINFOEXW osvi = {0 };
260+ osvi .dwOSVersionInfoSize = sizeof (osvi );
261+ DWORDLONG const mask = kernel32 -> VerSetConditionMask (
262+ kernel32 -> VerSetConditionMask (0 , VER_MAJORVERSION , VER_GREATER_EQUAL ),
263+ VER_MINORVERSION , VER_GREATER_EQUAL );
264+ osvi .dwMajorVersion = 6 ;
265+ osvi .dwMinorVersion = 2 ;
266+ tb_bool_t is_win7 = (kernel32 -> VerifyVersionInfoW (& osvi , VER_MAJORVERSION | VER_MINORVERSION , mask ) == FALSE &&
267+ GetLastError () == ERROR_OLD_WIN_VERSION );
268+ s_is_win7_or_lower = is_win7 ? 1 : 0 ;
269+ return is_win7 ;
270+ }
271+
272+ /* @see https://github.com/xmake-io/xmake/issues/7330
273+ * https://github.com/chromium/crashpad/commit/9b92d2fb7101bae2af9bb5447227df296b37b56a
274+ */
275+ static tb_bool_t tb_process_is_inheritable_handle (HANDLE handle )
276+ {
277+ tb_check_return_val (handle && handle != INVALID_HANDLE_VALUE , tb_false );
278+
279+ if (tb_process_is_win7_or_lower ()) {
280+ // File handles (FILE_TYPE_DISK) and pipe handles (FILE_TYPE_PIPE) are known
281+ // to be inheritable. Console handles (FILE_TYPE_CHAR) are not inheritable via
282+ // PROC_THREAD_ATTRIBUTE_HANDLE_LIST. See
283+ // @ref https://codereview.chromium.org/1473793002
284+ DWORD handle_type = GetFileType (handle );
285+ return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE ;
286+ }
287+
288+ // On Win 8+, console handles are safe to inherit via PROC_THREAD_ATTRIBUTE_HANDLE_LIST
289+ return tb_true ;
290+ }
291+
292+ static tb_void_t tb_process_add_inheritable_handle (HANDLE * handles , DWORD * count , DWORD max_count , HANDLE handle )
293+ {
294+ if (tb_process_is_inheritable_handle (handle ))
295+ {
296+ // There doesn't seem to be any documentation of this, but if there's a handle
297+ // duplicated in this list, CreateProcess() fails with ERROR_INVALID_PARAMETER.
298+ for (DWORD i = 0 ; i < * count ; i ++ )
299+ {
300+ if (handles [i ] == handle )
301+ return ;
302+ }
303+ if (* count < max_count )
304+ handles [(* count )++ ] = handle ;
305+ }
306+ }
307+
247308/* //////////////////////////////////////////////////////////////////////////////////////
248309 * implementation
249310 */
@@ -424,7 +485,7 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
424485
425486 // enable inherit
426487 tb_kernel32 ()-> SetHandleInformation (hStdInput , HANDLE_FLAG_INHERIT , TRUE);
427- handlesToInherit [ handlesToInheritCount ++ ] = hStdInput ;
488+ tb_process_add_inheritable_handle ( handlesToInherit , & handlesToInheritCount , tb_arrayn ( handlesToInherit ), hStdInput ) ;
428489 process -> file_handles [process -> file_handles_count ++ ] = hStdInput ;
429490 process -> psi -> hStdInput = hStdInput ;
430491 }
@@ -436,7 +497,7 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
436497
437498 // enable inherit
438499 tb_kernel32 ()-> SetHandleInformation (hStdInput , HANDLE_FLAG_INHERIT , TRUE);
439- handlesToInherit [ handlesToInheritCount ++ ] = hStdInput ;
500+ tb_process_add_inheritable_handle ( handlesToInherit , & handlesToInheritCount , tb_arrayn ( handlesToInherit ), hStdInput ) ;
440501 process -> psi -> hStdInput = hStdInput ;
441502 }
442503
@@ -456,7 +517,7 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
456517
457518 // enable inherit
458519 tb_kernel32 ()-> SetHandleInformation (hStdOutput , HANDLE_FLAG_INHERIT , TRUE);
459- handlesToInherit [ handlesToInheritCount ++ ] = hStdOutput ;
520+ tb_process_add_inheritable_handle ( handlesToInherit , & handlesToInheritCount , tb_arrayn ( handlesToInherit ), hStdOutput ) ;
460521 process -> file_handles [process -> file_handles_count ++ ] = hStdOutput ;
461522 process -> psi -> hStdOutput = hStdOutput ;
462523 }
@@ -468,7 +529,7 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
468529
469530 // enable inherit
470531 tb_kernel32 ()-> SetHandleInformation (hStdOutput , HANDLE_FLAG_INHERIT , TRUE);
471- handlesToInherit [ handlesToInheritCount ++ ] = hStdOutput ;
532+ tb_process_add_inheritable_handle ( handlesToInherit , & handlesToInheritCount , tb_arrayn ( handlesToInherit ), hStdOutput ) ;
472533 process -> psi -> hStdOutput = hStdOutput ;
473534 }
474535
@@ -488,7 +549,7 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
488549
489550 // enable inherit
490551 tb_kernel32 ()-> SetHandleInformation (hStdError , HANDLE_FLAG_INHERIT , TRUE);
491- handlesToInherit [ handlesToInheritCount ++ ] = hStdError ;
552+ tb_process_add_inheritable_handle ( handlesToInherit , & handlesToInheritCount , tb_arrayn ( handlesToInherit ), hStdError ) ;
492553 process -> file_handles [process -> file_handles_count ++ ] = hStdError ;
493554 process -> psi -> hStdError = hStdError ;
494555 }
@@ -511,7 +572,7 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
511572
512573 // enable inherit
513574 tb_kernel32 ()-> SetHandleInformation (hStdError , HANDLE_FLAG_INHERIT , TRUE);
514- handlesToInherit [ handlesToInheritCount ++ ] = hStdError ;
575+ tb_process_add_inheritable_handle ( handlesToInherit , & handlesToInheritCount , tb_arrayn ( handlesToInherit ), hStdError ) ;
515576 process -> psi -> hStdError = hStdError ;
516577 }
517578 }
@@ -569,16 +630,14 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
569630 process -> psi -> hStdInput = hDupInput ;
570631 process -> file_handles [process -> file_handles_count ++ ] = hDupInput ;
571632 // add to handlesToInherit list so it can be inherited when using PROC_THREAD_ATTRIBUTE_HANDLE_LIST
572- if (handlesToInheritCount < sizeof (handlesToInherit ) / sizeof (handlesToInherit [0 ]))
573- handlesToInherit [handlesToInheritCount ++ ] = hDupInput ;
633+ tb_process_add_inheritable_handle (handlesToInherit , & handlesToInheritCount , tb_arrayn (handlesToInherit ), hDupInput );
574634 }
575635 else
576636 {
577637 // if duplication fails, try to make original inheritable (may affect parent)
578638 tb_kernel32 ()-> SetHandleInformation (hStdInput , HANDLE_FLAG_INHERIT , TRUE);
579639 process -> psi -> hStdInput = hStdInput ;
580- if (handlesToInheritCount < sizeof (handlesToInherit ) / sizeof (handlesToInherit [0 ]))
581- handlesToInherit [handlesToInheritCount ++ ] = hStdInput ;
640+ tb_process_add_inheritable_handle (handlesToInherit , & handlesToInheritCount , tb_arrayn (handlesToInherit ), hStdInput );
582641 }
583642 }
584643 }
@@ -594,16 +653,14 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
594653 process -> psi -> hStdOutput = hDupOutput ;
595654 process -> file_handles [process -> file_handles_count ++ ] = hDupOutput ;
596655 // add to handlesToInherit list so it can be inherited when using PROC_THREAD_ATTRIBUTE_HANDLE_LIST
597- if (handlesToInheritCount < sizeof (handlesToInherit ) / sizeof (handlesToInherit [0 ]))
598- handlesToInherit [handlesToInheritCount ++ ] = hDupOutput ;
656+ tb_process_add_inheritable_handle (handlesToInherit , & handlesToInheritCount , tb_arrayn (handlesToInherit ), hDupOutput );
599657 }
600658 else
601659 {
602660 // if duplication fails, try to make original inheritable (may affect parent)
603661 tb_kernel32 ()-> SetHandleInformation (hStdOutput , HANDLE_FLAG_INHERIT , TRUE);
604662 process -> psi -> hStdOutput = hStdOutput ;
605- if (handlesToInheritCount < sizeof (handlesToInherit ) / sizeof (handlesToInherit [0 ]))
606- handlesToInherit [handlesToInheritCount ++ ] = hStdOutput ;
663+ tb_process_add_inheritable_handle (handlesToInherit , & handlesToInheritCount , tb_arrayn (handlesToInherit ), hStdOutput );
607664 }
608665 }
609666 }
@@ -619,16 +676,14 @@ tb_process_ref_t tb_process_init_cmd(tb_char_t const* cmd, tb_process_attr_ref_t
619676 process -> psi -> hStdError = hDupError ;
620677 process -> file_handles [process -> file_handles_count ++ ] = hDupError ;
621678 // add to handlesToInherit list so it can be inherited when using PROC_THREAD_ATTRIBUTE_HANDLE_LIST
622- if (handlesToInheritCount < sizeof (handlesToInherit ) / sizeof (handlesToInherit [0 ]))
623- handlesToInherit [handlesToInheritCount ++ ] = hDupError ;
679+ tb_process_add_inheritable_handle (handlesToInherit , & handlesToInheritCount , tb_arrayn (handlesToInherit ), hDupError );
624680 }
625681 else
626682 {
627683 // if duplication fails, try to make original inheritable (may affect parent)
628684 tb_kernel32 ()-> SetHandleInformation (hStdError , HANDLE_FLAG_INHERIT , TRUE);
629685 process -> psi -> hStdError = hStdError ;
630- if (handlesToInheritCount < sizeof (handlesToInherit ) / sizeof (handlesToInherit [0 ]))
631- handlesToInherit [handlesToInheritCount ++ ] = hStdError ;
686+ tb_process_add_inheritable_handle (handlesToInherit , & handlesToInheritCount , tb_arrayn (handlesToInherit ), hStdError );
632687 }
633688 }
634689 }
0 commit comments