11//! Integer and floating-point number formatting
22
3- // ignore-tidy-undocumented-unsafe
4-
53use crate :: fmt;
64use crate :: mem:: MaybeUninit ;
75use crate :: num:: flt2dec;
@@ -84,6 +82,8 @@ trait GenericRadix {
8482 }
8583 }
8684 let buf = & buf[ curr..] ;
85+ // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be
86+ // valid UTF-8
8787 let buf = unsafe {
8888 str:: from_utf8_unchecked ( slice:: from_raw_parts ( MaybeUninit :: first_ptr ( buf) , buf. len ( ) ) )
8989 } ;
@@ -189,11 +189,19 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\
189189macro_rules! impl_Display {
190190 ( $( $t: ident) ,* as $u: ident via $conv_fn: ident named $name: ident) => {
191191 fn $name( mut n: $u, is_nonnegative: bool , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
192+ // 2^128 is about 3*10^38, so 39 gives an extra byte of space
192193 let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 39 ] ;
193194 let mut curr = buf. len( ) as isize ;
194195 let buf_ptr = MaybeUninit :: first_ptr_mut( & mut buf) ;
195196 let lut_ptr = DEC_DIGITS_LUT . as_ptr( ) ;
196197
198+ // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we
199+ // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show
200+ // that it's OK to copy into `buf_ptr`, notice that at the beginning
201+ // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
202+ // each step this is kept the same as `n` is divided. Since `n` is always
203+ // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
204+ // is safe to access.
197205 unsafe {
198206 // need at least 16 bits for the 4-characters-at-a-time to work.
199207 assert!( crate :: mem:: size_of:: <$u>( ) >= 2 ) ;
@@ -206,6 +214,10 @@ macro_rules! impl_Display {
206214 let d1 = ( rem / 100 ) << 1 ;
207215 let d2 = ( rem % 100 ) << 1 ;
208216 curr -= 4 ;
217+
218+ // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
219+ // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
220+ // which is `10^40 > 2^128 > n`.
209221 ptr:: copy_nonoverlapping( lut_ptr. offset( d1) , buf_ptr. offset( curr) , 2 ) ;
210222 ptr:: copy_nonoverlapping( lut_ptr. offset( d2) , buf_ptr. offset( curr + 2 ) , 2 ) ;
211223 }
@@ -232,6 +244,8 @@ macro_rules! impl_Display {
232244 }
233245 }
234246
247+ // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
248+ // UTF-8 since `DEC_DIGITS_LUT` is
235249 let buf_slice = unsafe {
236250 str :: from_utf8_unchecked(
237251 slice:: from_raw_parts( buf_ptr. offset( curr) , buf. len( ) - curr as usize ) )
@@ -304,6 +318,8 @@ macro_rules! impl_Exp {
304318 } ;
305319
306320 // 39 digits (worst case u128) + . = 40
321+ // Since `curr` always decreases by the number of digits copied, this means
322+ // that `curr >= 0`.
307323 let mut buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 40 ] ;
308324 let mut curr = buf. len( ) as isize ; //index for buf
309325 let buf_ptr = MaybeUninit :: first_ptr_mut( & mut buf) ;
@@ -313,6 +329,8 @@ macro_rules! impl_Exp {
313329 while n >= 100 {
314330 let d1 = ( ( n % 100 ) as isize ) << 1 ;
315331 curr -= 2 ;
332+ // SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since
333+ // `DEC_DIGITS_LUT` has a length of 200.
316334 unsafe {
317335 ptr:: copy_nonoverlapping( lut_ptr. offset( d1) , buf_ptr. offset( curr) , 2 ) ;
318336 }
@@ -324,6 +342,7 @@ macro_rules! impl_Exp {
324342 // decode second-to-last character
325343 if n >= 10 {
326344 curr -= 1 ;
345+ // SAFETY: Safe since `40 > curr >= 0` (see comment)
327346 unsafe {
328347 * buf_ptr. offset( curr) = ( n as u8 % 10_u8 ) + b'0' ;
329348 }
@@ -333,11 +352,13 @@ macro_rules! impl_Exp {
333352 // add decimal point iff >1 mantissa digit will be printed
334353 if exponent != trailing_zeros || added_precision != 0 {
335354 curr -= 1 ;
355+ // SAFETY: Safe since `40 > curr >= 0`
336356 unsafe {
337357 * buf_ptr. offset( curr) = b'.' ;
338358 }
339359 }
340360
361+ // SAFETY: Safe since `40 > curr >= 0`
341362 let buf_slice = unsafe {
342363 // decode last character
343364 curr -= 1 ;
@@ -350,6 +371,8 @@ macro_rules! impl_Exp {
350371 // stores 'e' (or 'E') and the up to 2-digit exponent
351372 let mut exp_buf = [ MaybeUninit :: <u8 >:: uninit( ) ; 3 ] ;
352373 let exp_ptr = MaybeUninit :: first_ptr_mut( & mut exp_buf) ;
374+ // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]`
375+ // is contained within `exp_buf` since `len <= 3`.
353376 let exp_slice = unsafe {
354377 * exp_ptr. offset( 0 ) = if upper { b'E' } else { b'e' } ;
355378 let len = if exponent < 10 {
0 commit comments