From nobody Sat Nov 15 16:07:51 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1749483968; cv=none; d=zohomail.com; s=zohoarc; b=ONaDOoan4Iyf9DV+9vthdRPW9R5R2aZhq63xzisyc+MaMQVqs/kha0kaexdI3jBSOguVFAyY87otEBcglmcyQ9K7BzSyX8thhXQ81VzprQrFKrpQWZmP58VQ3VDwyvt1gdxrUfM5wI3u6zmilTE4lg+Dl/sYqyxedR5UeEzlx8s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749483968; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=wPitIwtRsJrMNIILebImcTxNfCDytC/cKtWdPcESChA=; b=fb7L6LnRs/+Kz4aoBrfRfYAE0LB9Kw96dK/9iMNnCqVCWmq/wg8q9wu5oImvox9r2Yj6jQ2UTWAXx+kTe+NTcMw4sixK8SsJGfexMXXPL/DSpADUqb0OT/eqs2LgjXZ4w1nS7mWV7OWyWkn19Uu8gQE/ue3vhfjKUzYOEtI3kqk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749483968115613.4493652354315; Mon, 9 Jun 2025 08:46:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOefs-0000Nc-WA; Mon, 09 Jun 2025 11:44:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefq-0000MP-PV for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:34 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefp-0007gW-4q for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:34 -0400 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-7-XCyTK5edNJKt-QmVctJHIg-1; Mon, 09 Jun 2025 11:44:29 -0400 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-3a4eec544c6so1821575f8f.0 for ; Mon, 09 Jun 2025 08:44:29 -0700 (PDT) Received: from [192.168.122.1] ([151.49.64.79]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45213709637sm113704375e9.26.2025.06.09.08.44.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 08:44:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749483872; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wPitIwtRsJrMNIILebImcTxNfCDytC/cKtWdPcESChA=; b=S1RwrdFc2M8GVXqbrLDPt15iwirLEwtu4XVGVVa9QoJ+5Kpww+scHUDokswERUdrsBH6Fh fXrOSR0fFMLmhFSD1d46x6GhGhV+5kXLcj8l8Eo+X9VjM+xte3dCgfDWY2IRVGaIH3NrDi C21d+zI2u2DrFjJP3zNSJN9R26OwFsk= X-MC-Unique: XCyTK5edNJKt-QmVctJHIg-1 X-Mimecast-MFC-AGG-ID: XCyTK5edNJKt-QmVctJHIg_1749483868 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749483868; x=1750088668; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wPitIwtRsJrMNIILebImcTxNfCDytC/cKtWdPcESChA=; b=gYGyuOU48IWcxGjq4uYQRgugJ1h2OTKFKAsyCCA2INyoYMVHwm81MiuaOdr8I+XTu7 VS8Vh7+7G0EchlBMHYUIoig5LxRTcoIpaq0Kdv+Lcq3gJVEQXZXKasVKR0qIu4YiSu4n LWVLZmWyU2mEGD41n0z7214NtWHnckz5p60j/A4jqBuf3Ol9VqP+OUcnfnp3vYfkGzYr 1UDHsy3l1RZp9FBNQ0eOgTIQPvweVJ2vtyoJv/ULNXUS2YbVU/a5rNZithSfYr+9bTMG 3nynoMUI2rNoEWuFwhBXCBYWSUydCw+3rzcVnzNhIw1/CcLpkl+DXcr2t7JC8fplcbwx Wwaw== X-Gm-Message-State: AOJu0Yzl/qBhB842ZlnI/hk5kgQIR4XLRbIAh9qjCIBUnU4DHDI7EZzz B/mR8yHqNY5x4ggu/z+AklQjLKcJGLz8XPzXEbuvlTup7Se79FuBT8SLDRxn25sUdchNstPRt7I uQ5nPQRPNz9/ikzCioEt6GBegp9Jf4pV1esiCpNI2l6YuBYkjA8OYGzmbmeknVv5huPjtKbz0Eh 0cRAkrElCf2yxnaJK22yU10aj9aQU7aEzXlA+gSiWx X-Gm-Gg: ASbGncvfhJ11q3BqIlMsMq85vhsi5anYH+HMwTDJiKkum6k91sp4ctMrAl9p4Xi+54U QI01lSRVWt6x5b4sRoCZNtyXWfOk0BlHpkdeVPM7Glq+aq24o8A2Lb1k4+0LoG61EkFhNlJaj4w V1RHJBzQ7ZFrBUOK0JWhaY5he9eXYkkCU76O2KIgNyrS/oXAJr3Ds1UctbRP2XV+JW6rOvcUf5i V7L1dXuxaP2sbOSkdrrkBL9MEAxQNNVPtoK8P++ElnkW5pHBFeICpsdcmPp8VImBojxShTdm+vO 1WOZEthuorLV1w== X-Received: by 2002:a05:6000:2c0f:b0:3a5:222f:c0d0 with SMTP id ffacd0b85a97d-3a53166c269mr10426962f8f.0.1749483867669; Mon, 09 Jun 2025 08:44:27 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEFkwF1GAK1Q8MA9qw75TWqqQtRjZhcW7CjQjgwMId/TkFXlky45NF92JRCplH0YmqnglgC7Q== X-Received: by 2002:a05:6000:2c0f:b0:3a5:222f:c0d0 with SMTP id ffacd0b85a97d-3a53166c269mr10426939f8f.0.1749483867177; Mon, 09 Jun 2025 08:44:27 -0700 (PDT) From: Paolo Bonzini 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 Message-ID: <20250609154423.706056-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609154423.706056-1-pbonzini@redhat.com> References: <20250609154423.706056-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1749483975212116600 Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Zhao Liu --- 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 =3D 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; =20 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, + child: *mut U, +} + +impl<'a, T, U> MaybeUninitField<'a, T, U> { + #[doc(hidden)] + pub fn new(parent: &'a mut MaybeUninit, 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 =3D MaybeUninit; + + fn deref(&self) -> &MaybeUninit { + // SAFETY: self.child was obtained by dereferencing a valid mutable + // reference; the content of the memory may be invalid or uninitia= lized + // 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 { + // SAFETY: self.child was obtained by dereferencing a valid mutable + // reference; the content of the memory may be invalid or uninitia= lized + // 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 =3D MaybeUninit::zeroed(); +/// uninit_field_mut!(s, x).write(5); +/// let s =3D unsafe { s.assume_init() }; +/// assert_match!(s, S { x: 5, y: 0 }); +/// ``` +#[macro_export] +macro_rules! uninit_field_mut { + ($container:expr, $($field:tt)+) =3D> {{ + let container__: &mut ::std::mem::MaybeUninit<_> =3D &mut $contain= er; + let container_ptr__ =3D container__.as_mut_ptr(); + + // SAFETY: the container is not used directly, only through a Mayb= eUninit<>, + // so the safety is delegated to the caller and to final invocatio= n of + // assume_init() + let target__ =3D unsafe { std::ptr::addr_of_mut!((*container_ptr__= ).$($field)+) }; + $crate::uninit::MaybeUninitField::new(container__, target__) + }}; +} --=20 2.49.0 From nobody Sat Nov 15 16:07:51 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1749483908; cv=none; d=zohomail.com; s=zohoarc; b=iri/WZZ/GuLbZKlVZ88rQmL16olTHvwxp4OL0qON2cWlShAQ4AglfcoBGohdROmxrTLQV/LkjcrlkoUdDK9KakgoWUo6o6c0xFbz6KQu0qRYwRB1F2Y/V+M2uEILMej+OUOM+Li/9R1BM7ZG6FYyiueibN9KeNGo0f5ocGf+pyw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749483908; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=5HjroMel8a6RF+nigSPUiqMo1YKd1zSm1exQlnXqhVE=; b=JQ/eGiFcp8Q6aRtgjqNLpo38LzXUR5iaiiiUqfK10HbiFJxN4mKZPBRuqUp61ERlQw+0YoGBFhNtN1rDSx6GFchMgL3QmIZQh0d564Ssy/CBtqv/JPj/UcUky4YRKJtjx4BRIlnH+HAmo/3zawm9nLGhYQyMow7TPeviQtiopK0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749483908234285.53329486359564; Mon, 9 Jun 2025 08:45:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOeft-0000QE-T0; Mon, 09 Jun 2025 11:44:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefs-0000NO-4E for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:36 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefp-0007gy-Tz for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:35 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-326-1CAVF-HHM4icG44tJPohjA-1; Mon, 09 Jun 2025 11:44:32 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-453080e4741so12727335e9.0 for ; Mon, 09 Jun 2025 08:44:31 -0700 (PDT) Received: from [192.168.122.1] ([151.49.64.79]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-452730d1686sm110576235e9.36.2025.06.09.08.44.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 08:44:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749483873; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5HjroMel8a6RF+nigSPUiqMo1YKd1zSm1exQlnXqhVE=; b=eCn+Nxijya2SOZlOr2LCxknlhwoleaO6d3NhDkBvcQkkjVJDDawdtOqa+WK4XlYyFCgdkR EevDRVPdDniUKB50a+Twjp5tx34rdjJ2eiRUtIHZNU7SP+eC6bwEbfdkGoKfW0JB3kozkE Bngd3n426lqR3bb0Mz8GbOGvlnksQnQ= X-MC-Unique: 1CAVF-HHM4icG44tJPohjA-1 X-Mimecast-MFC-AGG-ID: 1CAVF-HHM4icG44tJPohjA_1749483871 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749483870; x=1750088670; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=5HjroMel8a6RF+nigSPUiqMo1YKd1zSm1exQlnXqhVE=; b=UjtR3DzdLMQZ4NfS6YRoERzjbsjdI6WwRqvrTm3B+5eTq42YkYNkMXSIdBVi5lRBdC 5kYneYFklXrlOKCWBx0rTp1g/0wK/mNMyWG9rRznQAOXvANHXqEmdigEXR73YRIV6iK0 5zOoYa1gquX4J4qSMekC+D6aHP6eAC6aSmuLn8CcGnefvXl/neV8uEXcnS1vUknELNDj F4xY1Lp3XjDeG2cI1SPRsMfDwWGQ9vkecz+AUWeAxGqFRxjLzeIvBgkB8hW0Ti1tmHhe 6l8IrbTOigtqaixTPda/Q9TX12nTZMtyejZnDPYwKo98vmHG9fKM1CTsh+EXRxUiG2tC XuAw== X-Gm-Message-State: AOJu0YyZ2SvB4d/xLPzXHCg626i7sQ7N3Cr4cgQj6nxy1x/eYfLFzgcv WeTvqCC7vW4YZvRzMJMD/PyWtCBSPqN9IUTKoazhieqT+NppVGElCT1H+Kr6V21oBS9i0NEbBYa xA5Oy+okShuZXnvW38kZmPW3IxFYE4xA75u5G5x+srXue5P2pOQrVH1hQq9y1BvCPwXh34SHywu d3SZhzVZXeef7/yBJ1n1l7eO1pQO4bZFx8ltG+ZTbS X-Gm-Gg: ASbGncuaOgpztsozfn73e2WqdD+Z13TysbosBQbmIri1rVJR80H+8H1XESIZpqFd/wl fMYZd0eulaBixUiyfsJVGrVjIUHKoNQisDCvkpYPMklJUdQQJLG2cwI/5mXVYIY86jGHBoHn4XP W8Hsy4+0Uh2zjcNb3hbT923smJAdgTfZ2wXT3tO5voZ2wUFTvZNen1/+GPZSUtMOyhO82MD4Ake ryYCVXbNNsqHw31Pr3pLxmRN+BSGV+Ed9CtDsYzquZAiHAMBscgr0O1eWb9zHvKbxlO7pknxGkD q+vJ7kC1sFi0VQ== X-Received: by 2002:a05:600c:8b23:b0:450:d37c:9fc8 with SMTP id 5b1f17b1804b1-452013898d8mr134266425e9.13.1749483869999; Mon, 09 Jun 2025 08:44:29 -0700 (PDT) X-Google-Smtp-Source: AGHT+IF535ooEPbrZS5uS233pOZdaRmQSWaeSCD/MruHfVyfo1LgqyeQe8cN6CnFFxN99WP1nPwp5A== X-Received: by 2002:a05:600c:8b23:b0:450:d37c:9fc8 with SMTP id 5b1f17b1804b1-452013898d8mr134266155e9.13.1749483869432; Mon, 09 Jun 2025 08:44:29 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 2/5] rust: hpet: fully initialize object after instance_init Date: Mon, 9 Jun 2025 17:44:20 +0200 Message-ID: <20250609154423.706056-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609154423.706056-1-pbonzini@redhat.com> References: <20250609154423.706056-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1749483910955116600 Content-Type: text/plain; charset="utf-8" The array of BqlRefCell is not initialized yet at the end of instance_init. In particular, the "state" field is NonNull and therefore it is invalid to have it as zero bytes. Note that MaybeUninit is necessary because assigning to self.timers[index] would trigger Drop of the old value. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/timer/hpet/src/device.rs | 42 +++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/devi= ce.rs index 735b2fbef79..340ca1d355d 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -4,6 +4,7 @@ =20 use std::{ ffi::{c_int, c_void, CStr}, + mem::MaybeUninit, pin::Pin, ptr::{addr_of_mut, null_mut, NonNull}, slice::from_ref, @@ -25,6 +26,7 @@ qom_isa, sysbus::{SysBusDevice, SysBusDeviceImpl}, timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, + uninit_field_mut, vmstate::VMStateDescription, vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmsta= te_validate, zeroable::Zeroable, @@ -212,13 +214,13 @@ pub struct HPETTimer { } =20 impl HPETTimer { - fn init(&mut self, index: u8, state: &HPETState) { - *self =3D HPETTimer { + fn new(index: u8, state: *const HPETState) -> HPETTimer { + HPETTimer { index, // SAFETY: the HPETTimer will only be used after the timer // is initialized below. qemu_timer: unsafe { Timer::new() }, - state: NonNull::new((state as *const HPETState).cast_mut()).un= wrap(), + state: NonNull::new(state.cast_mut()).unwrap(), config: 0, cmp: 0, fsb: 0, @@ -226,19 +228,15 @@ fn init(&mut self, index: u8, state: &HPETState) { period: 0, wrap_flag: 0, last: 0, - }; + } + } =20 + fn init_timer_with_cell(cell: &BqlRefCell) { + let mut timer =3D cell.borrow_mut(); // SAFETY: HPETTimer is only used as part of HPETState, which is // always pinned. - let qemu_timer =3D unsafe { Pin::new_unchecked(&mut self.qemu_time= r) }; - qemu_timer.init_full( - None, - CLOCK_VIRTUAL, - Timer::NS, - 0, - timer_handler, - &state.timers[self.index as usize], - ) + let qemu_timer =3D unsafe { Pin::new_unchecked(&mut timer.qemu_tim= er) }; + qemu_timer.init_full(None, CLOCK_VIRTUAL, Timer::NS, 0, timer_hand= ler, cell); } =20 fn get_state(&self) -> &HPETState { @@ -607,9 +605,18 @@ fn handle_legacy_irq(&self, irq: u32, level: u32) { } } =20 - fn init_timer(&self) { - for (index, timer) in self.timers.iter().enumerate() { - timer.borrow_mut().init(index.try_into().unwrap(), self); + fn init_timers(this: &mut MaybeUninit) { + let state =3D this.as_ptr(); + for index in 0..HPET_MAX_TIMERS { + let mut timer =3D uninit_field_mut!(*this, timers[index]); + + // Initialize in two steps, to avoid calling Timer::init_full = on a + // temporary that can be moved. + let timer =3D timer.write(BqlRefCell::new(HPETTimer::new( + index.try_into().unwrap(), + state, + ))); + HPETTimer::init_timer_with_cell(timer); } } =20 @@ -710,6 +717,8 @@ unsafe fn init(&mut self) { "hpet", HPET_REG_SPACE_LEN, ); + + Self::init_timers(unsafe { &mut *((self as *mut Self).cast::>()) }); } =20 fn post_init(&self) { @@ -731,7 +740,6 @@ fn realize(&self) -> qemu_api::Result<()> { =20 self.hpet_id.set(HPETFwConfig::assign_hpet_id()?); =20 - self.init_timer(); // 64-bit General Capabilities and ID Register; LegacyReplacementR= oute. self.capability.set( HPET_CAP_REV_ID_VALUE << HPET_CAP_REV_ID_SHIFT | --=20 2.49.0 From nobody Sat Nov 15 16:07:51 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1749483934; cv=none; d=zohomail.com; s=zohoarc; b=M6Go0en0rkznJptdUgCpxlpwXRB2xkY6E0umzoa8wBK4IU2cGDe+1n0lHxrGBKES7VM4WDDzQ68vaIetk40lxCnI+9OsSM6PqjnHH1ToVxgO4/JTaA+T6UqU9iDlrLu4PdlnAvYetR7n6hVZtdOug5DhJwYOrGIJS1aZM71JLS8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749483934; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=0XtFw1Gm8P8SykWkqXaUzKJqdfFMOaemdUuq3TQP0wE=; b=NrjwQZB5LEBQo6sx6yTIi4Mp5zyT6BfYdXPoRdijV3EI9x4vXsiNzYfyQ9oXndtvvlw0xe+A1R6WdRXwjEZg8le1hCmFabfWw09NV2o/HAN7KOncEL7fO4SWf/QSjnbTaepCIls6+Drcqri5WizClgbT6xTvfcOXrWKsOr3fbpY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749483934187263.5529263916226; Mon, 9 Jun 2025 08:45:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOefw-0000U6-Bp; Mon, 09 Jun 2025 11:44:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOeft-0000Q3-NR for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:37 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefs-0007hZ-3I for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:37 -0400 Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-381-DKml0V4VMB2HAuI3cxdufg-1; Mon, 09 Jun 2025 11:44:34 -0400 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-3a4ff581df3so2312547f8f.1 for ; Mon, 09 Jun 2025 08:44:34 -0700 (PDT) Received: from [192.168.122.1] ([151.49.64.79]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a532464575sm9901756f8f.97.2025.06.09.08.44.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 08:44:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749483875; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0XtFw1Gm8P8SykWkqXaUzKJqdfFMOaemdUuq3TQP0wE=; b=CNlabHVMGB4vyvCejNNbI7LvFpqkub4INgfPgOsQyQqxbDQxCgPHhgEmu1p43FEJ64QE7N IrRALg/R1m22pXxesIXm1Pr/QYAfASqSXiNfC+kc9Sqs0bQXXa13A/kD9NZkvfDdijVeHU FfLArKVsSkiob7oudhR/xy69Fl5iVJs= X-MC-Unique: DKml0V4VMB2HAuI3cxdufg-1 X-Mimecast-MFC-AGG-ID: DKml0V4VMB2HAuI3cxdufg_1749483873 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749483872; x=1750088672; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0XtFw1Gm8P8SykWkqXaUzKJqdfFMOaemdUuq3TQP0wE=; b=LKy7RmBzDr7Wre80aiAmjRWQMvHfEfnSCW5HPiJaqzxl0w0+G9QKPSDUvMqV/Z2SXK WR1Hi6vpX9alqoplJq62Zdu36B1amZ9AZqmaX0Qp5ilKFAjBz3HYsgi5GkBWUY41dyzj vBcCAv8nmXyzusu5LUxqZKh0cXO+jCBQyfjY+vnrZVp0/upjzJ3rShgX70QdjRzf3T2t 5J1HHnf0M++bqsrQ1iT+FTn5tYV0WjR1oVflvVU1z82gvjR9Pk7LPUCNUyGONnSF40Xm k/FQy7Kn+InxK2k2vJm4vJc1U4G9KO3J5/RoXjtSTlAS51aoRm3t4du+xUvGhGPl1eB6 E0Zw== X-Gm-Message-State: AOJu0YwxotWx1CnMd7+qwKEEyhzqBRU+f9hzRDoIZUQeqNgb3DEpiUjG JWzZa25uSrrA+xnKY353vzX8yyez9TrX0P9d4GHeagfYbuG9V2ZlWKQeXuARbLsb7Gbt2XI+loD 3+Y0JAARb4j42ovgkIP2eM5dZSFYaR1v9SK1HAMa7qLiC28xBAavQT1xUkfT/89NuyFhpKdbOsV wR8P1BZ/MwGXbZTIH1vLD534HO6cPbIlisY8nBhM8U X-Gm-Gg: ASbGnculcL/7L9/xv/D1RAdY2rXb0sJVRSPwGC6/g2dmWQQgUR6YGooIQftk8HDZnQr k5zigQrRFYkCo9yeJJgHsD/ILiOrb5MmCkSJKgkblT5XeogCHbHAETYcFTSDhNIRctZjK3MsqAm XfZiIhvQOl9fhyaPLvsPqeHky84RtSVpv95ySZx5fUSfqqkHU4AAFg9JWyHOmGOC5CLLlWSSsHR ifcLiZCSKpVXIoQ+8bFVYxknynppI4BYF4viq84zq5oIblxMeCDcKzmB4pv0Jo+VKAYVMOlCEFX vQqxRsAlDfBYWM6be61sIrGh X-Received: by 2002:a05:6000:124c:b0:3a4:dfbe:2b14 with SMTP id ffacd0b85a97d-3a5513f6775mr11945f8f.16.1749483872259; Mon, 09 Jun 2025 08:44:32 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGA887dzRG+kwqNJMKkT2oJADBvSV+FfV5SewknSuJ4Z+XFGr12R8krTTB0SZuf5A77jgfh+Q== X-Received: by 2002:a05:6000:124c:b0:3a4:dfbe:2b14 with SMTP id ffacd0b85a97d-3a5513f6775mr11932f8f.16.1749483871720; Mon, 09 Jun 2025 08:44:31 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 3/5] rust: qom: introduce ParentInit Date: Mon, 9 Jun 2025 17:44:21 +0200 Message-ID: <20250609154423.706056-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609154423.706056-1-pbonzini@redhat.com> References: <20250609154423.706056-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1749483935333116600 Content-Type: text/plain; charset="utf-8" This is a smart pointer for MaybeUninit; it can be upcasted to the already-initialized parent classes, or dereferenced to a MaybeUninit for the class that is being initialized. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/qemu-api/src/qom.rs | 86 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 14f98fee60a..21c271cd2f9 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -95,7 +95,7 @@ use std::{ ffi::{c_void, CStr}, fmt, - mem::ManuallyDrop, + mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, ptr::NonNull, }; @@ -206,6 +206,90 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<()= , fmt::Error> { } } =20 +/// This struct knows that the superclasses of the object have already been +/// initialized. +pub struct ParentInit<'a, T>(&'a mut MaybeUninit); + +impl<'a, T> ParentInit<'a, T> { + #[inline] + pub fn with(obj: &'a mut MaybeUninit, f: impl FnOnce(ParentInit<'a,= T>)) { + let parent_init =3D ParentInit(obj); + f(parent_init) + } +} + +impl ParentInit<'_, T> { + /// Return the receiver as a mutable raw pointer to Object. + pub fn as_object_mut_ptr(&self) -> *mut bindings::Object { + self.as_object_ptr().cast_mut() + } + + /// Return the receiver as a const raw pointer to Object. + /// This is preferrable to `as_object_mut_ptr()` if a C + /// function only needs a `const Object *`. + pub fn as_object_ptr(&self) -> *const bindings::Object { + self.0.as_ptr().cast() + } +} + +impl<'a, T: ObjectImpl> ParentInit<'a, T> { + /// Convert from a derived type to one of its parent types, which + /// have already been initialized. + /// + /// # Safety + /// + /// Structurally this is always a safe operation; the [`IsA`] trait + /// provides static verification trait that `Self` dereferences to `U`= or + /// a child of `U`, and only parent types of `T` are allowed. + /// + /// However, while the fields of the resulting reference are initializ= ed, + /// calls might use uninitialized fields of the subclass. It is your + /// responsibility to avoid this. + pub unsafe fn upcast(&self) -> &'a U + where + T::ParentType: IsA, + { + // SAFETY: soundness is declared via IsA, which is an unsafe tr= ait; + // the parent has been initialized before `instance_init `is called + unsafe { &*(self.0.as_ptr().cast::()) } + } + + /// Convert from a derived type to one of its parent types, which + /// have already been initialized. + /// + /// # Safety + /// + /// Structurally this is always a safe operation; the [`IsA`] trait + /// provides static verification trait that `Self` dereferences to `U`= or + /// a child of `U`, and only parent types of `T` are allowed. + /// + /// However, while the fields of the resulting reference are initializ= ed, + /// calls might use uninitialized fields of the subclass. It is your + /// responsibility to avoid this. + pub unsafe fn upcast_mut(&mut self) -> &'a mut U + where + T::ParentType: IsA, + { + // SAFETY: soundness is declared via IsA, which is an unsafe tr= ait; + // the parent has been initialized before `instance_init `is called + unsafe { &mut *(self.0.as_mut_ptr().cast::()) } + } +} + +impl Deref for ParentInit<'_, T> { + type Target =3D MaybeUninit; + + fn deref(&self) -> &Self::Target { + self.0 + } +} + +impl DerefMut for ParentInit<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0 + } +} + unsafe extern "C" fn rust_instance_init(obj: *mut bindings:= :Object) { let mut state =3D NonNull::new(obj).unwrap().cast::(); // SAFETY: obj is an instance of T, since rust_instance_init --=20 2.49.0 From nobody Sat Nov 15 16:07:51 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1749483916; cv=none; d=zohomail.com; s=zohoarc; b=XdybKt7YYvqqmINlhSteq+biR4gkLa5IdgZ/SoDV5tON5U/x3gNvC6S1jtK+RUOzqMlFlfiMU0m5ZSjL278Qdvtm9DrykOGJF4XCDaDzsf2TOBXhKEs36g1BuUzkb6Y5A5aZx3upY9+ZiJvFEazN7dXd0COlIPfmcXeF3Ho0j0Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749483916; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=epM41E1l12D6pUwXy3YmY7/Hvv8B/vOVwD8gZKKOhHo=; b=I0MGW4vO7JN5FJY6ZgGpN/xvxMwUdthwvKkyv5TZMbAzfoy6evgPqydzbYA8n3eZkOcE4y1F7hjafuQCpf4jPpqV26OT2gLQ8K+Fn5pryuEiNs92MfCaWO1udIpxgawj7LqeibhL4Sp8sRHACg6aifohfwRX6llFjq/l5gsgbNE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749483916170739.6335207667229; Mon, 9 Jun 2025 08:45:16 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOefy-0000Us-QP; Mon, 09 Jun 2025 11:44:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefw-0000U8-DE for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:40 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefu-0007i9-Dx for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:40 -0400 Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-417-KjvZzj-dODSMDKnSnLwfGA-1; Mon, 09 Jun 2025 11:44:36 -0400 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-451deff247cso25086745e9.1 for ; Mon, 09 Jun 2025 08:44:35 -0700 (PDT) Received: from [192.168.122.1] ([151.49.64.79]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45307b9d827sm65817845e9.22.2025.06.09.08.44.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 08:44:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749483877; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=epM41E1l12D6pUwXy3YmY7/Hvv8B/vOVwD8gZKKOhHo=; b=KyBh4VqrzRlCNwDpJllCcBBOniCgzvISFd8OwiYxXW2VC092PtkeXPOLidAMMPUd1GpnUo 6LfmT9+nSyRoQEClAOwM03XISLrNq/g8Cuz+UlSN5Jeud5mHBy+6e5dq3VG9hKdcNALbol CsuvxKVdi7r35+r8mszAu8Tr4k7sYqI= X-MC-Unique: KjvZzj-dODSMDKnSnLwfGA-1 X-Mimecast-MFC-AGG-ID: KjvZzj-dODSMDKnSnLwfGA_1749483875 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749483874; x=1750088674; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=epM41E1l12D6pUwXy3YmY7/Hvv8B/vOVwD8gZKKOhHo=; b=SxeGcFSp1/xsR9d4EIGmVa9jGCaSMdaYuFRCGuSQYLSIIgn5VjnXity+CUoXztE07e XWN0zIsED+MQ7geBWd1ikeJST6cvQrxF3Cqqx2iImIeuG82WGWZ6KEM15Vkr42Drl+gg jP7g5MRV0x2NaOZowLHtFS4FcE1qi3XIQF4HwcyXT82K8wRq9Rptywc4c4VCSIAqFaLu b9rggE+IScp/KWkZa9q20b+ZAiQ2JxojSt5N5j32tIDiZYk3p0DpO+kbislLity0whqe uTtKDiZSWt6BQ1cYIBpzJN/GzLTqGoy9y41hADQi/PMoTYiRuDXX6leggTmghi8fUMJf ODwg== X-Gm-Message-State: AOJu0YydIXQDYf4+6fqgA66Q7nvelGLlcWIvhizXx08a/Xq3X5k19UgX cfRtqyShX9fg6oXfpoHRCPOgWqqykW7xuAVv+MmTh868DPQpRJygPnGIEu9vxlhtCivolbtj91N pFEuTLxh4yqvMy9/JuWYpUvGb4mHBY3zq6/iYadDcgL66JfWRH1o9RdhJYDJquhHROkfEKur0YG YJzWY1qcuii/qunsqB4as6tgyWbYTyBTAjlQtmA/hu X-Gm-Gg: ASbGncuwgJrzk9raUHCpwEICHIRjR2cKlCu14u9ft3NAkqdlPcINrCwBvV+ADPJtr69 tbZ9/nzeVWfDUsUKoHHlWfuHn952x06RYmmhWlkFdUj5PPxmQxjJtfm1cEWbikn9rw4IL25vpvX 3s1VOmLoJBr/0NdhJyT6JL9PRB9o8+i5vG1bq/HI8y17cAcHtQmYIvkLUHRyGgQoErmHIZWU9ol LGCfRKAJvEopIqYup+4cdIPWDWyAK+/T4gXbUmPmtFwrl3d78RzE2L80QRmML96bHJk57sHq136 N0t3s144vRecXGY8yRlTmjdW X-Received: by 2002:a05:6000:2dc7:b0:3a4:ed9a:7016 with SMTP id ffacd0b85a97d-3a551427f0emr4291f8f.26.1749483874486; Mon, 09 Jun 2025 08:44:34 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEjGUAEUHvdGNUkTj0micNOMkn375JR2vzYSokk4elbOzTyj8ZmQQscRYA7Y6NVFIefwQPwAQ== X-Received: by 2002:a05:6000:2dc7:b0:3a4:ed9a:7016 with SMTP id ffacd0b85a97d-3a551427f0emr4273f8f.26.1749483873965; Mon, 09 Jun 2025 08:44:33 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 4/5] rust: qom: make ParentInit lifetime-invariant Date: Mon, 9 Jun 2025 17:44:22 +0200 Message-ID: <20250609154423.706056-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609154423.706056-1-pbonzini@redhat.com> References: <20250609154423.706056-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1749483917047116600 Content-Type: text/plain; charset="utf-8" This is the trick that allows the parent-field initializer to be used only for the object that it's meant to be initialized. This way, the owner of a MemoryRegion must be the object that embeds it. More information is in the comments; it's best explained with a simplified example. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/qemu-api/src/qom.rs | 88 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 21c271cd2f9..1481ef20f0c 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -95,6 +95,7 @@ use std::{ ffi::{c_void, CStr}, fmt, + marker::PhantomData, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, ptr::NonNull, @@ -208,12 +209,91 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(= ), fmt::Error> { =20 /// This struct knows that the superclasses of the object have already been /// initialized. -pub struct ParentInit<'a, T>(&'a mut MaybeUninit); +/// +/// The declaration of `ParentInit` is.. *"a kind of magic"*. It uses a +/// technique that is found in several crates, the main ones probably being +/// `ghost-cell` (in fact it was introduced by the [`GhostCell` paper](htt= ps://plv.mpi-sws.org/rustbelt/ghostcell/)) +/// and `generativity`. +/// +/// The `PhantomData` makes the `ParentInit` type *invariant* with respect= to +/// the lifetime argument `'init`. This, together with the `for<'...>` in +/// `[ParentInit::with]`, block any attempt of the compiler to be creative= when +/// operating on types of type `ParentInit` and to extend their lifetimes.= In +/// particular, it ensures that the `ParentInit` cannot be made to outlive= the +/// `rust_instance_init()` function that creates it, and therefore that the +/// `&'init T` reference is valid. +/// +/// This implementation of the same concept, without the QOM baggage, can = help +/// understanding the effect: +/// +/// ``` +/// use std::marker::PhantomData; +/// +/// #[derive(PartialEq, Eq)] +/// pub struct Jail<'closure, T: Copy>(&'closure T, PhantomData &'closure ()>); +/// +/// impl<'closure, T: Copy> Jail<'closure, T> { +/// fn get(&self) -> T { +/// *self.0 +/// } +/// +/// #[inline] +/// fn with(v: T, f: impl for<'id> FnOnce(Jail<'id, T>) -> U) -> U { +/// let parent_init =3D Jail(&v, PhantomData); +/// f(parent_init) +/// } +/// } +/// ``` +/// +/// It's impossible to escape the `Jail`; `token1` cannot be moved out of = the +/// closure: +/// +/// ```ignore +/// let x =3D 42; +/// let escape =3D Jail::with(&x, |token1| { +/// println!("{}", token1.get()); +/// token1 +/// }); +/// // fails to compile: +/// println!("{}", escape.get()); +/// ``` +/// +/// Likewise, in the QOM case the `ParentInit` cannot be moved out of +/// `instance_init()`. Without this trick it would be possible to stash a +/// `ParentInit` and use it later to access uninitialized memory. +/// +/// Here is another example, showing how separately-created "identities" s= tay +/// isolated: +/// +/// ```ignore +/// impl<'closure, T: Copy> Clone for Jail<'closure, T> { +/// fn clone(&self) -> Jail<'closure, T> { +/// Jail(self.0, PhantomData) +/// } +/// } +/// +/// fn main() { +/// Jail::with(42, |token1| { +/// // this works and returns true: the clone has the same "identi= ty" +/// println!("{}", token1 =3D=3D token1.clone()); +/// Jail::with(42, |token2| { +/// // here the outer token remains accessible... +/// println!("{}", token1.get()); +/// // ... but the two are separate: this fails to compile: +/// println!("{}", token1 =3D=3D token2); +/// }); +/// }); +/// } +/// ``` +pub struct ParentInit<'init, T>( + &'init mut MaybeUninit, + PhantomData &'init ()>, +); =20 -impl<'a, T> ParentInit<'a, T> { +impl<'init, T> ParentInit<'init, T> { #[inline] - pub fn with(obj: &'a mut MaybeUninit, f: impl FnOnce(ParentInit<'a,= T>)) { - let parent_init =3D ParentInit(obj); + pub fn with(obj: &'init mut MaybeUninit, f: impl for<'id> FnOnce(Pa= rentInit<'id, T>)) { + let parent_init =3D ParentInit(obj, PhantomData); f(parent_init) } } --=20 2.49.0 From nobody Sat Nov 15 16:07:51 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1749483908; cv=none; d=zohomail.com; s=zohoarc; b=IyNGFv1WoTJJYi9NICqDkWVKvs6Vtx+Ls5aSnCH5FCv5E09X0uXCLy2TZkBoBAmMspxvAt7mIeXmLE1SBtZod3q+RL5VjNjbx4TSQr1hhEIphW2Qe045n6hUc5hoqM/eGqx1DuyhS6v00kJZV6enJVLkGrEbrbY52ei/p1A5Knk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1749483908; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=iJdTmi7Wq/CYnDjJy94M4C2eH+AHFnXk5byaM7y7ITg=; b=UNhjKhkSemA2ecK/wUz/X2/DvL47Z617aBPHevSjtpFogY/fpov5CNGaVkFBDpbJFHcgykCFjW03Wp3ejb6nzqHHfxNYdritUd90Nl6pG8wLRhT9V51o9ewhDntqSHzkkL2XvLaY21yP7gJCTUxYUwH/kptDi0Kvin8W8fo2EHE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1749483908779963.9196545484424; Mon, 9 Jun 2025 08:45:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uOeg2-0000a5-61; Mon, 09 Jun 2025 11:44:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOeg0-0000V8-Fn for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:44 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uOefx-0007id-T8 for qemu-devel@nongnu.org; Mon, 09 Jun 2025 11:44:43 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-674-flbWxF30OZqc7beeTtDIvA-1; Mon, 09 Jun 2025 11:44:39 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-451d5600a54so34384995e9.2 for ; Mon, 09 Jun 2025 08:44:39 -0700 (PDT) Received: from [192.168.122.1] ([151.49.64.79]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a53244fd02sm9723515f8f.75.2025.06.09.08.44.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Jun 2025 08:44:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1749483881; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iJdTmi7Wq/CYnDjJy94M4C2eH+AHFnXk5byaM7y7ITg=; b=MUM4whgXkq63yWTZbNbcJLgbMKJBiykJxpVjheAIgJgptDG45ihzxUiFApA7ckSzZgM+m5 dk0mZbxP6UVKav3Di0LjmEW105nFPSMpM5/SIKjI8xxA2IgfC1F3/y1e5uuhshhFM/TD+e DXl/7gDTHfJ+lEH1PTmeclx8Ke7qyEM= X-MC-Unique: flbWxF30OZqc7beeTtDIvA-1 X-Mimecast-MFC-AGG-ID: flbWxF30OZqc7beeTtDIvA_1749483878 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749483877; x=1750088677; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iJdTmi7Wq/CYnDjJy94M4C2eH+AHFnXk5byaM7y7ITg=; b=CzI97+/7904dlw8AGCI1G6q3djkrw+c8xnSXCJvtoG+ZHKjI1+Ar5fv0Z4aqrhSGQg DiHpSNyCu+mfRJcPcBCuacR2KutT+bM2E6f6bWmOUmHwAhNsJUBpy2z2RRvdiXrW+i1l Xl2aeE04vED1uBnvEvyyWJvg25kqDpSg/B9mvRjfE2K4Z6Cm5vRDsXUPTu+4jtwTWmBL oN0Bv1kKwwRa+lPM6jDMfZdpEjXfZYK+CMU4LuOyPgy9uzr00ngPY+Jaw2CqXGja1XvH KVqYPuSLUDhgD2eEbdMLvOgbc2NOQ6ttuw2SgIX+u5QoReMh26lI3QKO5Qfu98Rubq+C 4iZw== X-Gm-Message-State: AOJu0YwYAFlA2k7VpJqJ903LmN9DXR47abMJCh4/pOFQKBkVZE2P890v dD+Qa2oYR+FJxpJQiTBIZ0VFAl07RaLFRhkvPb/9jS4LQrO17Og65K7TM/DckdpCwRSKTx9lzm5 /sHkKD0U9zJ97LTNUvEK3MOV4+1ipw/FvC/Zo2MVDup1bmQbDxb+4g22pjXwTvBR2KGqbJjD1gm 5olhDctUFZCgggjU8NtgaXGDDkPAaeAo+nGIg8sK4a X-Gm-Gg: ASbGncvzji2ApyB6jh+opMhj3rgphLu48VspOpTOuxXSxTyWRSTzXwWpu517oIQx9Vi QW9IcLVFVofPDUTTiyT+cwB72jsiA9w41qvs5NfuBddsNNAqhDr8bOpbcIXBpws8w80h3nhB/D1 j7VIfcWG+Fe7rYEl6tr3V5lyOq8XAZ7nG4yWeAMZH5MgvzNeKhV1SMyCqY7PCpp5Wh8lce+VB7U awi6LsEpuhYjvaE38vVa06XEAeFcSH36bYSKjkFr7WpJFBTS/+LDJuOuecEYae0Tyn1EAWVXwOR GW/PBaGKGsgp6MMAvGOMdhOB X-Received: by 2002:a05:6000:1787:b0:3a4:e502:81b8 with SMTP id ffacd0b85a97d-3a531caf95fmr10762751f8f.43.1749483877144; Mon, 09 Jun 2025 08:44:37 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGx4j3Fs+EP83RDPqP4md1YaQYyLAVX6E/8VNJ1+RrXZKeUL4o4iIgIHtEBt1GCKhM28JeGPg== X-Received: by 2002:a05:6000:1787:b0:3a4:e502:81b8 with SMTP id ffacd0b85a97d-3a531caf95fmr10762732f8f.43.1749483876586; Mon, 09 Jun 2025 08:44:36 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 5/5] rust: qom: change instance_init to take a ParentInit<> Date: Mon, 9 Jun 2025 17:44:23 +0200 Message-ID: <20250609154423.706056-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609154423.706056-1-pbonzini@redhat.com> References: <20250609154423.706056-1-pbonzini@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1749483911146116600 Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- rust/hw/char/pl011/src/device.rs | 34 ++++++++++----------- rust/hw/timer/hpet/src/device.rs | 16 ++++------ rust/qemu-api/src/memory.rs | 12 ++++---- rust/qemu-api/src/qdev.rs | 51 ++++++++++++++++++++------------ rust/qemu-api/src/qom.rs | 9 ++++-- 5 files changed, 65 insertions(+), 57 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/devi= ce.rs index be8387f6f2d..2d416cd9a3c 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -2,7 +2,7 @@ // Author(s): Manos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later =20 -use std::{ffi::CStr, mem::size_of, ptr::addr_of_mut}; +use std::{ffi::CStr, mem::size_of}; =20 use qemu_api::{ chardev::{CharBackend, Chardev, Event}, @@ -11,9 +11,10 @@ memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder= }, prelude::*, qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType= , ResettablePhasesImpl}, - qom::{ObjectImpl, Owned, ParentField}, + qom::{ObjectImpl, Owned, ParentField, ParentInit}, static_assert, sysbus::{SysBusDevice, SysBusDeviceImpl}, + uninit_field_mut, vmstate::VMStateDescription, }; =20 @@ -163,7 +164,7 @@ impl PL011Impl for PL011State { impl ObjectImpl for PL011State { type ParentType =3D SysBusDevice; =20 - const INSTANCE_INIT: Option =3D Some(Self::init); + const INSTANCE_INIT: Option)> =3D Some(Self= ::init); const INSTANCE_POST_INIT: Option =3D Some(Self::post_init); const CLASS_INIT: fn(&mut Self::Class) =3D Self::Class::class_init::; } @@ -488,7 +489,7 @@ impl PL011State { /// `PL011State` type. It must not be called more than once on the same /// location/instance. All its fields are expected to hold uninitializ= ed /// values with the sole exception of `parent_obj`. - unsafe fn init(&mut self) { + unsafe fn init(mut this: ParentInit) { static PL011_OPS: MemoryRegionOps =3D MemoryRegionOpsB= uilder::::new() .read(&PL011State::read) .write(&PL011State::write) @@ -496,28 +497,23 @@ unsafe fn init(&mut self) { .impl_sizes(4, 4) .build(); =20 - // SAFETY: - // - // self and self.iomem are guaranteed to be valid at this point si= nce callers - // must make sure the `self` reference is valid. + // SAFETY: this and this.iomem are guaranteed to be valid at this = point MemoryRegion::init_io( - unsafe { &mut *addr_of_mut!(self.iomem) }, - addr_of_mut!(*self), + &mut uninit_field_mut!(*this, iomem), &PL011_OPS, "pl011", 0x1000, ); =20 - self.regs =3D Default::default(); + uninit_field_mut!(*this, regs).write(Default::default()); =20 - // SAFETY: - // - // self.clock is not initialized at this point; but since `Owned<_= >` is - // not Drop, we can overwrite the undefined value without side eff= ects; - // it's not sound but, because for all PL011State instances are cr= eated - // by QOM code which calls this function to initialize the fields,= at - // leastno code is able to access an invalid self.clock value. - self.clock =3D self.init_clock_in("clk", &Self::clock_update, Cloc= kEvent::ClockUpdate); + let clock =3D DeviceState::init_clock_in( + &mut this, + "clk", + &Self::clock_update, + ClockEvent::ClockUpdate, + ); + uninit_field_mut!(*this, clock).write(clock); } =20 const fn clock_update(&self, _event: ClockEvent) { diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/devi= ce.rs index 340ca1d355d..a281927781e 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -21,8 +21,8 @@ hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEM= TXATTRS_UNSPECIFIED, }, prelude::*, - qdev::{DeviceImpl, DeviceMethods, DeviceState, Property, ResetType, Re= settablePhasesImpl}, - qom::{ObjectImpl, ObjectType, ParentField}, + qdev::{DeviceImpl, DeviceState, Property, ResetType, ResettablePhasesI= mpl}, + qom::{ObjectImpl, ObjectType, ParentField, ParentInit}, qom_isa, sysbus::{SysBusDevice, SysBusDeviceImpl}, timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, @@ -697,7 +697,7 @@ fn set_counter_reg(&self, shift: u32, len: u32, val: u6= 4) { .set(self.counter.get().deposit(shift, len, val)); } =20 - unsafe fn init(&mut self) { + unsafe fn init(mut this: ParentInit) { static HPET_RAM_OPS: MemoryRegionOps =3D MemoryRegionOpsBuilder::::new() .read(&HPETState::read) @@ -707,18 +707,14 @@ unsafe fn init(&mut self) { .impl_sizes(4, 8) .build(); =20 - // SAFETY: - // self and self.iomem are guaranteed to be valid at this point si= nce 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, ); =20 - Self::init_timers(unsafe { &mut *((self as *mut Self).cast::>()) }); + Self::init_timers(&mut this); } =20 fn post_init(&self) { @@ -900,7 +896,7 @@ unsafe impl ObjectType for HPETState { impl ObjectImpl for HPETState { type ParentType =3D SysBusDevice; =20 - const INSTANCE_INIT: Option =3D Some(Self::init); + const INSTANCE_INIT: Option)> =3D Some(Self= ::init); const INSTANCE_POST_INIT: Option =3D Some(Self::post_init); const CLASS_INIT: fn(&mut Self::Class) =3D Self::Class::class_init::; } diff --git a/rust/qemu-api/src/memory.rs b/rust/qemu-api/src/memory.rs index 9ef2694bd62..e40fad6cf19 100644 --- a/rust/qemu-api/src/memory.rs +++ b/rust/qemu-api/src/memory.rs @@ -16,6 +16,7 @@ callbacks::FnCall, cell::Opaque, prelude::*, + uninit::MaybeUninitField, zeroable::Zeroable, }; =20 @@ -147,7 +148,7 @@ impl MemoryRegion { #[inline(always)] unsafe fn do_init_io( slot: *mut bindings::MemoryRegion, - owner: *mut Object, + owner: *mut bindings::Object, ops: &'static bindings::MemoryRegionOps, name: &'static str, size: u64, @@ -156,7 +157,7 @@ unsafe fn do_init_io( let cstr =3D CString::new(name).unwrap(); memory_region_init_io( slot, - owner.cast::(), + owner, ops, owner.cast::(), cstr.as_ptr(), @@ -166,16 +167,15 @@ unsafe fn do_init_io( } =20 pub fn init_io>( - &mut self, - owner: *mut T, + this: &mut MaybeUninitField<'_, T, Self>, ops: &'static MemoryRegionOps, name: &'static str, size: u64, ) { unsafe { Self::do_init_io( - self.0.as_mut_ptr(), - owner.cast::(), + this.as_mut_ptr().cast(), + MaybeUninitField::parent_mut(this).cast(), &ops.0, name, size, diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 0610959f467..a2a95a4938f 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -19,7 +19,7 @@ error::{Error, Result}, irq::InterruptSource, prelude::*, - qom::{ObjectClass, ObjectImpl, Owned}, + qom::{ObjectClass, ObjectImpl, Owned, ParentInit}, vmstate::VMStateDescription, }; =20 @@ -247,15 +247,9 @@ unsafe impl ObjectType for DeviceState { } qom_isa!(DeviceState: Object); =20 -/// Trait for methods exposed by the [`DeviceState`] class. The methods c= an be -/// called on all objects that have the trait `IsA`. -/// -/// The trait should only be used through the blanket implementation, -/// which guarantees safety via `IsA`. -pub trait DeviceMethods: ObjectDeref -where - Self::Target: IsA, -{ +/// Initialization methods take a [`ParentInit`] and can be called as +/// associated functions. +impl DeviceState { /// Add an input clock named `name`. Invoke the callback with /// `self` as the first parameter for the events that are requested. /// @@ -266,12 +260,15 @@ pub trait DeviceMethods: ObjectDeref /// which Rust code has a reference to a child object) it would be /// possible for this function to return a `&Clock` too. #[inline] - fn init_clock_in FnCall<(&'a Self::Target, ClockEvent)>>( - &self, + pub fn init_clock_in FnCall<(&'a T, ClockEve= nt)>>( + this: &mut ParentInit, name: &str, _cb: &F, events: ClockEvent, - ) -> Owned { + ) -> Owned + where + T::ParentType: IsA, + { fn do_init_clock_in( dev: &DeviceState, name: &str, @@ -287,10 +284,10 @@ fn do_init_clock_in( unsafe { let cstr =3D CString::new(name).unwrap(); let clk =3D bindings::qdev_init_clock_in( - dev.as_mut_ptr(), + dev.0.as_mut_ptr(), cstr.as_ptr(), cb, - dev.as_void_ptr(), + dev.0.as_void_ptr(), events.0, ); =20 @@ -307,12 +304,12 @@ fn do_init_clock_in( // SAFETY: the opaque is "this", which is indeed a pointer= to T F::call((unsafe { &*(opaque.cast::()) }, event)) } - Some(rust_clock_cb::) + Some(rust_clock_cb::) } else { None }; =20 - do_init_clock_in(self.upcast(), name, cb, events) + do_init_clock_in(unsafe { this.upcast_mut() }, name, cb, events) } =20 /// Add an output clock named `name`. @@ -324,16 +321,32 @@ fn do_init_clock_in( /// which Rust code has a reference to a child object) it would be /// possible for this function to return a `&Clock` too. #[inline] - fn init_clock_out(&self, name: &str) -> Owned { + pub fn init_clock_out(this: &mut ParentInit, name: &= str) -> Owned + where + T::ParentType: IsA, + { unsafe { let cstr =3D CString::new(name).unwrap(); - let clk =3D bindings::qdev_init_clock_out(self.upcast().as_mut= _ptr(), cstr.as_ptr()); + // TODO: introduce a type guaranteeing that the DeviceState pa= rt has been + // initialized + let dev: &mut DeviceState =3D this.upcast_mut(); + let clk =3D bindings::qdev_init_clock_out(dev.0.as_mut_ptr(), = cstr.as_ptr()); =20 let clk: &Clock =3D Clock::from_raw(clk); Owned::from(clk) } } +} =20 +/// Trait for methods exposed by the [`DeviceState`] class. The methods c= an be +/// called on all objects that have the trait `IsA`. +/// +/// The trait should only be used through the blanket implementation, +/// which guarantees safety via `IsA`. +pub trait DeviceMethods: ObjectDeref +where + Self::Target: IsA, +{ fn prop_set_chr(&self, propname: &str, chr: &Owned) { assert!(bql_locked()); let c_propname =3D CString::new(propname).unwrap(); diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 1481ef20f0c..80a50108e65 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -371,12 +371,15 @@ fn deref_mut(&mut self) -> &mut Self::Target { } =20 unsafe extern "C" fn rust_instance_init(obj: *mut bindings:= :Object) { - let mut state =3D NonNull::new(obj).unwrap().cast::(); + let mut state =3D NonNull::new(obj).unwrap().cast::>(); + // SAFETY: obj is an instance of T, since rust_instance_init // is called from QOM core as the instance_init function // for class T unsafe { - T::INSTANCE_INIT.unwrap()(state.as_mut()); + ParentInit::with(state.as_mut(), |parent_init| { + T::INSTANCE_INIT.unwrap()(parent_init); + }); } } =20 @@ -643,7 +646,7 @@ pub trait ObjectImpl: ObjectType + IsA { /// /// FIXME: The argument is not really a valid reference. `&mut /// MaybeUninit` would be a better description. - const INSTANCE_INIT: Option =3D None; + const INSTANCE_INIT: Option)> =3D None; =20 /// Function that is called to finish initialization of an object, once /// `INSTANCE_INIT` functions have been called. --=20 2.49.0