rust: qom: change instance_init to take a ParentInit<>

This removes undefined behavior associated to writing to uninitialized
fields, and makes it possible to remove "unsafe" from the instance_init
implementation.

However, the init function itself is still unsafe, because it must promise
(as a sort as MaybeUninit::assume_init) that all fields have been
initialized.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2025-03-04 20:48:05 +01:00
parent 8d394f6cf0
commit 345bef46a1
5 changed files with 63 additions and 57 deletions

View file

@ -21,8 +21,8 @@ use qemu_api::{
hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED,
},
prelude::*,
qdev::{DeviceImpl, DeviceMethods, DeviceState, Property, ResetType, ResettablePhasesImpl},
qom::{ObjectImpl, ObjectType, ParentField},
qdev::{DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesImpl},
qom::{ObjectImpl, ObjectType, ParentField, ParentInit},
qom_isa,
sysbus::{SysBusDevice, SysBusDeviceImpl},
timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND},
@ -697,7 +697,7 @@ impl HPETState {
.set(self.counter.get().deposit(shift, len, val));
}
unsafe fn init(&mut self) {
unsafe fn init(mut this: ParentInit<Self>) {
static HPET_RAM_OPS: MemoryRegionOps<HPETState> =
MemoryRegionOpsBuilder::<HPETState>::new()
.read(&HPETState::read)
@ -707,18 +707,14 @@ impl HPETState {
.impl_sizes(4, 8)
.build();
// SAFETY:
// self and self.iomem are guaranteed to be valid at this point since callers
// must make sure the `self` reference is valid.
MemoryRegion::init_io(
unsafe { &mut *addr_of_mut!(self.iomem) },
addr_of_mut!(*self),
&mut uninit_field_mut!(*this, iomem),
&HPET_RAM_OPS,
"hpet",
HPET_REG_SPACE_LEN,
);
Self::init_timers(unsafe { &mut *((self as *mut Self).cast::<MaybeUninit<Self>>()) });
Self::init_timers(&mut this);
}
fn post_init(&self) {
@ -900,7 +896,7 @@ unsafe impl ObjectType for HPETState {
impl ObjectImpl for HPETState {
type ParentType = SysBusDevice;
const INSTANCE_INIT: Option<unsafe fn(&mut Self)> = Some(Self::init);
const INSTANCE_INIT: Option<unsafe fn(ParentInit<Self>)> = Some(Self::init);
const INSTANCE_POST_INIT: Option<fn(&Self)> = Some(Self::post_init);
const CLASS_INIT: fn(&mut Self::Class) = Self::Class::class_init::<Self>;
}