Skip to content

Commit 2b0a5aa

Browse files
committed
fix: don't panic on volatile access to null
According to https://discourse.llvm.org/t/rfc-volatile-access-to-non-dereferenceable-memory-may-be-well-defined/86303/4, LLVM allows volatile operations on null and handles it correctly. This should be allowed in Rust as well, because I/O memory may be hard-coded to address 0 in some cases, like the AVR chip ATtiny1626. A test case that ensured a failure when passing null to volatile was removed, since it's now valid. Due to the addition of `maybe_is_aligned` to `ub_checks`, `maybe_is_aligned_and_not_null` was refactored to use it.
1 parent 2398bd6 commit 2b0a5aa

File tree

4 files changed

+21
-17
lines changed

4 files changed

+21
-17
lines changed

library/core/src/ptr/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,12 +2090,11 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
20902090
unsafe {
20912091
ub_checks::assert_unsafe_precondition!(
20922092
check_language_ub,
2093-
"ptr::read_volatile requires that the pointer argument is aligned and non-null",
2093+
"ptr::read_volatile requires that the pointer argument is aligned",
20942094
(
20952095
addr: *const () = src as *const (),
20962096
align: usize = align_of::<T>(),
2097-
is_zst: bool = T::IS_ZST,
2098-
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
2097+
) => ub_checks::maybe_is_aligned(addr, align)
20992098
);
21002099
intrinsics::volatile_load(src)
21012100
}
@@ -2170,12 +2169,11 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
21702169
unsafe {
21712170
ub_checks::assert_unsafe_precondition!(
21722171
check_language_ub,
2173-
"ptr::write_volatile requires that the pointer argument is aligned and non-null",
2172+
"ptr::write_volatile requires that the pointer argument is aligned",
21742173
(
21752174
addr: *mut () = dst as *mut (),
21762175
align: usize = align_of::<T>(),
2177-
is_zst: bool = T::IS_ZST,
2178-
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
2176+
) => ub_checks::maybe_is_aligned(addr, align)
21792177
);
21802178
intrinsics::volatile_store(dst, src);
21812179
}

library/core/src/ub_checks.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,25 @@ pub(crate) const fn maybe_is_aligned_and_not_null(
120120
align: usize,
121121
is_zst: bool,
122122
) -> bool {
123+
// This is just for safety checks so we can const_eval_select.
124+
maybe_is_aligned(ptr, align) && (is_zst || !ptr.is_null())
125+
}
126+
127+
/// Checks whether `ptr` is properly aligned with respect to the given alignment.
128+
///
129+
/// In `const` this is approximate and can fail spuriously. It is primarily intended
130+
/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
131+
/// check is anyway not executed in `const`.
132+
#[inline]
133+
#[rustc_allow_const_fn_unstable(const_eval_select)]
134+
pub(crate) const fn maybe_is_aligned(ptr: *const (), align: usize) -> bool {
123135
// This is just for safety checks so we can const_eval_select.
124136
const_eval_select!(
125-
@capture { ptr: *const (), align: usize, is_zst: bool } -> bool:
137+
@capture { ptr: *const (), align: usize } -> bool:
126138
if const {
127-
is_zst || !ptr.is_null()
139+
true
128140
} else {
129-
ptr.is_aligned_to(align) && (is_zst || !ptr.is_null())
141+
ptr.is_aligned_to(align)
130142
}
131143
)
132144
}

tests/ui/precondition-checks/read_volatile.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@ run-fail
22
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
33
//@ error-pattern: unsafe precondition(s) violated: ptr::read_volatile requires
4-
//@ revisions: null misaligned
4+
//@ revisions: misaligned
55

66
#![allow(invalid_null_arguments)]
77

@@ -11,8 +11,6 @@ fn main() {
1111
let src = [0u16; 2];
1212
let src = src.as_ptr();
1313
unsafe {
14-
#[cfg(null)]
15-
ptr::read_volatile(ptr::null::<u8>());
1614
#[cfg(misaligned)]
1715
ptr::read_volatile(src.byte_add(1));
1816
}

tests/ui/precondition-checks/write_volatile.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
//@ run-fail
22
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
33
//@ error-pattern: unsafe precondition(s) violated: ptr::write_volatile requires
4-
//@ revisions: null misaligned
5-
6-
#![allow(invalid_null_arguments)]
4+
//@ revisions: misaligned
75

86
use std::ptr;
97

108
fn main() {
119
let mut dst = [0u16; 2];
1210
let mut dst = dst.as_mut_ptr();
1311
unsafe {
14-
#[cfg(null)]
15-
ptr::write_volatile(ptr::null_mut::<u8>(), 1u8);
1612
#[cfg(misaligned)]
1713
ptr::write_volatile(dst.byte_add(1), 1u16);
1814
}

0 commit comments

Comments
 (0)