Skip to content

Commit

Permalink
Fix DecInt::new panicking on integers greater than 64 bits and optimi…
Browse files Browse the repository at this point in the history
…ze out any panics in DecInt::new
  • Loading branch information
Alex Saveau committed Oct 31, 2024
1 parent 2f5261c commit 4183bb0
Showing 1 changed file with 19 additions and 11 deletions.
30 changes: 19 additions & 11 deletions src/path/dec_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -36,25 +36,33 @@ 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<u8>; 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<u8>; 40 + 1],
len: usize,
}

impl DecInt {
/// Construct a new path component from an integer.
#[inline]
pub fn new<Int: Integer>(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<u8>]>(str_buf.as_bytes())
});
buf[str_buf.len()] = MaybeUninit::new(0);
{
const _: () = assert!(mem::size_of::<Buffer>() == 40);
if str_buf.len() > mem::size_of::<Buffer>() {
// SAFETY: the largest i128 str is 40 chars long
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<u8>]>(str_buf.as_bytes())
});
buf[str_buf.len()] = MaybeUninit::new(0);
}

Self {
buf,
Expand Down Expand Up @@ -92,7 +100,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>], &[u8]>(init) }
unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(init) }
}

/// Return the raw byte buffer.
Expand Down

0 comments on commit 4183bb0

Please sign in to comment.