From patchwork Thu Feb 6 16:24:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamir Duberstein X-Patchwork-Id: 13963305 Received: from mail-qk1-f179.google.com (mail-qk1-f179.google.com [209.85.222.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5D4323645D; Thu, 6 Feb 2025 16:24:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.222.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738859095; cv=none; b=Hya0PuXvnkwtHnBHqLWnpQIsGQ+71Mql+NTHu2NOKXt+sI916nK/5dYxKeZktPIGUSOEEVMmxUqQ6sA3pxiOdEiPMKcwIMqEDOMXxALFzkXsCoaSVr1/gTnMo/3HodSg2OeSyA7Ho8J5yeJvYppGVAOp763aMX9chQzQgZTH+7s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738859095; c=relaxed/simple; bh=KV9oFpyRHvIgJJglZ1PvCei21FEuloF6XP6yVbmEeNw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=O8rHX3qwdVFYKmPnLYU5xlQHamYHQWKGAqJJfnrd1b+shLR6r81mpMwWF8YlVBg4jPIZ5uYO7Zb6a3RdK7Wynnv4o6t0ItiNqX0UcJdsTO99+uUbpMDyIHB4sS8zVysp/qkvhag6Mx4MgpiiwN3HDsvtS8BTFjWT3wWmUszj96g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=NXI4qTRz; arc=none smtp.client-ip=209.85.222.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NXI4qTRz" Received: by mail-qk1-f179.google.com with SMTP id af79cd13be357-7bcf33f698dso96832585a.2; Thu, 06 Feb 2025 08:24:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1738859092; x=1739463892; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=UYQ0XvquT6hYA9s74+tEED+m5QKgjIG6l9kLMfBz/ak=; b=NXI4qTRznJ60V98U47gASbWT9iO2Rv45hQ+N9SdOHTvWBKLZIIzZk0eNP0kxJYJVkp CsGr+jU/GVWbo9Z5L1B35x+8A0ugsDcBrpqI4EvFKgo9r6GTER6KBKbwi0kW6jzlbaeS SB2KY10MtYYm7AOb7shT2pxTMGbUU1JjT5plcH/s3PfYkHjg6Fb4mOdNCbNhoqXjWf3v Mm3wH6mSKiIKBGEuaZUlY/qlB4JoX1TUs8xGz7KAkvXHquMamtiqMWcege7vpD+aexqP wsi33o3uRyqiad0rQg4FWmEhIoNx+Yjh1IAEFQ5gT0L7lWI3dbIsVszAZ223dejijIrO 2p1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738859092; x=1739463892; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UYQ0XvquT6hYA9s74+tEED+m5QKgjIG6l9kLMfBz/ak=; b=Z2HHoPhFyjy4gyjHjsCQ82mO6enHl3QK8U2EBM8COa7lKJR355s49Jq6bv1HP+H7lv pQvorcrgxGD78vdFBL/zwIcjEt9NU8bO9Q9k8TaTsAcNzOEx4qcca94OLPjTli5Z+9Jn MkVFp3rmhqFLnoOj2BIE1DpBwWqA6lumKgAByzjYX98tFj188pXqLlyS3VmDlyxF1S7G UOolla+OQng36SPUjVgHObgCXgkr/vH/tVjbAzzbX4ERK+rz0PsDmV2Luh8R1GAovbNB R7Yz14Hz0nPUb/xzDmkyjhxynj73a6R930DTrGuOCzS4ydlsEyPgSc5+OIPC/VyU8jfz P09Q== X-Forwarded-Encrypted: i=1; AJvYcCUCw6YFWG0dRJOM/fLouHkvrIKGgs0XWhkU9wWFBEpXdeoNsIsGjBrnLDAwPXiH4xTQLDU7EEXOxGH5Kf0sfBI=@vger.kernel.org, AJvYcCVJTxmkc6sCW36cODrDvOfXTa5nyPQNDVIzJp/2SRnvZdtWtv5BS/qHYqV6qje0cvDFX5IGeVxg856s@vger.kernel.org, AJvYcCVdFCgZdi4Kz/XGComHackY4hujVfQ67Uys97gicCGQSGiJSfUveBYc08kIOlSDHHiQych5QBbnU71AxqVa@vger.kernel.org, AJvYcCWY2J6m1jLdm4CA/6O9URwD1H4V5pJxthRbnkwP1Qd5NPiartIioGqUJdbSqz9/0/hk7g1HXy+jCOAikLP2@vger.kernel.org X-Gm-Message-State: AOJu0Yz+MXtAku4SY1/7+rhx+wCpkq9f93jOF8VX2t0N7YhrYE4SoEpH wQT3tJ/QigSwiQ7DYejC/8c9sttjk6nRZS5twcs9nzTbz278bzLk X-Gm-Gg: ASbGnctWJQ3Yt9Smyg6jgTsEU4BAiZx6M3r1xpGBCYgm1ii+R4O924TzS+saoVSVSVq 1kufBhQeZM6oD4+1FIGGdCLRiNbZEBlIRDLsbaP4rJS7CY0i+Byp5lZppmt0DRdNJzYiDYsxpdj uEGllV+Af8ink+v6Z6pEGwFkL5b9bizgEZMuG6QYj6FMO5Q5UYRbN3xXZXai0yAnkZFRJ5PSWYd BR00C6fHCM2y+FAmhPIv2cc8NRvybcZsk9pNGVjjS4W4e231uFx4PDCVvaCUJtDM/TXTz1JP9G7 lZeY5nPFrZYKgP2NonVGUiBUraDGOUYk/QWv X-Google-Smtp-Source: AGHT+IGBUmqjlcra9kdtXjtZ4MSYcD/OdRH0uj1y5Qec1qS08vnUCkdyoSkN3nmVpDIgGpRbolnkwg== X-Received: by 2002:a05:620a:4103:b0:7b1:41b8:9ed7 with SMTP id af79cd13be357-7c039fc0b18mr937878385a.16.1738859092343; Thu, 06 Feb 2025 08:24:52 -0800 (PST) Received: from tamird-mac.local ([2600:4041:5be7:7c00:fb:aded:686f:8a03]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7c041eb8e09sm76440685a.102.2025.02.06.08.24.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 Feb 2025 08:24:51 -0800 (PST) From: Tamir Duberstein Date: Thu, 06 Feb 2025 11:24:43 -0500 Subject: [PATCH v15 1/3] rust: types: add `ForeignOwnable::PointedTo` Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250206-rust-xarray-bindings-v15-1-a22b5dcacab3@gmail.com> References: <20250206-rust-xarray-bindings-v15-0-a22b5dcacab3@gmail.com> In-Reply-To: <20250206-rust-xarray-bindings-v15-0-a22b5dcacab3@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev Allow implementors to specify the foreign pointer type; this exposes information about the pointed-to type such as its alignment. This requires the trait to be `unsafe` since it is now possible for implementors to break soundness by returning a misaligned pointer. Encoding the pointer type in the trait (and avoiding pointer casts) allows the compiler to check that implementors return the correct pointer type. This is preferable to directly encoding the alignment in the trait using a constant as the compiler would be unable to check it. Reviewed-by: Andreas Hindborg Signed-off-by: Tamir Duberstein --- rust/kernel/alloc/kbox.rs | 38 ++++++++++++++++++++------------------ rust/kernel/miscdevice.rs | 7 ++++++- rust/kernel/pci.rs | 5 ++++- rust/kernel/platform.rs | 5 ++++- rust/kernel/sync/arc.rs | 21 ++++++++++++--------- rust/kernel/types.rs | 46 +++++++++++++++++++++++++++++++--------------- 6 files changed, 77 insertions(+), 45 deletions(-) diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index cb4ebea3b074..55529832db54 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -349,68 +349,70 @@ fn try_init(init: impl Init, flags: Flags) -> Result } } -impl ForeignOwnable for Box +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. +unsafe impl ForeignOwnable for Box where A: Allocator, { + type PointedTo = T; type Borrowed<'a> = &'a T; type BorrowedMut<'a> = &'a mut T; - fn into_foreign(self) -> *mut crate::ffi::c_void { - Box::into_raw(self).cast() + fn into_foreign(self) -> *mut Self::PointedTo { + Box::into_raw(self) } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr.cast()) } + unsafe { Box::from_raw(ptr) } } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T { // SAFETY: The safety requirements of this method ensure that the object remains alive and // immutable for the duration of 'a. - unsafe { &*ptr.cast() } + unsafe { &*ptr } } - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T { - let ptr = ptr.cast(); + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T { // SAFETY: The safety requirements of this method ensure that the pointer is valid and that // nothing else will access the value for the duration of 'a. unsafe { &mut *ptr } } } -impl ForeignOwnable for Pin> +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. +unsafe impl ForeignOwnable for Pin> where A: Allocator, { + type PointedTo = T; type Borrowed<'a> = Pin<&'a T>; type BorrowedMut<'a> = Pin<&'a mut T>; - fn into_foreign(self) -> *mut crate::ffi::c_void { + fn into_foreign(self) -> *mut Self::PointedTo { // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) } + unsafe { Pin::new_unchecked(Box::from_raw(ptr)) } } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for // the lifetime of the returned value. - let r = unsafe { &*ptr.cast() }; + let r = unsafe { &*ptr }; // SAFETY: This pointer originates from a `Pin>`. unsafe { Pin::new_unchecked(r) } } - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut T> { - let ptr = ptr.cast(); + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> { // SAFETY: The safety requirements for this function ensure that the object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the object remains alive for diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index e14433b2ab9d..f1a081dd64c7 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -225,13 +225,15 @@ impl VtableHelper { Ok(ptr) => ptr, Err(err) => return err.to_errno(), }; + let ptr = ptr.into_foreign(); + let ptr = ptr.cast(); // This overwrites the private data with the value specified by the user, changing the type of // this file's private data. All future accesses to the private data is performed by other // fops_* methods in this file, which all correctly cast the private data to the new type. // // SAFETY: The open call of a file can access the private data. - unsafe { (*raw_file).private_data = ptr.into_foreign() }; + unsafe { (*raw_file).private_data = ptr }; 0 } @@ -246,6 +248,7 @@ impl VtableHelper { ) -> c_int { // SAFETY: The release call of a file owns the private data. let private = unsafe { (*file).private_data }; + let private = private.cast(); // SAFETY: The release call of a file owns the private data. let ptr = unsafe { ::from_foreign(private) }; @@ -267,6 +270,7 @@ impl VtableHelper { ) -> c_long { // SAFETY: The ioctl call of a file can access the private data. let private = unsafe { (*file).private_data }; + let private = private.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { ::borrow(private) }; @@ -316,6 +320,7 @@ impl VtableHelper { ) { // SAFETY: The release call of a file owns the private data. let private = unsafe { (*file).private_data }; + let private = private.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device = unsafe { ::borrow(private) }; // SAFETY: diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 4c98b5b9aa1e..eb25fabbff9c 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -72,10 +72,12 @@ extern "C" fn probe_callback( match T::probe(&mut pdev, info) { Ok(data) => { + let data = data.into_foreign(); + let data = data.cast(); // Let the `struct pci_dev` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct pci_dev`. - unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; + unsafe { bindings::pci_set_drvdata(pdev.as_raw(), data) }; } Err(err) => return Error::to_errno(err), } @@ -87,6 +89,7 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { // SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a // `struct pci_dev`. let ptr = unsafe { bindings::pci_get_drvdata(pdev) }; + let ptr = ptr.cast(); // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 50e6b0421813..53764cb7f804 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -63,10 +63,12 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff let info = ::id_info(pdev.as_ref()); match T::probe(&mut pdev, info) { Ok(data) => { + let data = data.into_foreign(); + let data = data.cast(); // Let the `struct platform_device` own a reference of the driver's private data. // SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a // `struct platform_device`. - unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data.into_foreign() as _) }; + unsafe { bindings::platform_set_drvdata(pdev.as_raw(), data) }; } Err(err) => return Error::to_errno(err), } @@ -77,6 +79,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. let ptr = unsafe { bindings::platform_get_drvdata(pdev) }; + let ptr = ptr.cast(); // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 3cefda7a4372..dfe4abf82c25 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -140,9 +140,10 @@ pub struct Arc { _p: PhantomData>, } +#[doc(hidden)] #[pin_data] #[repr(C)] -struct ArcInner { +pub struct ArcInner { refcount: Opaque, data: T, } @@ -342,18 +343,20 @@ pub fn into_unique_or_drop(self) -> Option>> { } } -impl ForeignOwnable for Arc { +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. +unsafe impl ForeignOwnable for Arc { + type PointedTo = ArcInner; type Borrowed<'a> = ArcBorrow<'a, T>; type BorrowedMut<'a> = Self::Borrowed<'a>; - fn into_foreign(self) -> *mut crate::ffi::c_void { - ManuallyDrop::new(self).ptr.as_ptr().cast() + fn into_foreign(self) -> *mut Self::PointedTo { + ManuallyDrop::new(self).ptr.as_ptr() } - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; + let inner = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and @@ -361,17 +364,17 @@ unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { unsafe { Self::from_inner(inner) } } - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // call to `Self::into_foreign`. - let inner = unsafe { NonNull::new_unchecked(ptr.cast::>()) }; + let inner = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> { + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety // requirements for `borrow`. unsafe { Self::borrow(ptr) } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 2bbaab83b9d6..55ddd50e8aaa 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,7 +18,19 @@ /// /// This trait is meant to be used in cases when Rust objects are stored in C objects and /// eventually "freed" back to Rust. -pub trait ForeignOwnable: Sized { +/// +/// # Safety +/// +/// Implementers must ensure that [`into_foreign`] returns a pointer which meets the alignment +/// requirements of [`PointedTo`]. +/// +/// [`into_foreign`]: Self::into_foreign +/// [`PointedTo`]: Self::PointedTo +pub unsafe trait ForeignOwnable: Sized { + /// Type used when the value is foreign-owned. In practical terms only defines the alignment of + /// the pointer. + type PointedTo; + /// Type used to immutably borrow a value that is currently foreign-owned. type Borrowed<'a>; @@ -27,16 +39,18 @@ pub trait ForeignOwnable: Sized { /// Converts a Rust-owned object to a foreign-owned one. /// - /// The foreign representation is a pointer to void. There are no guarantees for this pointer. - /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in - /// any way except for [`from_foreign`], [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can - /// result in undefined behavior. + /// # Guarantees + /// + /// The return value is guaranteed to be well-aligned, but there are no other guarantees for + /// this pointer. For example, it might be null, dangling, or point to uninitialized memory. + /// Using it in any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], + /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. /// /// [`from_foreign`]: Self::from_foreign /// [`try_from_foreign`]: Self::try_from_foreign /// [`borrow`]: Self::borrow /// [`borrow_mut`]: Self::borrow_mut - fn into_foreign(self) -> *mut crate::ffi::c_void; + fn into_foreign(self) -> *mut Self::PointedTo; /// Converts a foreign-owned object back to a Rust-owned one. /// @@ -46,7 +60,7 @@ pub trait ForeignOwnable: Sized { /// must not be passed to `from_foreign` more than once. /// /// [`into_foreign`]: Self::into_foreign - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self; + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self; /// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -58,7 +72,7 @@ pub trait ForeignOwnable: Sized { /// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`]. /// /// [`from_foreign`]: Self::from_foreign - unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { + unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option { if ptr.is_null() { None } else { @@ -81,7 +95,7 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { /// /// [`into_foreign`]: Self::into_foreign /// [`from_foreign`]: Self::from_foreign - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>; + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>; /// Borrows a foreign-owned object mutably. /// @@ -109,21 +123,23 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { /// [`from_foreign`]: Self::from_foreign /// [`borrow`]: Self::borrow /// [`Arc`]: crate::sync::Arc - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a>; + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedMut<'a>; } -impl ForeignOwnable for () { +// SAFETY: The `into_foreign` function returns a pointer that is dangling, but well-aligned. +unsafe impl ForeignOwnable for () { + type PointedTo = (); type Borrowed<'a> = (); type BorrowedMut<'a> = (); - fn into_foreign(self) -> *mut crate::ffi::c_void { + fn into_foreign(self) -> *mut Self::PointedTo { core::ptr::NonNull::dangling().as_ptr() } - unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} + unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {} - unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {} - unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a> {} + unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {} + unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut<'a> {} } /// Runs a cleanup function/closure when dropped.