From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- third_party/rust/safemem/src/lib.rs | 143 ++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 third_party/rust/safemem/src/lib.rs (limited to 'third_party/rust/safemem/src/lib.rs') diff --git a/third_party/rust/safemem/src/lib.rs b/third_party/rust/safemem/src/lib.rs new file mode 100644 index 0000000000..a30c933906 --- /dev/null +++ b/third_party/rust/safemem/src/lib.rs @@ -0,0 +1,143 @@ +//! Safe wrappers for memory-accessing functions like `std::ptr::copy()`. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate core as std; +use std::ptr; + +macro_rules! idx_check ( + ($slice:expr, $idx:expr) => { + assert!($idx < $slice.len(), + concat!("`", stringify!($idx), "` ({}) out of bounds. Length: {}"), + $idx, $slice.len()); + } +); + +macro_rules! len_check ( + ($slice:expr, $start:ident, $len:ident) => { + assert!( + $start.checked_add($len) + .expect(concat!("Overflow evaluating ", stringify!($start + $len))) + <= $slice.len(), + "Length {} starting at {} is out of bounds (slice len {}).", $len, $start, $slice.len() + ) + } +); + +/// Copy `len` elements from `src_idx` to `dest_idx`. Ranges may overlap. +/// +/// Safe wrapper for `memmove()`/`std::ptr::copy()`. +/// +/// ###Panics +/// * If either `src_idx` or `dest_idx` are out of bounds, or if either of these plus `len` is out of +/// bounds. +/// * If `src_idx + len` or `dest_idx + len` overflows. +pub fn copy_over(slice: &mut [T], src_idx: usize, dest_idx: usize, len: usize) { + if slice.len() == 0 { return; } + + idx_check!(slice, src_idx); + idx_check!(slice, dest_idx); + len_check!(slice, src_idx, len); + len_check!(slice, dest_idx, len); + + // At any point a Rust reference exists, the compiler is free to do this. + // So we explicitely add it to be caught by miri. + #[cfg(miri)] + slice.iter().copied().for_each(drop); + + let ptr = slice.as_mut_ptr(); + + unsafe { + ptr::copy(ptr.offset(src_idx as isize), ptr.offset(dest_idx as isize), len); + } +} + +/// Safe wrapper for `std::ptr::write_bytes()`/`memset()`. +pub fn write_bytes(slice: &mut [u8], byte: u8) { + unsafe { + ptr::write_bytes(slice.as_mut_ptr(), byte, slice.len()); + } +} + +/// Prepend `elems` to `vec`, resizing if necessary. +/// +/// ### Panics +/// +/// If `vec.len() + elems.len()` overflows. +#[cfg(feature = "std")] +pub fn prepend(elems: &[T], vec: &mut Vec) { + let elems_len = elems.len(); // `<= isize::MAX as usize` + if elems_len == 0 { return; } + + let old_len = vec.len(); // `<= isize::MAX as usize` + if old_len == 0 { + // Prepend = append: delegate to Rust's stdlib implementation. + vec.extend_from_slice(elems); + } else { + // Our overflow check occurs here, no need to do it ourselves. + vec.reserve(elems_len); + let ptr = vec.as_mut_ptr(); + unsafe { + // Move the old elements down to the end. + ptr::copy( + ptr, + ptr.offset(elems_len as isize), + old_len, + ); + // Copy the input elements to the start + ptr::copy_nonoverlapping( + elems.as_ptr(), + ptr, + elems_len, + ); + // Set the len *after* having initialized the elements. + vec.set_len(old_len + elems_len); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[should_panic] + fn bounds_check() { + let mut arr = [0i32, 1, 2, 3, 4, 5]; + + copy_over(&mut arr, 2, 1, 7); + } + + #[test] + fn copy_empty() { + let mut arr: [i32; 0] = []; + + copy_over(&mut arr, 0, 0, 0); + } + + #[test] + #[cfg(feature = "std")] + fn prepend_empty() { + let mut vec: Vec = vec![]; + prepend(&[1, 2, 3], &mut vec); + } + + #[test] + #[cfg(feature = "std")] + fn prepend_i32() { + let mut vec = vec![3, 4, 5]; + prepend(&[1, 2], &mut vec); + assert_eq!(vec, &[1, 2, 3, 4, 5]); + } + + /// Detect potential uninit values when running miri + #[test] + #[cfg(all( + feature = "std", + miri, + ))] + fn prepend_bool() { + prepend(&[true], &mut vec![false]); + } +} -- cgit v1.2.3