From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: qemu-rust@nongnu.org
Subject: [PATCH 1/5] rust: qemu_api: introduce MaybeUninit field projection
Date: Mon, 9 Jun 2025 17:44:19 +0200 [thread overview]
Message-ID: <20250609154423.706056-2-pbonzini@redhat.com> (raw)
In-Reply-To: <20250609154423.706056-1-pbonzini@redhat.com>
Add a macro that makes it possible to convert a MaybeUninit<> into
another MaybeUninit<> for a single field within it. Furthermore, it is
possible to use the resulting MaybeUninitField<> in APIs that take the
parent object, such as memory_region_init_io().
This allows removing some of the undefined behavior from instance_init()
functions, though this may not be the definitive implementation.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
rust/qemu-api/meson.build | 1 +
rust/qemu-api/src/lib.rs | 1 +
rust/qemu-api/src/uninit.rs | 85 +++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+)
create mode 100644 rust/qemu-api/src/uninit.rs
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index cac8595a148..33653b4a28e 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -28,6 +28,7 @@ _qemu_api_rs = static_library(
'src/qom.rs',
'src/sysbus.rs',
'src/timer.rs',
+ 'src/uninit.rs',
'src/vmstate.rs',
'src/zeroable.rs',
],
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 93902fc94bc..c78198f0f41 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -27,6 +27,7 @@
pub mod qom;
pub mod sysbus;
pub mod timer;
+pub mod uninit;
pub mod vmstate;
pub mod zeroable;
diff --git a/rust/qemu-api/src/uninit.rs b/rust/qemu-api/src/uninit.rs
new file mode 100644
index 00000000000..a7bed6935b1
--- /dev/null
+++ b/rust/qemu-api/src/uninit.rs
@@ -0,0 +1,85 @@
+//! Access fields of a [`MaybeUninit`](std::mem::MaybeUninit)
+
+use std::{
+ mem::MaybeUninit,
+ ops::{Deref, DerefMut},
+};
+
+pub struct MaybeUninitField<'a, T, U> {
+ parent: &'a mut MaybeUninit<T>,
+ child: *mut U,
+}
+
+impl<'a, T, U> MaybeUninitField<'a, T, U> {
+ #[doc(hidden)]
+ pub fn new(parent: &'a mut MaybeUninit<T>, child: *mut U) -> Self {
+ MaybeUninitField { parent, child }
+ }
+
+ /// Return a constant pointer to the containing object of the field.
+ ///
+ /// Because the `MaybeUninitField` remembers the containing object,
+ /// it is possible to use it in foreign APIs that initialize the
+ /// child.
+ pub fn parent(f: &Self) -> *const T {
+ f.parent.as_ptr()
+ }
+
+ /// Return a mutable pointer to the containing object.
+ ///
+ /// Because the `MaybeUninitField` remembers the containing object,
+ /// it is possible to use it in foreign APIs that initialize the
+ /// child.
+ pub fn parent_mut(f: &mut Self) -> *mut T {
+ f.parent.as_mut_ptr()
+ }
+}
+
+impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> {
+ type Target = MaybeUninit<U>;
+
+ fn deref(&self) -> &MaybeUninit<U> {
+ // SAFETY: self.child was obtained by dereferencing a valid mutable
+ // reference; the content of the memory may be invalid or uninitialized
+ // but MaybeUninit<_> makes no assumption on it
+ unsafe { &*(self.child.cast()) }
+ }
+}
+
+impl<'a, T, U> DerefMut for MaybeUninitField<'a, T, U> {
+ fn deref_mut(&mut self) -> &mut MaybeUninit<U> {
+ // SAFETY: self.child was obtained by dereferencing a valid mutable
+ // reference; the content of the memory may be invalid or uninitialized
+ // but MaybeUninit<_> makes no assumption on it
+ unsafe { &mut *(self.child.cast()) }
+ }
+}
+
+/// ```
+/// #[derive(Debug)]
+/// struct S {
+/// x: u32,
+/// y: u32,
+/// }
+///
+/// # use std::mem::MaybeUninit;
+/// # use qemu_api::{assert_match, uninit_field_mut};
+///
+/// let mut s: MaybeUninit<S> = MaybeUninit::zeroed();
+/// uninit_field_mut!(s, x).write(5);
+/// let s = unsafe { s.assume_init() };
+/// assert_match!(s, S { x: 5, y: 0 });
+/// ```
+#[macro_export]
+macro_rules! uninit_field_mut {
+ ($container:expr, $($field:tt)+) => {{
+ let container__: &mut ::std::mem::MaybeUninit<_> = &mut $container;
+ let container_ptr__ = container__.as_mut_ptr();
+
+ // SAFETY: the container is not used directly, only through a MaybeUninit<>,
+ // so the safety is delegated to the caller and to final invocation of
+ // assume_init()
+ let target__ = unsafe { std::ptr::addr_of_mut!((*container_ptr__).$($field)+) };
+ $crate::uninit::MaybeUninitField::new(container__, target__)
+ }};
+}
--
2.49.0
next prev parent reply other threads:[~2025-06-09 15:44 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-09 15:44 [PATCH 0/5] rust: make instance_init implementations use safe Rust Paolo Bonzini
2025-06-09 15:44 ` Paolo Bonzini [this message]
2025-06-11 11:09 ` [PATCH 1/5] rust: qemu_api: introduce MaybeUninit field projection Zhao Liu
2025-06-09 15:44 ` [PATCH 2/5] rust: hpet: fully initialize object after instance_init Paolo Bonzini
2025-06-11 9:43 ` Zhao Liu
2025-06-09 15:44 ` [PATCH 3/5] rust: qom: introduce ParentInit Paolo Bonzini
2025-06-11 15:25 ` Zhao Liu
2025-06-09 15:44 ` [PATCH 4/5] rust: qom: make ParentInit lifetime-invariant Paolo Bonzini
2025-06-12 9:21 ` Zhao Liu
2025-06-12 9:07 ` Paolo Bonzini
2025-06-12 9:41 ` Zhao Liu
2025-06-12 9:24 ` Paolo Bonzini
2025-06-12 10:31 ` Zhao Liu
2025-06-09 15:44 ` [PATCH 5/5] rust: qom: change instance_init to take a ParentInit<> Paolo Bonzini
2025-06-12 15:25 ` Zhao Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250609154423.706056-2-pbonzini@redhat.com \
--to=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-rust@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).