Skip to content

Commit d0138aa

Browse files
authored
Merge pull request #310 from luadebug/win7
Refactor handle inheritance logic in process.c
2 parents e5236a8 + 2eb1800 commit d0138aa

File tree

3 files changed

+93
-18
lines changed

3 files changed

+93
-18
lines changed

src/tbox/platform/windows/interface/kernel32.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ static tb_bool_t tb_kernel32_instance_init(tb_kernel32_ref_t kernel32)
6868
TB_INTERFACE_LOAD(kernel32, CopyFileExW);
6969
TB_INTERFACE_LOAD(kernel32, PeekConsoleInputW);
7070
TB_INTERFACE_LOAD(kernel32, PeekNamedPipe);
71+
TB_INTERFACE_LOAD(kernel32, VerifyVersionInfoW);
72+
TB_INTERFACE_LOAD(kernel32, VerSetConditionMask);
7173
#if defined(TB_COMPILER_IS_MSVC) && TB_COMPILER_VERSION_BT(16, 0)
7274
TB_INTERFACE_LOAD(kernel32, GetLogicalProcessorInformationEx);
7375
#endif

src/tbox/platform/windows/interface/kernel32.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,18 @@ typedef BOOL (WINAPI* tb_kernel32_PeekNamedPipe_t)(
213213
LPDWORD lpTotalBytesAvail,
214214
LPDWORD lpBytesLeftThisMessage);
215215

216+
// the VerifyVersionInfoW func type
217+
typedef BOOL (WINAPI* tb_kernel32_VerifyVersionInfoW_t)(
218+
LPOSVERSIONINFOEXW lpVersionInformation,
219+
DWORD dwTypeMask,
220+
DWORDLONG dwlConditionMask);
221+
222+
// the VerSetConditionMask func type
223+
typedef ULONGLONG (WINAPI* tb_kernel32_VerSetConditionMask_t)(
224+
ULONGLONG ConditionMask,
225+
DWORD TypeMask,
226+
BYTE Condition);
227+
216228
// the kernel32 interfaces type
217229
typedef struct __tb_kernel32_t
218230
{
@@ -300,6 +312,12 @@ typedef struct __tb_kernel32_t
300312
// PeekNamedPipe
301313
tb_kernel32_PeekNamedPipe_t PeekNamedPipe;
302314

315+
// VerifyVersionInfoW
316+
tb_kernel32_VerifyVersionInfoW_t VerifyVersionInfoW;
317+
318+
// VerSetConditionMask
319+
tb_kernel32_VerSetConditionMask_t VerSetConditionMask;
320+
303321
// GetLogicalProcessorInformationEx
304322
#if defined(TB_COMPILER_IS_MSVC) && TB_COMPILER_VERSION_BT(16, 0)
305323
tb_kernel32_GetLogicalProcessorInformationEx_t GetLogicalProcessorInformationEx;

src/tbox/platform/windows/process.c

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)