diff --git a/crates/libs/windows/src/core/heap.rs b/crates/libs/windows/src/core/heap.rs index 25b8aa7389..e1a3bc77c9 100644 --- a/crates/libs/windows/src/core/heap.rs +++ b/crates/libs/windows/src/core/heap.rs @@ -32,20 +32,32 @@ pub unsafe fn heap_free(ptr: RawPtr) { } } -/// Copy a slice of `T` into a freshly allocated buffer with an additional default `T` at the end. +/// Copy len elements of an iterator of type `T` into a freshly allocated buffer. /// -/// Returns a pointer to the beginning of the buffer +/// Returns a pointer to the beginning of the buffer. This pointer must be freed when done using `heap_free`. /// /// # Panics /// -/// This function panics if the heap allocation fails or if the pointer returned from -/// the heap allocation is not properly aligned to `T`. -pub fn heap_string(slice: &[T]) -> *const T { - unsafe { - let buffer = heap_alloc((slice.len() + 1) * std::mem::size_of::()).expect("could not allocate string") as *mut T; - assert!(buffer.align_offset(std::mem::align_of::()) == 0, "heap allocated buffer is not properly aligned"); - buffer.copy_from_nonoverlapping(slice.as_ptr(), slice.len()); - buffer.add(slice.len()).write(T::default()); - buffer +/// This function panics if the heap allocation fails, the alignment requirements of 'T' surpass +/// 8 (HeapAlloc's alignment). +pub fn alloc_from_iter(iter: I, len: usize) -> *const T +where + I: Iterator, + T: Copy, +{ + // alignment of memory returned by HeapAlloc is at least 8 + // Source: https://docs.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc + // Ensure that T has sufficient alignment requirements + assert!(std::mem::align_of::() <= 8, "T alignment surpasses HeapAlloc alignment"); + + let ptr = heap_alloc(len * std::mem::size_of::()).expect("could not allocate string") as *mut T; + + for (offset, c) in iter.take(len).enumerate() { + // SAFETY: ptr points to an allocation object of size `len`, indices accessed are always lower than `len` + unsafe { + ptr.add(offset).write(c); + } } + + ptr } diff --git a/crates/libs/windows/src/core/pcstr.rs b/crates/libs/windows/src/core/pcstr.rs index e5b9d7aee2..0fbcd2b25d 100644 --- a/crates/libs/windows/src/core/pcstr.rs +++ b/crates/libs/windows/src/core/pcstr.rs @@ -45,7 +45,7 @@ unsafe impl Abi for PCSTR { #[cfg(feature = "alloc")] impl<'a> IntoParam<'a, PCSTR> for &str { fn into_param(self) -> Param<'a, PCSTR> { - Param::Boxed(PCSTR(heap_string(self.as_bytes()))) + Param::Boxed(PCSTR(alloc_from_iter(self.as_bytes().iter().copied().chain(core::iter::once(0)), self.len() + 1))) } } #[cfg(feature = "alloc")] diff --git a/crates/libs/windows/src/core/pcwstr.rs b/crates/libs/windows/src/core/pcwstr.rs index 9a83a18cc5..7966162b0b 100644 --- a/crates/libs/windows/src/core/pcwstr.rs +++ b/crates/libs/windows/src/core/pcwstr.rs @@ -45,7 +45,7 @@ unsafe impl Abi for PCWSTR { #[cfg(feature = "alloc")] impl<'a> IntoParam<'a, PCWSTR> for &str { fn into_param(self) -> Param<'a, PCWSTR> { - Param::Boxed(PCWSTR(heap_string(&self.encode_utf16().collect::>()))) + Param::Boxed(PCWSTR(alloc_from_iter(self.encode_utf16().chain(core::iter::once(0)), self.len() + 1))) } } #[cfg(feature = "alloc")] @@ -58,7 +58,7 @@ impl<'a> IntoParam<'a, PCWSTR> for alloc::string::String { impl<'a> IntoParam<'a, PCWSTR> for &::std::ffi::OsStr { fn into_param(self) -> Param<'a, PCWSTR> { use ::std::os::windows::ffi::OsStrExt; - Param::Boxed(PCWSTR(heap_string(&self.encode_wide().collect::>()))) + Param::Boxed(PCWSTR(alloc_from_iter(self.encode_wide().chain(core::iter::once(0)), self.len() + 1))) } } #[cfg(feature = "alloc")]