rust: provide safe wrapper for MaybeUninit::zeroed()

MaybeUninit::zeroed() is handy, but it introduces unsafe (and has a
pretty heavy syntax in general).  Introduce a trait that provides the
same functionality while staying within safe Rust.

In addition, MaybeUninit::zeroed() is not available as a "const"
function until Rust 1.75.0, so this also prepares for having handwritten
implementations of the trait until we can assume that version.

Reviewed-by: Junjie Mao <junjie.mao@hotmail.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2024-10-18 10:51:10 +02:00
parent c92c447ff0
commit 6e50bde1e1
6 changed files with 35 additions and 10 deletions

View File

@ -4,7 +4,7 @@
use core::ptr::NonNull; use core::ptr::NonNull;
use qemu_api::{bindings::*, definitions::ObjectImpl}; use qemu_api::{bindings::*, definitions::ObjectImpl, zeroable::Zeroable};
use crate::device::PL011State; use crate::device::PL011State;
@ -12,7 +12,7 @@
pub static VMSTATE_PL011: VMStateDescription = VMStateDescription { pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
name: PL011State::TYPE_INFO.name, name: PL011State::TYPE_INFO.name,
unmigratable: true, unmigratable: true,
..unsafe { ::core::mem::MaybeUninit::<VMStateDescription>::zeroed().assume_init() } ..Zeroable::ZERO
}; };
qemu_api::declare_properties! { qemu_api::declare_properties! {

View File

@ -2,9 +2,9 @@
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org> // Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
use core::{mem::MaybeUninit, ptr::NonNull}; use core::ptr::NonNull;
use qemu_api::bindings::*; use qemu_api::{bindings::*, zeroable::Zeroable};
use crate::device::PL011State; use crate::device::PL011State;
@ -14,11 +14,11 @@
read_with_attrs: None, read_with_attrs: None,
write_with_attrs: None, write_with_attrs: None,
endianness: device_endian::DEVICE_NATIVE_ENDIAN, endianness: device_endian::DEVICE_NATIVE_ENDIAN,
valid: unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_1>::zeroed().assume_init() }, valid: Zeroable::ZERO,
impl_: MemoryRegionOps__bindgen_ty_2 { impl_: MemoryRegionOps__bindgen_ty_2 {
min_access_size: 4, min_access_size: 4,
max_access_size: 4, max_access_size: 4,
..unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_2>::zeroed().assume_init() } ..Zeroable::ZERO
}, },
}; };

View File

@ -5,6 +5,7 @@ _qemu_api_rs = static_library(
'src/lib.rs', 'src/lib.rs',
'src/definitions.rs', 'src/definitions.rs',
'src/device_class.rs', 'src/device_class.rs',
'src/zeroable.rs',
], ],
{'.' : bindings_rs}, {'.' : bindings_rs},
), ),

View File

@ -31,7 +31,7 @@ macro_rules! define_property {
offset: ::core::mem::offset_of!($state, $field) as isize, offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: true, set_default: true,
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 }, defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval as u64 },
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() } ..$crate::zeroable::Zeroable::ZERO
} }
}; };
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => { ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
@ -41,7 +41,7 @@ macro_rules! define_property {
info: $prop, info: $prop,
offset: ::core::mem::offset_of!($state, $field) as isize, offset: ::core::mem::offset_of!($state, $field) as isize,
set_default: false, set_default: false,
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() } ..$crate::zeroable::Zeroable::ZERO
} }
}; };
} }
@ -58,7 +58,7 @@ macro_rules! declare_properties {
len len
}] = [ }] = [
$($prop),*, $($prop),*,
unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() }, $crate::zeroable::Zeroable::ZERO,
]; ];
}; };
} }
@ -79,7 +79,7 @@ macro_rules! vm_state_description {
$vname.as_ptr() $vname.as_ptr()
},)* },)*
unmigratable: true, unmigratable: true,
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::VMStateDescription>::zeroed().assume_init() } ..$crate::zeroable::Zeroable::ZERO
}; };
} }
} }

View File

@ -29,6 +29,7 @@ unsafe impl Sync for bindings::VMStateDescription {}
pub mod definitions; pub mod definitions;
pub mod device_class; pub mod device_class;
pub mod zeroable;
use std::alloc::{GlobalAlloc, Layout}; use std::alloc::{GlobalAlloc, Layout};

View File

@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/// Encapsulates the requirement that
/// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause
/// undefined behavior.
///
/// # Safety
///
/// Do not add this trait to a type unless all-zeroes is
/// a valid value for the type. In particular, remember that raw
/// pointers can be zero, but references and `NonNull<T>` cannot
/// unless wrapped with `Option<>`.
pub unsafe trait Zeroable: Default {
/// SAFETY: If the trait was added to a type, then by definition
/// this is safe.
const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() };
}
unsafe impl Zeroable for crate::bindings::Property__bindgen_ty_1 {}
unsafe impl Zeroable for crate::bindings::Property {}
unsafe impl Zeroable for crate::bindings::VMStateDescription {}
unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_1 {}
unsafe impl Zeroable for crate::bindings::MemoryRegionOps__bindgen_ty_2 {}