From 407ce3bae44d51ff594214e9ed71cffc2fd8b527 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 16 Nov 2023 16:44:50 +0200 Subject: [PATCH] Change pass to NonNull + docs on it --- src/pass.rs | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/pass.rs b/src/pass.rs index 80d6e282..8f9240c8 100644 --- a/src/pass.rs +++ b/src/pass.rs @@ -1,33 +1,51 @@ //! Interfaces for passing stuff between the kernel and the userspace -// TODO -#![allow(missing_docs)] + +use core::ptr::NonNull; use crate::error::Error; -// TODO use NonNull instead -pub trait Placer { - fn place_ref(&mut self, r: &T) -> Result<*const T::Output, Error>; - fn place_slice(&mut self, r: &[T]) -> Result<*const [T::Output], Error>; +/// Interface for a "writer", producing objects "owned" by the userspace. +/// +/// # Safety +/// +/// The trait is marked unsafe as it is the implementor's concern that the produced pointers can +/// actually hold the requested values and are properly aligned for that. +pub unsafe trait Placer { + /// Converts a kernel-space reference into a pointer that can be safely dereferenced in + /// userspace + fn place_ref(&mut self, r: &T) -> Result, Error>; + /// Converts a kernel-space slice reference into a slice pointer, elements of which are placed + /// in safely-accessible memory by userspace + fn place_slice(&mut self, r: &[T]) -> Result, Error>; } -pub trait Place { +/// Interface for "transferring ownership" of an object to userspace. +/// +/// # Safety +/// +/// The trait is marked unsafe because it may produce arbitrary pointer, so it's the implementor's +/// concern that they are actually correct. +pub unsafe trait Place { + /// Conversion result type, must be safely accessible from userspace type Output: 'static; + /// Creates a userspace-reachable variant of the internal value fn place(&self, placer: &mut P) -> Result; + /// Converts the internal value using [Place::place] and returns a safe userspace reference fn place_ref(&self, placer: &mut P) -> Result<&'static Self::Output, Error> where Self: Sized, { let ptr = placer.place_ref(self)?; - unsafe { Ok(&*ptr) } + unsafe { Ok(ptr.as_ref()) } } } macro_rules! impl_primitive { ($($ty:ty),+) => { $( - impl $crate::pass::Place for $ty { + unsafe impl $crate::pass::Place for $ty { type Output = $ty; fn place(&self, _placer: &mut P) -> Result<$ty, Error> { @@ -40,25 +58,27 @@ macro_rules! impl_primitive { impl_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, bool, char); -impl<'s> Place for &'s str { +unsafe impl<'s> Place for &'s str { type Output = &'static str; fn place(&self, placer: &mut P) -> Result { let data = placer.place_slice(self.as_bytes())?; // Safety: safe, object passed in was already a proper &str - Ok(unsafe { core::str::from_utf8_unchecked(data.as_ref().unwrap()) }) + Ok(unsafe { core::str::from_utf8_unchecked(data.as_ref()) }) } } -impl Place for [T] { +unsafe impl Place for [T] { type Output = &'static [T::Output]; fn place(&self, placer: &mut P) -> Result { let data = placer.place_slice(self)?; - Ok(unsafe { data.as_ref().unwrap() }) + Ok(unsafe { data.as_ref() }) } } +/// Automatically implements the [Place] interface for a struct, properly handling any nested +/// references #[macro_export] macro_rules! impl_place_lifetime { ( @@ -78,7 +98,7 @@ macro_rules! impl_place_lifetime { ),* } - impl<$struct_lifetime> $crate::pass::Place for $struct_name<$struct_lifetime> { + unsafe impl<$struct_lifetime> $crate::pass::Place for $struct_name<$struct_lifetime> { type Output = $struct_name<'static>; fn place(&self, placer: &mut P)