Closed MaulingMonkey closed 2 years ago
Being able to Deref from OwnedHandle
-> BorrowedHandle<'a>
-> PsuedoHandle<'a>
would be ideal, and is almost doable:
#![forbid(unsafe_op_in_unsafe_fn)]
use core::ffi::c_void;
use core::mem::transmute;
use core::ops::*;
use core::ptr::NonNull;
type HANDLE = *mut c_void;
fn some_handle() -> HANDLE { 0xF0usize as _ }
#[repr(transparent)] pub struct OwnedHandle(NonNull<c_void>);
#[repr(transparent)] pub struct BorrowedHandleValue(c_void);
#[repr(transparent)] pub struct PsuedoHandleValue (c_void);
pub type BorrowedHandle<'a> = &'a BorrowedHandleValue;
pub type PsuedoHandle<'a> = &'a PsuedoHandleValue;
impl Deref for OwnedHandle { type Target = BorrowedHandleValue; fn deref(&self) -> BorrowedHandle { unsafe { transmute(self.0) } } }
impl Deref for BorrowedHandleValue { type Target = PsuedoHandleValue; fn deref(&self) -> PsuedoHandle { unsafe { transmute(self ) } } }
impl OwnedHandle { pub unsafe fn from_raw(handle: HANDLE) -> Option<Self> { Some(Self(NonNull::new(handle)?)) } }
fn main() {
let owned : OwnedHandle = unsafe { OwnedHandle::from_raw(some_handle()) }.unwrap();
let borrowed : BorrowedHandle = &*owned;
let psuedo : PsuedoHandle = &**owned;
requires_owned(&owned);
requires_borrowed(&owned);
requires_psuedo(&owned);
requires_borrowed(borrowed);
requires_psuedo(borrowed);
requires_psuedo(psuedo);
}
fn requires_owned(_: &OwnedHandle) {}
fn requires_borrowed(_: BorrowedHandle) {}
fn requires_psuedo(_: PsuedoHandle) {}
However, this angers Miri and invokes Undefined Behavior:
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address 0xf0 is unallocated)
--> src/main.rs:17:118
|
17 | impl Deref for OwnedHandle { type Target = BorrowedHandleValue; fn deref(&self) -> BorrowedHandle { unsafe { transmute(self.0) } } }
| ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0xf0 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: backtrace:
= note: inside `<OwnedHandle as std::ops::Deref>::deref` at src/main.rs:17:118
note: inside `main` at src/main.rs:24:38
--> src/main.rs:24:38
|
24 | let borrowed : BorrowedHandle = &*owned;
| ^^^^^^
AsRef and From/Into spam is occasionally awkward, but it's not the absolute worst
#![forbid(unsafe_op_in_unsafe_fn)]
use core::ffi::c_void;
use core::marker::PhantomData;
use core::mem::transmute;
use core::ops::*;
use core::ptr::NonNull;
type HANDLE = *mut c_void;
// &'a Owned = borrowed handle, but not C struct FFI compatible (extra indirection: ~NonNull<NonNull<c_void>>, not NonNull<c_void>)
// Handle<'a> = borrowed handle
// Psuedo<'a> = borrowed handle or psuedo handle
#[repr(transparent)] pub struct Owned (NonNull<c_void>);
#[derive(Clone, Copy)] #[repr(transparent)] pub struct Handle<'a>(NonNull<c_void>, PhantomData<&'a c_void>);
#[derive(Clone, Copy)] #[repr(transparent)] pub struct Psuedo<'a>(NonNull<c_void>, PhantomData<&'a c_void>);
// impl Clone for Owned via DuplicateHandle?
impl Drop for Owned { fn drop(&mut self) { /* CloseHandle(...) */ } }
impl Owned { pub unsafe fn from_raw(handle: HANDLE) -> Option<Self> { Some(Self(NonNull::new(handle)?)) } }
impl Psuedo<'static> { pub unsafe fn from_raw(handle: HANDLE) -> Option<Self> { Some(Self(NonNull::new(handle)?, PhantomData)) } }
impl AsRef<Owned > for Owned { fn as_ref(&self) -> &Owned { self } }
impl<'a> AsRef<Handle<'a>> for &'a Owned { fn as_ref(&self) -> &Handle<'a> { unsafe { transmute(*self) } } }
impl<'a> AsRef<Psuedo<'a>> for &'a Owned { fn as_ref(&self) -> &Psuedo<'a> { unsafe { transmute(*self) } } }
impl<'a> AsRef<Handle<'a>> for Handle<'a> { fn as_ref(&self) -> &Handle<'a> { self } }
impl<'a> AsRef<Psuedo<'a>> for Handle<'a> { fn as_ref(&self) -> &Psuedo<'a> { unsafe { transmute(self) } } }
impl<'a> AsRef<Psuedo<'a>> for Psuedo<'a> { fn as_ref(&self) -> &Psuedo<'a> { self } }
impl<'a> From<&'a Owned > for Handle<'a> { fn from(h: &'a Owned ) -> Self { Self(h.0, PhantomData) } }
impl<'a> From<&'a Owned > for Psuedo<'a> { fn from(h: &'a Owned ) -> Self { Self(h.0, PhantomData) } }
impl<'a> From<Handle<'a>> for Psuedo<'a> { fn from(h: Handle<'a>) -> Self { Self(h.0, PhantomData) } }
fn get_current_process() -> Psuedo<'static> { unsafe { Psuedo::from_raw(!0usize as _) }.unwrap() } // ~ GetCurrentProcess()
fn open_current_process() -> Owned { unsafe { Owned::from_raw(42usize as _) }.unwrap() } // TODO: DuplicateHandle(...) to turn a psuedo-handle into a real one
#[repr(C)] struct Struct<'a> { handle: Option<Handle<'a>> }
fn main() {
let owned : Owned = open_current_process();
let psuedo : Psuedo = get_current_process();
let mut some_struct = Struct { handle: None };
some_struct.handle = Some((&owned).into());
// some_struct.handle = Some((&psuedo).into()); // forbidden: Struct requires a real handle, not a psuedo handle
let borrowed : Handle = some_struct.handle.unwrap();
requires_owned (&owned);
requires_handle(&owned);
requires_psuedo(&owned);
// drop(owned); // forbidden: still borrowed by `borrowed`
requires_handle(borrowed);
requires_psuedo(borrowed);
drop(owned);
requires_psuedo(psuedo);
}
fn requires_owned (_: impl AsRef<Owned >) {}
fn requires_handle<'a>(_: impl AsRef<Handle<'a>>) {}
fn requires_psuedo<'a>(_: impl AsRef<Psuedo<'a>>) {}
Kernel Object Types
https://docs.microsoft.com/en-us/windows/win32/sysinfo/kernel-objects
Storage
Ownership