Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/core/src/alloc/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl Layout {
assert_unsafe_precondition!(
check_library_ub,
"Layout::from_size_align_unchecked requires that align is a power of 2 \
and the rounded-up allocation size does not exceed isize::MAX",
and the rounded-up allocation size does not exceed isize::MAX (size:{size}, align:{align})",
(
size: usize = size,
align: usize = align,
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/ascii/ascii_char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ impl AsciiChar {
pub const unsafe fn digit_unchecked(d: u8) -> Self {
assert_unsafe_precondition!(
check_library_ub,
"`ascii::Char::digit_unchecked` input cannot exceed 9.",
"`ascii::Char::digit_unchecked` input cannot exceed 9. (d:{d})",
(d: u8 = d) => d < 10
);

Expand Down
2 changes: 1 addition & 1 deletion library/core/src/char/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
unsafe {
assert_unsafe_precondition!(
check_language_ub,
"invalid value for `char`",
"invalid value for `char` ({i})",
(i: u32 = i) => char_try_from_u32(i).is_ok()
);
transmute(i)
Expand Down
5 changes: 3 additions & 2 deletions library/core/src/char/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,8 +1260,9 @@ impl char {
pub const unsafe fn as_ascii_unchecked(&self) -> ascii::Char {
assert_unsafe_precondition!(
check_library_ub,
"as_ascii_unchecked requires that the char is valid ASCII",
(it: &char = self) => it.is_ascii()
"as_ascii_unchecked requires that the char is valid ASCII \
(self:{it})",
(it: char = *self) => it.is_ascii()
);

// SAFETY: the caller promised that this char is ASCII.
Expand Down
124 changes: 124 additions & 0 deletions library/core/src/displaywrapper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use core::fmt::{Display, Formatter, Result};

#[allow(missing_debug_implementations)]
pub struct DisplayWrapper<T>(pub T);

macro_rules! display_int {
($ty:ty) => {
impl Display for DisplayWrapper<$ty> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let n = self.0;
let is_negative = n < 0;
let n = (!(n as u128)).wrapping_add(1);
display_int(n, is_negative, f)
}
}
};
}

display_int!(i8);
display_int!(i16);
display_int!(i32);
display_int!(i64);
display_int!(i128);
display_int!(isize);

macro_rules! display_uint {
($ty:ty) => {
impl Display for DisplayWrapper<$ty> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
display_int(self.0 as u128, false, f)
}
}
};
}

display_uint!(u8);
display_uint!(u16);
display_uint!(u32);
display_uint!(u64);
display_uint!(u128);
display_uint!(usize);

impl Display for DisplayWrapper<*const ()> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
format_ptr(self.0.addr(), f)
}
}
impl Display for DisplayWrapper<*mut ()> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
format_ptr(self.0.addr(), f)
}
}

#[inline]
fn format_ptr(addr: usize, f: &mut Formatter<'_>) -> Result {
const HEX: [u8; 16] = *b"0123456789abcdef";
let mut buf = [0u8; 42];
let mut cur = buf.len();

let mut n = addr;
while n >= 16 {
let d = n % 16;
n /= 16;
cur -= 1;
buf[cur] = HEX[d];
}
cur -= 1;
buf[cur] = HEX[n];

cur -= 1;
buf[cur] = b'x';
cur -= 1;
buf[cur] = b'0';

// SAFETY: The buffer is initially ASCII and we only write ASCII bytes to it.
let s = unsafe { core::str::from_utf8_unchecked(&buf[cur..]) };
f.write_str(s)
}

impl Display for DisplayWrapper<char> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let mut buf = [0u8; 4];
let s = self.0.encode_utf8(&mut buf);
f.write_str(s)
}
}

impl Display for DisplayWrapper<bool> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let s = match self.0 {
true => "true",
false => "false",
};
f.write_str(s)
}
}

