Skip to content

Commit

Permalink
capi: correctly mark Leakable methods as unsafe
Browse files Browse the repository at this point in the history
These methods were only ever used internally, but just to be safe make
sure they're properly marked as unsafe.

Signed-off-by: Aleksa Sarai <[email protected]>
  • Loading branch information
cyphar committed Jul 18, 2024
1 parent cf5c899 commit 45ca5c1
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/capi/ret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,5 @@ pub extern "C" fn pathrs_errorinfo_free(ptr: *mut CError) {

// SAFETY: The C caller guarantees that the pointer is of the correct type
// and that this isn't a double-free.
unsafe { &mut *ptr }.free()
unsafe { (&mut *ptr).free() }
}
28 changes: 16 additions & 12 deletions src/capi/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ pub(crate) trait Leakable {
/// Leak a structure such that it can be passed through C-FFI.
fn leak(self) -> &'static mut Self;

/// Given a structure leaked through Leakable::leak, un-leak it. Callers
/// must be sure to only ever call this once on a given pointer (otherwise
/// memory corruption will occur).
fn unleak(&'static mut self) -> Self;
/// Given a structure leaked through Leakable::leak, un-leak it.
///
/// SAFETY: Callers must be sure to only ever call this once on a given
/// pointer (otherwise memory corruption will occur).
unsafe fn unleak(&'static mut self) -> Self;

/// Shorthand for `std::mem::drop(self.unleak())`.
fn free(&'static mut self);
///
/// SAFETY: Same unsafety issue as `self.unleak()`.
unsafe fn free(&'static mut self);
}

/// A macro to implement the trivial methods of Leakable -- due to a restriction
Expand All @@ -50,15 +53,16 @@ macro_rules! leakable {
Box::leak(Box::new(self))
}

fn unleak(&'static mut self) -> Self {
// SAFETY: Box::from_raw is safe because the C caller guarantees
// that the pointer we get is the same one we gave them, and
// it will only ever be called once with the same pointer.
unsafe fn unleak(&'static mut self) -> Self {
// SAFETY: Box::from_raw is safe because the caller guarantees that
// the pointer we get is the same one we gave them, and it will only
// ever be called once with the same pointer.
*unsafe { Box::from_raw(self as *mut Self) }
}

fn free(&'static mut self) {
let _ = self.unleak();
unsafe fn free(&'static mut self) {
// SAFETY: Caller guarantees this is safe to do.
let _ = unsafe { self.unleak() };
// drop Self
}
};
Expand All @@ -69,7 +73,7 @@ macro_rules! leakable {
}
};

(impl <$($generics:tt),+> Leakable for $type:ty ;) => {
(impl<$($generics:tt),+> Leakable for $type:ty ;) => {
impl<$($generics),+> Leakable for $type {
leakable!(...);
}
Expand Down

0 comments on commit 45ca5c1

Please sign in to comment.