#![allow(clippy::undocumented_unsafe_blocks)]
use core::ffi::c_void;
#[derive(Debug)]
pub(crate) struct LocalAllocGuard<T> {
ptr: *mut T,
}
impl<T> LocalAllocGuard<T> {
pub(crate) unsafe fn from_raw(ptr: *mut T) -> Self {
Self { ptr }
}
pub(crate) fn as_ptr(&self) -> *mut T {
self.ptr
}
#[allow(dead_code)]
pub(crate) fn into_raw(mut self) -> *mut T {
let p = self.ptr;
self.ptr = core::ptr::null_mut();
p
}
}
impl<T> Drop for LocalAllocGuard<T> {
fn drop(&mut self) {
if !self.ptr.is_null() {
local_free(self.ptr.cast::<c_void>());
self.ptr = core::ptr::null_mut();
}
}
}
impl LocalAllocGuard<u16> {
pub(crate) unsafe fn to_string_lossy(&self) -> String {
if self.ptr.is_null() {
return String::new();
}
let mut len = 0usize;
while unsafe { *self.ptr.add(len) } != 0 {
len += 1;
}
let slice = unsafe { core::slice::from_raw_parts(self.ptr, len) };
String::from_utf16_lossy(slice)
}
}
#[derive(Debug)]
pub(crate) struct CoTaskMem<T> {
ptr: *mut T,
}
impl<T> CoTaskMem<T> {
pub(crate) unsafe fn from_raw(ptr: *mut T) -> Self {
Self { ptr }
}
pub(crate) fn as_ptr(&self) -> *mut T {
self.ptr
}
#[allow(dead_code)]
pub(crate) fn into_raw(mut self) -> *mut T {
let p = self.ptr;
self.ptr = core::ptr::null_mut();
p
}
}
impl<T> Drop for CoTaskMem<T> {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe {
windows::Win32::System::Com::CoTaskMemFree(Some(self.ptr.cast::<c_void>()));
}
self.ptr = core::ptr::null_mut();
}
}
}
#[cfg(windows)]
#[link(name = "Kernel32")]
unsafe extern "system" {
fn LocalFree(h: isize) -> isize;
}
#[cfg(windows)]
fn local_free(ptr: *mut c_void) {
unsafe {
let _ = LocalFree(ptr as isize);
}
}
#[cfg(test)]
#[cfg(windows)]
mod tests {
use super::*;
use windows::Win32::Security::Authorization::{ConvertSidToStringSidW, ConvertStringSidToSidW};
use windows::core::PCWSTR;
#[test]
fn localalloc_guard_round_trip_string_sid() {
unsafe {
let sddl = super::super::wstr::WideString::from_str("S-1-5-32-544");
let mut psid = windows::Win32::Security::PSID::default();
ConvertStringSidToSidW(PCWSTR(sddl.as_pcwstr().0), &mut psid)
.expect("ConvertStringSidToSidW");
let mut out = windows::core::PWSTR::null();
ConvertSidToStringSidW(psid, &mut out).expect("ConvertSidToStringSidW");
let s = LocalAllocGuard::<u16> { ptr: out.0 }.to_string_lossy();
assert!(s.starts_with("S-1-5-32-544"));
let _ = LocalAllocGuard::<core::ffi::c_void>::from_raw(psid.0);
}
}
}