#[inline]
fn display_int(mut n: u128, is_negative: bool, f: &mut Formatter<'_>) -> Result {
let mut buf = [0u8; 42];
let mut cur = buf.len();

while n >= 10 {
let d = n % 10;
n /= 10;
cur -= 1;
buf[cur] = (d as u8) + b'0';
}
cur -= 1;
buf[cur] = (n as u8) + b'0';
if is_negative {
cur -= 1;
buf[cur] = b'-';
}
// SAFETY: The buffer is initially ASCII and we only write ASCII bytes to it.
let s = unsafe { core::str::from_utf8_unchecked(&buf[cur..]) };
f.write_str(s)
}
1 change: 1 addition & 0 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,7 @@ impl<'a> Formatter<'a> {
/// assert_eq!(format!("{Foo:0>8}"), "Foo");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn write_str(&mut self, data: &str) -> Result {
self.buf.write_str(data)
}
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2388,7 +2388,7 @@ where
/// marked as `#[inline]`.
///
/// See [`const_eval_select()`] for the rules and requirements around that intrinsic.
pub(crate) macro const_eval_select {
pub macro const_eval_select {
(
@capture$([$($binders:tt)*])? { $($arg:ident : $ty:ty = $val:expr),* $(,)? } $( -> $ret:ty )? :
if const
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ pub mod alloc;

// note: does not need to be public
mod bool;
#[doc(hidden)]
#[unstable(feature = "ub_checks", issue = "none")]
pub mod displaywrapper;
mod escape;
mod tuple;
mod unit;
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ impl u8 {
assert_unsafe_precondition!(
check_library_ub,
"as_ascii_unchecked requires that the byte is valid ASCII",
(it: &u8 = self) => it.is_ascii()
(it: u8 = *self) => it.is_ascii()
);

// SAFETY: the caller promised that this byte is ASCII.
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/ops/index_range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ impl IndexRange {
pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
ub_checks::assert_unsafe_precondition!(
check_library_ub,
"IndexRange::new_unchecked requires `start <= end`",
"IndexRange::new_unchecked requires `start <= end` \
(start:{start}, end:{end})",
(start: usize = start, end: usize = end) => start <= end,
);
IndexRange { start, end }
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/ptr/alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ impl Alignment {
pub const unsafe fn new_unchecked(align: usize) -> Self {
assert_unsafe_precondition!(
check_language_ub,
"Alignment::new_unchecked requires a power of two",
"Alignment::new_unchecked requires a power of two \
(align:{align})",
(align: usize = align) => align.is_power_of_two()
);

Expand Down
12 changes: 8 additions & 4 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@ impl<T: PointeeSized> *const T {

ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::offset requires the address calculation to not overflow",
"ptr::offset requires the address calculation to not overflow \
(ptr:{this}, count:{count}, size:{size})",
(
this: *const () = self as *const (),
count: isize = count,
Expand Down Expand Up @@ -716,7 +717,8 @@ impl<T: PointeeSized> *const T {

ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::offset_from_unsigned requires `self >= origin`",
"ptr::offset_from_unsigned requires `self >= origin` \
(self:{this}, origin:{origin})",
(
this: *const () = self as *const (),
origin: *const () = origin as *const (),
Expand Down Expand Up @@ -851,7 +853,8 @@ impl<T: PointeeSized> *const T {
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::add requires that the address calculation does not overflow",
"ptr::add requires that the address calculation does not overflow \
(self:{this}, count:{count}, size:{size})",
(
this: *const () = self as *const (),
count: usize = count,
Expand Down Expand Up @@ -956,7 +959,8 @@ impl<T: PointeeSized> *const T {
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::sub requires that the address calculation does not overflow",
"ptr::sub requires that the address calculation does not overflow \
(self:{this}, count:{count}, size:{size})",
(
this: *const () = self as *const (),
count: usize = count,
Expand Down
27 changes: 18 additions & 9 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,8 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
and the specified memory ranges do not overlap",
and the specified memory ranges do not overlap \
(src{src}, dst:{dst}, size:{size}, align:{align}, count:{count})",
(
src: *const () = src as *const (),
dst: *mut () = dst as *mut (),
Expand Down Expand Up @@ -625,7 +626,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
unsafe {
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::copy requires that both pointer arguments are aligned and non-null",
"ptr::copy requires that both pointer arguments are aligned and non-null \
(src{src}, dst:{dst}, align:{align})",
(
src: *const () = src as *const (),
dst: *mut () = dst as *mut (),
Expand Down Expand Up @@ -699,7 +701,8 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
unsafe {
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::write_bytes requires that the destination pointer is aligned and non-null",
"ptr::write_bytes requires that the destination pointer is aligned and non-null \
(dst:{addr}, align:{align})",
(
addr: *const () = dst as *const (),
align: usize = align_of::<T>(),
Expand Down Expand Up @@ -1392,7 +1395,8 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
ub_checks::assert_unsafe_precondition!(
check_library_ub,
"ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
and the specified memory ranges do not overlap",
and the specified memory ranges do not overlap \
(x:{x}, y:{y}, size:{size}, align:{align}, count:{count})",
(
x: *mut () = x as *mut (),
y: *mut () = y as *mut (),
Expand Down Expand Up @@ -1577,7 +1581,8 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
unsafe {
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::replace requires that the pointer argument is aligned and non-null",
"ptr::replace requires that the pointer argument is aligned and non-null \
(dst:{addr}, (align:{align}))",
(
addr: *const () = dst as *const (),
align: usize = align_of::<T>(),
Expand Down Expand Up @@ -1730,7 +1735,8 @@ pub const unsafe fn read<T>(src: *const T) -> T {
#[cfg(debug_assertions)] // Too expensive to always enable (for now?)
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::read requires that the pointer argument is aligned and non-null",
"ptr::read requires that the pointer argument is aligned and non-null \
(src:{addr}, align:{align})",
(
addr: *const () = src as *const (),
align: usize = align_of::<T>(),
Expand Down Expand Up @@ -1930,7 +1936,8 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
#[cfg(debug_assertions)] // Too expensive to always enable (for now?)
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::write requires that the pointer argument is aligned and non-null",
"ptr::write requires that the pointer argument is aligned and non-null \
(dst:{addr}, align:{align})",
(
addr: *mut () = dst as *mut (),
align: usize = align_of::<T>(),
Expand Down Expand Up @@ -2105,7 +2112,8 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
unsafe {
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::read_volatile requires that the pointer argument is aligned",
"ptr::read_volatile requires that the pointer argument is aligned \
(src:{addr}, align:{align})",
(
addr: *const () = src as *const (),
align: usize = align_of::<T>(),
Expand Down Expand Up @@ -2192,7 +2200,8 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
unsafe {
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::write_volatile requires that the pointer argument is aligned",
"ptr::write_volatile requires that the pointer argument is aligned \
(dst:{addr}, align:{align})",
(
addr: *mut () = dst as *mut (),
align: usize = align_of::<T>(),
Expand Down
9 changes: 6 additions & 3 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,8 @@ impl<T: PointeeSized> *mut T {

ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::offset requires the address calculation to not overflow",
"ptr::offset requires the address calculation to not overflow \
(self:{this}, count:{count}, size:{size})",
(
this: *const () = self as *const (),
count: isize = count,
Expand Down Expand Up @@ -949,7 +950,8 @@ impl<T: PointeeSized> *mut T {
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::add requires that the address calculation does not overflow",
"ptr::add requires that the address calculation does not overflow \
(self:{this}, count:{count}, size:{size})",
(
this: *const () = self as *const (),
count: usize = count,
Expand Down Expand Up @@ -1054,7 +1056,8 @@ impl<T: PointeeSized> *mut T {
#[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild.
ub_checks::assert_unsafe_precondition!(
check_language_ub,
"ptr::sub requires that the address calculation does not overflow",
"ptr::sub requires that the address calculation does not overflow \
(self:{this}, count:{count}, size:{size})",
(
this: *const () = self as *const (),
count: usize = count,
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ impl<T: PointeeSized> NonNull<T> {
unsafe {
assert_unsafe_precondition!(
check_language_ub,
"NonNull::new_unchecked requires that the pointer is non-null",
"NonNull::new_unchecked requires that the pointer is non-null (ptr:{ptr})",
(ptr: *mut () = ptr as *mut ()) => !ptr.is_null()
);
NonNull { pointer: ptr as _ }
Expand Down
Loading
Loading