fix: adjust trampoline close_handles invalid to be safer (#6792)

## Summary

Closes https://github.com/astral-sh/uv/issues/6699

On cases like the ones described in
https://github.com/astral-sh/uv/issues/6699, `lpReserved2` somehow seems
to report multiple file descriptors that were not tied to any valid
handles. The previous implementation was faulting as it would try to
dereference these invalid handles. This change moves to using `HANDLE`
directly and check if its is_invalid instead before attempting to close
them.

## Test Plan

Manually tested and verified using `busybox-w32` like described in the
issue.

---------

Co-authored-by: konstin <konstin@mailbox.org>
This commit is contained in:
samypr100 2024-08-30 04:55:27 -04:00 committed by GitHub
parent c91c99b35e
commit 8674968a17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 9 additions and 7 deletions

View File

@ -13,8 +13,7 @@ use windows::Win32::{
TRUE,
},
System::Console::{
GetStdHandle, SetConsoleCtrlHandler, SetStdHandle, STD_ERROR_HANDLE, STD_INPUT_HANDLE,
STD_OUTPUT_HANDLE,
GetStdHandle, SetConsoleCtrlHandler, SetStdHandle, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
},
System::Environment::GetCommandLineA,
System::JobObjects::{
@ -329,7 +328,8 @@ fn spawn_child(si: &STARTUPINFOA, child_cmdline: CString) -> HANDLE {
// https://github.com/huangqinjin/ucrt/blob/10.0.19041.0/lowio/ioinit.cpp#L190-L223
fn close_handles(si: &STARTUPINFOA) {
// See distlib/PC/launcher.c::cleanup_standard_io()
for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE] {
// Unlike cleanup_standard_io(), we don't close STD_ERROR_HANDLE to retain eprintln!
for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE] {
if let Ok(handle) = unsafe { GetStdHandle(std_handle) } {
unsafe { CloseHandle(handle) }.unwrap_or_else(|_| {
eprintln!("Failed to close standard device handle {}", handle.0 as u32);
@ -348,12 +348,14 @@ fn close_handles(si: &STARTUPINFOA) {
let handle_count = unsafe { crt_magic.read_unaligned() } as isize;
let handle_start = unsafe { crt_magic.offset(1 + handle_count) };
for i in 0..handle_count {
let handle_ptr = unsafe { handle_start.offset(i).read_unaligned() } as *const HANDLE;
let handle = HANDLE(unsafe { handle_start.offset(i).read_unaligned() as _ });
// Close all fds inherited from the parent, except for the standard I/O fds.
unsafe { CloseHandle(*handle_ptr) }.unwrap_or_else(|_| {
if !handle.is_invalid() {
unsafe { CloseHandle(handle) }.unwrap_or_else(|_| {
eprintln!("Failed to close child file descriptors at {}", i);
});
}
}
}
/*