From 8a5052999142f26f6e6126f71d712b335714c86a Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Wed, 30 Oct 2024 23:01:40 -0400 Subject: [PATCH] Fix DecInt::new panicking on integers greater than 64 bits and optimize out any panics in DecInt::new --- src/path/dec_int.rs | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/path/dec_int.rs b/src/path/dec_int.rs index 1e9dc1a4f..21541c5c4 100644 --- a/src/path/dec_int.rs +++ b/src/path/dec_int.rs @@ -8,7 +8,7 @@ use crate::backend::fd::{AsFd, AsRawFd}; use crate::ffi::CStr; -use core::mem::MaybeUninit; +use core::mem::{self, MaybeUninit}; use itoa::{Buffer, Integer}; #[cfg(all(feature = "std", unix))] use std::os::unix::ffi::OsStrExt; @@ -36,9 +36,9 @@ use {core::fmt, std::ffi::OsStr, std::path::Path}; /// ``` #[derive(Clone)] pub struct DecInt { - // 20 `u8`s is enough to hold the decimal ASCII representation of any - // `u64`, and we add one for a NUL terminator for `as_c_str`. - buf: [MaybeUninit; 20 + 1], + // 40 `u8`s is enough to hold the decimal ASCII representation of any + // `i128`, and we add one for a NUL terminator for `as_c_str`. + buf: [MaybeUninit; 40 + 1], len: usize, } @@ -46,15 +46,22 @@ impl DecInt { /// Construct a new path component from an integer. #[inline] pub fn new(i: Int) -> Self { - let mut buf = [MaybeUninit::uninit(); 20 + 1]; + let mut buf = [MaybeUninit::uninit(); 40 + 1]; let mut str_buf = Buffer::new(); let str_buf = str_buf.format(i); - buf[..str_buf.len()].copy_from_slice(unsafe { - // SAFETY: you can always go from init to uninit - core::mem::transmute::<&[u8], &[MaybeUninit]>(str_buf.as_bytes()) - }); - buf[str_buf.len()] = MaybeUninit::new(0); + { + const _: () = assert!(mem::size_of::() == 40); + if str_buf.len() > mem::size_of::() { + unsafe { core::hint::unreachable_unchecked() } + } + + buf[..str_buf.len()].copy_from_slice(unsafe { + // SAFETY: you can always go from init to uninit + mem::transmute::<&[u8], &[MaybeUninit]>(str_buf.as_bytes()) + }); + buf[str_buf.len()] = MaybeUninit::new(0); + } Self { buf, @@ -92,7 +99,7 @@ impl DecInt { pub fn as_bytes_with_nul(&self) -> &[u8] { let init = &self.buf[..=self.len]; // SAFETY: we're guaranteed to have initialized len+1 bytes. - unsafe { core::mem::transmute::<&[MaybeUninit], &[u8]>(init) } + unsafe { mem::transmute::<&[MaybeUninit], &[u8]>(init) } } /// Return the raw byte buffer.