Skip to content

Commit d74823a

Browse files
committed
rust-lang#66219 documented unsafe in core::fmt
1 parent d78c056 commit d74823a

File tree

3 files changed

+47
-30
lines changed

3 files changed

+47
-30
lines changed

src/libcore/fmt/float.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ use crate::fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
22
use crate::mem::MaybeUninit;
33
use crate::num::flt2dec;
44

5-
// ignore-tidy-undocumented-unsafe
6-
75
// Don't inline this so callers don't use the stack space this function
86
// requires unless they have to.
97
#[inline(never)]
108
fn float_to_decimal_common_exact<T>(fmt: &mut Formatter<'_>, num: &T,
119
sign: flt2dec::Sign, precision: usize) -> Result
1210
where T: flt2dec::DecodableFloat
1311
{
12+
// SAFETY: possible undefined behavior, see comment
1413
unsafe {
1514
let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
1615
let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit();
@@ -33,6 +32,7 @@ fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter<'_>, num: &T,
3332
sign: flt2dec::Sign, precision: usize) -> Result
3433
where T: flt2dec::DecodableFloat
3534
{
35+
// SAFETY: possible undefined behavior, see comment
3636
unsafe {
3737
// enough for f32 and f64
3838
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
@@ -73,6 +73,7 @@ fn float_to_exponential_common_exact<T>(fmt: &mut Formatter<'_>, num: &T,
7373
upper: bool) -> Result
7474
where T: flt2dec::DecodableFloat
7575
{
76+
// SAFETY: possible undefined behavior, see comment
7677
unsafe {
7778
let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
7879
let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit();
@@ -92,6 +93,7 @@ fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter<'_>,
9293
upper: bool) -> Result
9394
where T: flt2dec::DecodableFloat
9495
{
96+
// SAFETY: possible undefined behavior, see comment
9597
unsafe {
9698
// enough for f32 and f64
9799
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();

src/libcore/fmt/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! Utilities for formatting and printing strings.
22
3-
// ignore-tidy-undocumented-unsafe
4-
53
#![stable(feature = "rust1", since = "1.0.0")]
64

75
use crate::cell::{UnsafeCell, Cell, RefCell, Ref, RefMut};
@@ -279,6 +277,7 @@ impl<'a> ArgumentV1<'a> {
279277
issue = "0")]
280278
pub fn new<'b, T>(x: &'b T,
281279
f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
280+
// SAFETY: relies on T being sized to avoid undefined behavior
282281
unsafe {
283282
ArgumentV1 {
284283
formatter: mem::transmute(f),
@@ -296,6 +295,7 @@ impl<'a> ArgumentV1<'a> {
296295

297296
fn as_usize(&self) -> Option<usize> {
298297
if self.formatter as usize == ArgumentV1::show_usize as usize {
298+
// SAFETY: if the formatter is show_usize, it means it came in as &usize
299299
Some(unsafe { *(self.value as *const _ as *const usize) })
300300
} else {
301301
None
@@ -1355,6 +1355,8 @@ impl<'a> Formatter<'a> {
13551355
let mut align = old_align;
13561356
if self.sign_aware_zero_pad() {
13571357
// a sign always goes first
1358+
// SAFETY: formatted.sign is always generated from determine_sign which is
1359+
// valid utf8
13581360
let sign = unsafe { str::from_utf8_unchecked(formatted.sign) };
13591361
self.buf.write_str(sign)?;
13601362

@@ -1386,6 +1388,8 @@ impl<'a> Formatter<'a> {
13861388

13871389
fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result {
13881390
fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
1391+
// SAFETY: formatted.sign is always generated from determine_sign which is
1392+
// valid utf8
13891393
buf.write_str(unsafe { str::from_utf8_unchecked(s) })
13901394
}
13911395

src/libcore/fmt/num.rs

+37-26
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
//! Integer and floating-point number formatting
22
3-
// ignore-tidy-undocumented-unsafe
4-
5-
63
use crate::fmt;
74
use crate::ops::{Div, Rem, Sub};
85
use crate::str;
@@ -83,6 +80,7 @@ trait GenericRadix {
8380
}
8481
}
8582
let buf = &buf[curr..];
83+
// SAFETY: only chars in buf are created by Self::digit which are asuumed to be valid utf8
8684
let buf = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(
8785
MaybeUninit::first_ptr(buf),
8886
buf.len()
@@ -191,49 +189,62 @@ static DEC_DIGITS_LUT: &[u8; 200] =
191189
macro_rules! impl_Display {
192190
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
193191
fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192+
// 2^128 is is about 3*10^38, so 39 gives an extra byte of space
194193
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
195194
let mut curr = buf.len() as isize;
196195
let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf);
197196
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
198197

199-
unsafe {
200-
// need at least 16 bits for the 4-characters-at-a-time to work.
201-
assert!(crate::mem::size_of::<$u>() >= 2);
198+
// need at least 16 bits for the 4-characters-at-a-time to work.
199+
assert!(crate::mem::size_of::<$u>() >= 2);
202200

203-
// eagerly decode 4 characters at a time
204-
while n >= 10000 {
205-
let rem = (n % 10000) as isize;
206-
n /= 10000;
201+
// eagerly decode 4 characters at a time
202+
while n >= 10000 {
203+
let rem = (n % 10000) as isize;
204+
n /= 10000;
207205

208-
let d1 = (rem / 100) << 1;
209-
let d2 = (rem % 100) << 1;
210-
curr -= 4;
206+
let d1 = (rem / 100) << 1;
207+
let d2 = (rem % 100) << 1;
208+
curr -= 4;
209+
// SAFETY: d1, d2 are each max 198, so buf_ptr[d1..d1 + 1] is safe to access
210+
unsafe {
211211
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
212212
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
213213
}
214+
}
214215

215-
// if we reach here numbers are <= 9999, so at most 4 chars long
216-
let mut n = n as isize; // possibly reduce 64bit math
216+
// if we reach here numbers are <= 9999, so at most 4 chars long
217+
let mut n = n as isize; // possibly reduce 64bit math
217218

218-
// decode 2 more chars, if > 2 chars
219-
if n >= 100 {
220-
let d1 = (n % 100) << 1;
221-
n /= 100;
222-
curr -= 2;
219+
// decode 2 more chars, if > 2 chars
220+
if n >= 100 {
221+
let d1 = (n % 100) << 1;
222+
n /= 100;
223+
curr -= 2;
224+
// SAFETY: d1 is max 198, so buf_ptr[d1..d1 + 1] is safe to access
225+
unsafe {
223226
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
224227
}
228+
}
225229

226-
// decode last 1 or 2 chars
227-
if n < 10 {
228-
curr -= 1;
230+
// decode last 1 or 2 chars
231+
if n < 10 {
232+
curr -= 1;
233+
// SAFETY: curr is still less than buf.len() and since n < 10, n + '0' is valid utf8
234+
unsafe {
229235
*buf_ptr.offset(curr) = (n as u8) + b'0';
230-
} else {
231-
let d1 = n << 1;
232-
curr -= 2;
236+
}
237+
} else {
238+
let d1 = n << 1;
239+
curr -= 2;
240+
// SAFETY: d1 is max 18, so buf_ptr[d1..d1 + 1] is safe to access
241+
unsafe {
233242
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
234243
}
235244
}
236245

246+
// SAFETY: curr > 0 (since we made buf large enough), and all the chars are valid utf8
247+
// since DEC_DIGITS_LUT is
237248
let buf_slice = unsafe {
238249
str::from_utf8_unchecked(
239250
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))

0 commit comments

Comments
 (0)