Skip to content

Commit 554c806

Browse files
committed
reject mapping to unaligned fields
1 parent aa93fb9 commit 554c806

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

src/lib.rs

+35-4
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,57 @@ pub mod access;
5757
/// let field_2 = map_field!(volatile.field_2);
5858
/// assert_eq!(field_2.read(), 255);
5959
/// ```
60+
///
61+
/// Creating `VolatilePtr`s to unaligned field in packed structs is not allowed:
62+
/// ```compile_fail
63+
/// # extern crate core;
64+
/// use volatile::{VolatilePtr, map_field};
65+
/// use core::ptr::NonNull;
66+
///
67+
/// #[repr(packed)]
68+
/// struct Example { field_1: u8, field_2: usize, }
69+
/// let mut value = Example { field_1: 15, field_2: 255 };
70+
/// let mut volatile = unsafe { VolatilePtr::new_read_write(NonNull::from(&mut value)) };
71+
///
72+
/// // Constructing a volatile reference to an unaligned field doesn't compile.
73+
/// let field_2 = map_field!(volatile.field_2);
74+
/// ```
6075
#[macro_export]
6176
macro_rules! map_field {
62-
($volatile:ident.$place:ident) => {
77+
($volatile:ident.$place:ident) => {{
78+
// Simulate creating a reference to the field. This is done to make
79+
// sure that the field is not potentially unaligned. The body of the
80+
// if statement will never be executed, so it can never cause any UB.
81+
if false {
82+
#[deny(unaligned_references)]
83+
let _ref_to_field = &(unsafe { &*$volatile.as_ptr().as_ptr() }).$place;
84+
}
85+
6386
unsafe {
6487
$volatile.map(|ptr| {
6588
core::ptr::NonNull::new(core::ptr::addr_of_mut!((*ptr.as_ptr()).$place)).unwrap()
6689
})
6790
}
68-
};
91+
}};
6992
}
7093

7194
#[macro_export]
7295
macro_rules! map_field_mut {
73-
($volatile:ident.$place:ident) => {
96+
($volatile:ident.$place:ident) => {{
97+
// Simulate creating a reference to the field. This is done to make
98+
// sure that the field is not potentially unaligned. The body of the
99+
// if statement will never be executed, so it can never cause any UB.
100+
if false {
101+
#[deny(unaligned_references)]
102+
let _ref_to_field = &(unsafe { &*$volatile.as_ptr().as_ptr() }).$place;
103+
}
104+
74105
unsafe {
75106
$volatile.map_mut(|ptr| {
76107
core::ptr::NonNull::new(core::ptr::addr_of_mut!((*ptr.as_ptr()).$place)).unwrap()
77108
})
78109
}
79-
};
110+
}};
80111
}
81112

82113
// this must be defined after the `map_field` macros

0 commit comments

Comments
 (0)