Avoid zeroing a 1kb stack buffer on every call to `std::sys::windows::fill_utf16_buf`

This commit is contained in:
Thom Chiovoloni 2022-08-18 14:51:10 -07:00
parent 8064a49508
commit f50f8782fe
No known key found for this signature in database
GPG Key ID: D7733D1D7A775F0A
1 changed files with 13 additions and 5 deletions

View File

@ -2,6 +2,7 @@
use crate::ffi::{CStr, OsStr, OsString};
use crate::io::ErrorKind;
use crate::mem::MaybeUninit;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::time::Duration;
@ -204,8 +205,8 @@ where
// This initial size also works around `GetFullPathNameW` returning
// incorrect size hints for some short paths:
// https://github.com/dylni/normpath/issues/5
let mut stack_buf = [0u16; 512];
let mut heap_buf = Vec::new();
let mut stack_buf: [MaybeUninit<u16>; 512] = MaybeUninit::uninit_array();
let mut heap_buf: Vec<MaybeUninit<u16>> = Vec::new();
unsafe {
let mut n = stack_buf.len();
loop {
@ -214,6 +215,11 @@ where
} else {
let extra = n - heap_buf.len();
heap_buf.reserve(extra);
// We used `reserve` and not `reserve_exact`, so in theory we
// may have gotten more than requested. If so, we'd like to use
// it... so long as we won't cause overflow.
n = heap_buf.capacity().min(c::DWORD::MAX as usize);
// Safety: MaybeUninit<u16> does not need initialization
heap_buf.set_len(n);
&mut heap_buf[..]
};
@ -228,13 +234,13 @@ where
// error" is still 0 then we interpret it as a 0 length buffer and
// not an actual error.
c::SetLastError(0);
let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
let k = match f1(buf.as_mut_ptr().cast::<u16>(), n as c::DWORD) {
0 if c::GetLastError() == 0 => 0,
0 => return Err(crate::io::Error::last_os_error()),
n => n,
} as usize;
if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
n *= 2;
n = n.saturating_mul(2).min(c::DWORD::MAX as usize);
} else if k > n {
n = k;
} else if k == n {
@ -244,7 +250,9 @@ where
// Therefore k never equals n.
unreachable!();
} else {
return Ok(f2(&buf[..k]));
// Safety: First `k` bytes are initialized.
let slice: &[u16] = MaybeUninit::slice_assume_init_ref(&buf[..k]);
return Ok(f2(slice));
}
}
}