Ensure that `HSTRING` builder provides initialized memory (#3141)
This commit is contained in:
Родитель
12a60df721
Коммит
f6c49f4f5e
|
@ -9,7 +9,13 @@ pub struct HStringBuilder(*mut HStringHeader);
|
||||||
impl HStringBuilder {
|
impl HStringBuilder {
|
||||||
/// Creates a preallocated `HSTRING` value.
|
/// Creates a preallocated `HSTRING` value.
|
||||||
pub fn new(len: usize) -> Result<Self> {
|
pub fn new(len: usize) -> Result<Self> {
|
||||||
Ok(Self(HStringHeader::alloc(len.try_into()?)?))
|
let header = HStringHeader::alloc(len.try_into()?)?;
|
||||||
|
|
||||||
|
if len > 0 {
|
||||||
|
unsafe { core::ptr::write_bytes((*header).data, 0, len) };
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(header))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shortens the string by removing any trailing 0 characters.
|
/// Shortens the string by removing any trailing 0 characters.
|
||||||
|
|
|
@ -14,18 +14,18 @@ pub struct HStringHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HStringHeader {
|
impl HStringHeader {
|
||||||
pub fn alloc(len: u32) -> Result<*mut HStringHeader> {
|
pub fn alloc(len: u32) -> Result<*mut Self> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(core::ptr::null_mut());
|
return Ok(core::ptr::null_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate enough space for header and two bytes per character.
|
// Allocate enough space for header and two bytes per character.
|
||||||
// The space for the terminating null character is already accounted for inside of `HStringHeader`.
|
// The space for the terminating null character is already accounted for inside of `HStringHeader`.
|
||||||
let bytes = core::mem::size_of::<HStringHeader>() + 2 * len as usize;
|
let bytes = core::mem::size_of::<Self>() + 2 * len as usize;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let header = unsafe { bindings::HeapAlloc(bindings::GetProcessHeap(), 0, bytes) }
|
let header =
|
||||||
as *mut HStringHeader;
|
unsafe { bindings::HeapAlloc(bindings::GetProcessHeap(), 0, bytes) } as *mut Self;
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
let header = unsafe {
|
let header = unsafe {
|
||||||
|
@ -33,7 +33,7 @@ impl HStringHeader {
|
||||||
fn malloc(bytes: usize) -> *mut core::ffi::c_void;
|
fn malloc(bytes: usize) -> *mut core::ffi::c_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
malloc(bytes) as *mut HStringHeader
|
malloc(bytes) as *mut Self
|
||||||
};
|
};
|
||||||
|
|
||||||
if header.is_null() {
|
if header.is_null() {
|
||||||
|
@ -42,7 +42,7 @@ impl HStringHeader {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// Use `ptr::write` (since `header` is unintialized). `HStringHeader` is safe to be all zeros.
|
// Use `ptr::write` (since `header` is unintialized). `HStringHeader` is safe to be all zeros.
|
||||||
header.write(core::mem::MaybeUninit::<HStringHeader>::zeroed().assume_init());
|
header.write(core::mem::MaybeUninit::<Self>::zeroed().assume_init());
|
||||||
(*header).len = len;
|
(*header).len = len;
|
||||||
(*header).count = RefCount::new(1);
|
(*header).count = RefCount::new(1);
|
||||||
(*header).data = &mut (*header).buffer_start;
|
(*header).data = &mut (*header).buffer_start;
|
||||||
|
@ -51,17 +51,13 @@ impl HStringHeader {
|
||||||
Ok(header)
|
Ok(header)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn free(header: *mut HStringHeader) {
|
pub unsafe fn free(header: *mut Self) {
|
||||||
if header.is_null() {
|
if header.is_null() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let header = header as *mut _;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
bindings::HeapFree(bindings::GetProcessHeap(), 0, header as *mut _);
|
||||||
bindings::HeapFree(bindings::GetProcessHeap(), 0, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
{
|
{
|
||||||
|
@ -69,18 +65,18 @@ impl HStringHeader {
|
||||||
fn free(ptr: *mut core::ffi::c_void);
|
fn free(ptr: *mut core::ffi::c_void);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(header);
|
free(header as *mut _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn duplicate(&self) -> Result<*mut HStringHeader> {
|
pub fn duplicate(&self) -> Result<*mut Self> {
|
||||||
if self.flags & HSTRING_REFERENCE_FLAG == 0 {
|
if self.flags & HSTRING_REFERENCE_FLAG == 0 {
|
||||||
// If this is not a "fast pass" string then simply increment the reference count.
|
// If this is not a "fast pass" string then simply increment the reference count.
|
||||||
self.count.add_ref();
|
self.count.add_ref();
|
||||||
Ok(self as *const HStringHeader as *mut HStringHeader)
|
Ok(self as *const Self as *mut Self)
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, allocate a new string and copy the value into the new string.
|
// Otherwise, allocate a new string and copy the value into the new string.
|
||||||
let copy = HStringHeader::alloc(self.len)?;
|
let copy = Self::alloc(self.len)?;
|
||||||
// SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
|
// SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
|
||||||
// We copy `len + 1` characters since `len` does not account for the terminating null character.
|
// We copy `len + 1` characters since `len` does not account for the terminating null character.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -47,5 +47,9 @@ fn hstring_builder() -> Result<()> {
|
||||||
assert_eq!(h.len(), 5);
|
assert_eq!(h.len(), 5);
|
||||||
assert_eq!(h.as_wide(), HELLO);
|
assert_eq!(h.as_wide(), HELLO);
|
||||||
|
|
||||||
|
// HStringBuilder will initialize memory to zero.
|
||||||
|
let b = HStringBuilder::new(5)?;
|
||||||
|
assert_eq!(*b, [0, 0, 0, 0, 0]);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче