Skip to content

Commit c51e1f1

Browse files
BennoLossinhoshinolina
authored andcommitted
rust: init: make guards in the init macros hygienic
Use hygienic identifiers for the guards instead of the field names. This makes the init macros feel more like normal struct initializers, since assigning identifiers with the name of a field does not create conflicts. Suggested-by: Asahi Lina <[email protected]> Signed-off-by: Benno Lossin <[email protected]>
1 parent 6c5c322 commit c51e1f1

3 files changed

Lines changed: 47 additions & 102 deletions

File tree

rust/kernel/init.rs

Lines changed: 42 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,6 @@ use crate::{
205205
use alloc::boxed::Box;
206206
use core::{
207207
alloc::AllocError,
208-
cell::Cell,
209208
convert::Infallible,
210209
marker::PhantomData,
211210
mem::MaybeUninit,
@@ -636,6 +635,7 @@ macro_rules! try_pin_init {
636635
$crate::try_pin_init!(init_slot:
637636
@data(data),
638637
@slot(slot),
638+
@guards(),
639639
@munch_fields($($fields)*,),
640640
);
641641
// We use unreachable code to ensure that all fields have been mentioned exactly
@@ -650,10 +650,6 @@ macro_rules! try_pin_init {
650650
@acc(),
651651
);
652652
}
653-
// Forget all guards, since initialization was a success.
654-
$crate::try_pin_init!(forget_guards:
655-
@munch_fields($($fields)*,),
656-
);
657653
}
658654
Ok(__InitOk)
659655
}
@@ -667,13 +663,17 @@ macro_rules! try_pin_init {
667663
(init_slot:
668664
@data($data:ident),
669665
@slot($slot:ident),
666+
@guards($($guards:ident,)*),
670667
@munch_fields($(,)?),
671668
) => {
672-
// Endpoint of munching, no fields are left.
669+
// Endpoint of munching, no fields are left. If execution reaches this point, all fields
670+
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
671+
$(::core::mem::forget($guards);)*
673672
};
674673
(init_slot:
675674
@data($data:ident),
676675
@slot($slot:ident),
676+
@guards($($guards:ident,)*),
677677
// In-place initialization syntax.
678678
@munch_fields($field:ident <- $val:expr, $($rest:tt)*),
679679
) => {
@@ -686,22 +686,24 @@ macro_rules! try_pin_init {
686686
unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), $field)? };
687687
// Create the drop guard.
688688
//
689-
// We only give access to `&DropGuard`, so it cannot be forgotten via safe code.
689+
// Users cannot access this field due to macro hygiene.
690690
//
691691
// SAFETY: We forget the guard later when initialization has succeeded.
692-
let $field = &unsafe {
692+
let guard = unsafe {
693693
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
694694
};
695695

696696
$crate::try_pin_init!(init_slot:
697697
@data($data),
698698
@slot($slot),
699+
@guards(guard, $($guards,)*),
699700
@munch_fields($($rest)*),
700701
);
701702
};
702703
(init_slot:
703704
@data($data:ident),
704705
@slot($slot:ident),
706+
@guards($($guards:ident,)*),
705707
// Direct value init, this is safe for every field.
706708
@munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
707709
) => {
@@ -712,16 +714,17 @@ macro_rules! try_pin_init {
712714
unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
713715
// Create the drop guard:
714716
//
715-
// We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
717+
// Users cannot access this field due to macro hygiene.
716718
//
717719
// SAFETY: We forget the guard later when initialization has succeeded.
718-
let $field = &unsafe {
720+
let guard = unsafe {
719721
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
720722
};
721723

722724
$crate::try_pin_init!(init_slot:
723725
@data($data),
724726
@slot($slot),
727+
@guards(guard, $($guards,)*),
725728
@munch_fields($($rest)*),
726729
);
727730
};
@@ -766,29 +769,6 @@ macro_rules! try_pin_init {
766769
@acc($($acc)* $field: ::core::panic!(),),
767770
);
768771
};
769-
(forget_guards:
770-
@munch_fields($(,)?),
771-
) => {
772-
// Munching finished.
773-
};
774-
(forget_guards:
775-
@munch_fields($field:ident <- $val:expr, $($rest:tt)*),
776-
) => {
777-
unsafe { $crate::init::__internal::DropGuard::forget($field) };
778-
779-
$crate::try_pin_init!(forget_guards:
780-
@munch_fields($($rest)*),
781-
);
782-
};
783-
(forget_guards:
784-
@munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
785-
) => {
786-
unsafe { $crate::init::__internal::DropGuard::forget($field) };
787-
788-
$crate::try_pin_init!(forget_guards:
789-
@munch_fields($($rest)*),
790-
);
791-
};
792772
}
793773

