From 57cc8bc6fe766dee0c26153e253c130aac834272 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Mon, 15 Nov 2021 16:50:05 +0000 Subject: [PATCH] hypervisor: aarch64: remove undefined behaviour in offset__of The variable tmp was never initialized. Calling assume_init when the content is not yet initialized causes immediate undefined behaviour. We also cannot create any intermediate references because they will be subject to the same requirements for references -- the referred object must be valid. Signed-off-by: Wei Liu --- hypervisor/src/kvm/aarch64/mod.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs index 1adce1fa4..0dbb23cb8 100644 --- a/hypervisor/src/kvm/aarch64/mod.rs +++ b/hypervisor/src/kvm/aarch64/mod.rs @@ -36,13 +36,23 @@ pub use {kvm_ioctls::Cap, kvm_ioctls::Kvm}; macro_rules! offset__of { ($str:ty, $($field:ident)+) => ({ let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit(); - let tmp = unsafe { tmp.assume_init() }; - let base = &tmp as *const _ as usize; - let member = &tmp.$($field)* as *const _ as usize; + let base = tmp.as_ptr(); - member - base + // Avoid warnings when nesting `unsafe` blocks. + #[allow(unused_unsafe)] + // SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures + // that we don't actually read from `base` (which would be UB) nor create an intermediate + // reference. + let member = unsafe { core::ptr::addr_of!((*base).$($field)*) } as *const u8; + + // Avoid warnings when nesting `unsafe` blocks. + #[allow(unused_unsafe)] + // SAFETY: The two pointers are within the same allocated object `tmp`. All requirements + // from offset_from are upheld. + unsafe { member.offset_from(base as *const u8) as usize } }); } + // Get the ID of a core register #[macro_export] macro_rules! arm64_core_reg_id {