Skip to content

Commit 65e5e12

Browse files
committed
Include arguments to the precondition check in failure messages
1 parent 64feb9b commit 65e5e12

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

library/core/src/slice/index.rs

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Indexing implementations for `[T]`.
22
33
use crate::panic::const_panic;
4-
use crate::ub_checks::assert_unsafe_precondition;
4+
use crate::ub_checks::assert_unsafe_precondition2;
55
use crate::{ops, range};
66

77
#[stable(feature = "rust1", since = "1.0.0")]
@@ -240,10 +240,10 @@ unsafe impl<T> SliceIndex<[T]> for usize {
240240

241241
#[inline]
242242
unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
243-
assert_unsafe_precondition!(
243+
assert_unsafe_precondition2!(
244244
check_language_ub,
245-
"slice::get_unchecked requires that the index is within the slice",
246-
(this: usize = self, len: usize = slice.len()) => this < len
245+
"slice::get_unchecked requires that the index is within the slice (index:{index}, len:{len})",
246+
(index: usize = self, len: usize = slice.len()) => index < len
247247
);
248248
// SAFETY: the caller guarantees that `slice` is not dangling, so it
249249
// cannot be longer than `isize::MAX`. They also guarantee that
@@ -259,10 +259,10 @@ unsafe impl<T> SliceIndex<[T]> for usize {
259259

260260
#[inline]
261261
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
262-
assert_unsafe_precondition!(
262+
assert_unsafe_precondition2!(
263263
check_library_ub,
264-
"slice::get_unchecked_mut requires that the index is within the slice",
265-
(this: usize = self, len: usize = slice.len()) => this < len
264+
"slice::get_unchecked_mut requires that the index is within the slice (index:{index}, len:{len})",
265+
(index: usize = self, len: usize = slice.len()) => index < len
266266
);
267267
// SAFETY: see comments for `get_unchecked` above.
268268
unsafe { get_mut_noubcheck(slice, self) }
@@ -308,9 +308,9 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
308308

309309
#[inline]
310310
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
311-
assert_unsafe_precondition!(
311+
assert_unsafe_precondition2!(
312312
check_library_ub,
313-
"slice::get_unchecked requires that the index is within the slice",
313+
"slice::get_unchecked requires that the index is within the slice (end:{end}, len:{len})",
314314
(end: usize = self.end(), len: usize = slice.len()) => end <= len
315315
);
316316
// SAFETY: the caller guarantees that `slice` is not dangling, so it
@@ -322,9 +322,9 @@ unsafe impl<T> SliceIndex<[T]> for ops::IndexRange {
322322

323323
#[inline]
324324
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
325-
assert_unsafe_precondition!(
325+
assert_unsafe_precondition2!(
326326
check_library_ub,
327-
"slice::get_unchecked_mut requires that the index is within the slice",
327+
"slice::get_unchecked_mut requires that the index is within the slice (end:{end}, len:{len})",
328328
(end: usize = self.end(), len: usize = slice.len()) => end <= len
329329
);
330330

@@ -387,9 +387,9 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
387387

388388
#[inline]
389389
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
390-
assert_unsafe_precondition!(
390+
assert_unsafe_precondition2!(
391391
check_library_ub,
392-
"slice::get_unchecked requires that the range is within the slice",
392+
"slice::get_unchecked requires that the range is within the slice (range:{start}..{end}, len:{len})",
393393
(
394394
start: usize = self.start,
395395
end: usize = self.end,
@@ -411,9 +411,9 @@ unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
411411

412412
#[inline]
413413
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
414-
assert_unsafe_precondition!(
414+
assert_unsafe_precondition2!(
415415
check_library_ub,
416-
"slice::get_unchecked_mut requires that the range is within the slice",
416+
"slice::get_unchecked_mut requires that the range is within the slice (range:{start}..{end}, len:{len})",
417417
(
418418
start: usize = self.start,
419419
end: usize = self.end,

library/core/src/slice/raw.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ use crate::{array, ptr, ub_checks};
123123
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
124124
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
125125
unsafe {
126-
ub_checks::assert_unsafe_precondition!(
126+
ub_checks::assert_unsafe_precondition2!(
127127
check_language_ub,
128-
"slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
128+
"slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX` (data:{data:?}, size:{size:?}, align:{align:?}, len:{len:?})",
129129
(
130130
data: *mut () = data as *mut (),
131131
size: usize = size_of::<T>(),
@@ -177,9 +177,9 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
177177
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
178178
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
179179
unsafe {
180-
ub_checks::assert_unsafe_precondition!(
180+
ub_checks::assert_unsafe_precondition2!(
181181
check_language_ub,
182-
"slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
182+
"slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX` (data:{data:?}, size:{size:?}, align:{align:?}, len:{len:?})",
183183
(
184184
data: *mut () = data as *mut (),
185185
size: usize = size_of::<T>(),

library/core/src/ub_checks.rs

+49
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,55 @@ macro_rules! assert_unsafe_precondition {
7979
}
8080
#[unstable(feature = "ub_checks", issue = "none")]
8181
pub use assert_unsafe_precondition;
82+
83+
/// assert_unsafe_precondition, but full
84+
#[macro_export]
85+
#[unstable(feature = "ub_checks", issue = "none")]
86+
macro_rules! assert_unsafe_precondition2 {
87+
($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
88+
{
89+
// This check is inlineable, but not by the MIR inliner.
90+
// The reason for this is that the MIR inliner is in an exceptionally bad position
91+
// to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
92+
// which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
93+
// would be bad for compile times.
94+
//
95+
// LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
96+
// inlining the check. If it's `true`, it can inline it and get significantly better performance.
97+
#[rustc_no_mir_inline]
98+
#[inline]
99+
#[rustc_nounwind]
100+
#[track_caller]
101+
#[rustc_allow_const_fn_unstable(const_eval_select)]
102+
const fn precondition_check($($name:$ty),*) {
103+
if $e { return; }
104+
crate::intrinsics::const_eval_select!(
105+
@capture { $($name: $ty),* }:
106+
if const #[track_caller] {
107+
::core::panicking::panic_nounwind(
108+
concat!("unsafe precondition(s) violated: ", $message)
109+
);
110+
} else #[track_caller] {
111+
::core::panicking::panic_nounwind_fmt(
112+
format_args!(
113+
concat!("unsafe precondition(s) violated: ", $message),
114+
$($name=$name),*
115+
),
116+
false
117+
);
118+
}
119+
)
120+
}
121+
122+
if ::core::ub_checks::$kind() {
123+
precondition_check($($arg,)*);
124+
}
125+
}
126+
};
127+
}
128+
#[unstable(feature = "ub_checks", issue = "none")]
129+
pub use assert_unsafe_precondition2;
130+
82131
/// Checking library UB is always enabled when UB-checking is done
83132
/// (and we use a reexport so that there is no unnecessary wrapper function).
84133
#[unstable(feature = "ub_checks", issue = "none")]

0 commit comments

Comments
 (0)