794774
/// Construct an in-place initializer for `struct`s.
@@ -903,6 +883,7 @@ macro_rules! try_init {
903883
// Initialize every field.
904884
$crate::try_init!(init_slot:
905885
@slot(slot),
886+
@guards(),
906887
@munch_fields($($fields)*,),
907888
);
908889
// We use unreachable code to ensure that all fields have been mentioned exactly
@@ -917,10 +898,6 @@ macro_rules! try_init {
917898
@acc(),
918899
);
919900
}
920-
// Forget all guards, since initialization was a success.
921-
$crate::try_init!(forget_guards:
922-
@munch_fields($($fields)*,),
923-
);
924901
}
925902
Ok(__InitOk)
926903
}
@@ -933,57 +910,68 @@ macro_rules! try_init {
933910
}};
934911
(init_slot:
935912
@slot($slot:ident),
913+
@guards($($guards:ident,)*),
936914
@munch_fields( $(,)?),
937915
) => {
938-
// Endpoint of munching, no fields are left.
916+
// Endpoint of munching, no fields are left. If execution reaches this point, all fields
917+
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
918+
$(::core::mem::forget($guards);)*
939919
};
940920
(init_slot:
941921
@slot($slot:ident),
922+
@guards($($guards:ident,)*),
942923
@munch_fields($field:ident <- $val:expr, $($rest:tt)*),
943924
) => {
944-
let $field = $val;
945-
// Call the initializer.
946-
//
947-
// SAFETY: `slot` is valid, because we are inside of an initializer closure, we
948-
// return when an error/panic occurs.
949-
unsafe {
950-
$crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))?;
925+
{
926+
let $field = $val;
927+
// Call the initializer.
928+
//
929+
// SAFETY: `slot` is valid, because we are inside of an initializer closure, we
930+
// return when an error/panic occurs.
931+
unsafe {
932+
$crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))?;
933+
}
951934
}
952935
// Create the drop guard.
953936
//
954-
// We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
937+
// Users cannot access this field due to macro hygiene.
955938
//
956939
// SAFETY: We forget the guard later when initialization has succeeded.
957-
let $field = &unsafe {
940+
let guard = unsafe {
958941
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
959942
};
960943

961944
$crate::try_init!(init_slot:
962945
@slot($slot),
946+
@guards(guard, $($guards,)*),
963947
@munch_fields($($rest)*),
964948
);
965949
};
966950
(init_slot:
967951
@slot($slot:ident),
952+
@guards($($guards:ident,)*),
968953
// Direct value init.
969954
@munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
970955
) => {
971-
$(let $field = $val;)?
972-
// Call the initializer.
973-
//
974-
// SAFETY: The memory at `slot` is uninitialized.
975-
unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
956+
{
957+
$(let $field = $val;)?
958+
// Call the initializer.
959+
//
960+
// SAFETY: The memory at `slot` is uninitialized.
961+
unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
962+
}
976963
// Create the drop guard.
977964
//
978-
// We only give access to `&DropGuard`, so it cannot be accidentally forgotten.
965+
// Users cannot access this field due to macro hygiene.
979966
//
980967
// SAFETY: We forget the guard later when initialization has succeeded.
981-
let $field = &unsafe {
968+
let guard = unsafe {
982969
$crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
983970
};
984971

985972
$crate::try_init!(init_slot:
986973
@slot($slot),
974+
@guards(guard, $($guards,)*),
987975
@munch_fields($($rest)*),
988976
);
989977
};
@@ -1028,29 +1016,6 @@ macro_rules! try_init {
10281016
@acc($($acc)*$field: ::core::panic!(),),
10291017
);
10301018
};
1031-
(forget_guards:
1032-
@munch_fields($(,)?),
1033-
) => {
1034-
// Munching finished.
1035-
};
1036-
(forget_guards:
1037-
@munch_fields($field:ident <- $val:expr, $($rest:tt)*),
1038-
) => {
1039-
unsafe { $crate::init::__internal::DropGuard::forget($field) };
1040-
1041-
$crate::try_init!(forget_guards:
1042-
@munch_fields($($rest)*),
1043-
);
1044-
};
1045-
(forget_guards:
1046-
@munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
1047-
) => {
1048-
unsafe { $crate::init::__internal::DropGuard::forget($field) };
1049-
1050-
$crate::try_init!(forget_guards:
1051-
@munch_fields($($rest)*),
1052-
);
1053-
};
10541019
}
10551020

10561021
/// A pin-initializer for the type `T`.

rust/kernel/init/__internal.rs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ impl<T> StackInit<T> {
174174
/// Can be forgotten to prevent the drop.
175175
pub struct DropGuard<T: ?Sized> {
176176
ptr: *mut T,
177-
do_drop: Cell<bool>,
178177
}
179178

180179
impl<T: ?Sized> DropGuard<T> {
@@ -190,32 +189,16 @@ impl<T: ?Sized> DropGuard<T> {
190189
/// - will not be dropped by any other means.
191190
#[inline]
192191
pub unsafe fn new(ptr: *mut T) -> Self {
193-
Self {
194-
ptr,
195-
do_drop: Cell::new(true),
196-
}
197-
}
198-
199-
/// Prevents this guard from dropping the supplied pointer.
200-
///
201-
/// # Safety
202-
///
203-
/// This function is unsafe in order to prevent safe code from forgetting this guard. It should
204-
/// only be called by the macros in this module.
205-
#[inline]
206-
pub unsafe fn forget(&self) {
207-
self.do_drop.set(false);
192+
Self { ptr }
208193
}
209194
}
210195

211196
impl<T: ?Sized> Drop for DropGuard<T> {
212197
#[inline]
213198
fn drop(&mut self) {
214-
if self.do_drop.get() {
215-
// SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function
216-
// ensuring that this operation is safe.
217-
unsafe { ptr::drop_in_place(self.ptr) }
218-
}
199+
// SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function
200+
// ensuring that this operation is safe.
201+
unsafe { ptr::drop_in_place(self.ptr) }
219202
}
220203
}
221204

rust/macros/zeroable.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use crate::{
2-
helpers::{parse_generics, Generics},
3-
quote,
4-
};
1+
use crate::helpers::{parse_generics, Generics};
52
use proc_macro::TokenStream;
63

74
pub(crate) fn derive(input: TokenStream) -> TokenStream {

0 commit comments

Comments
 (0)