use std::{
borrow::Borrow,
collections::{HashMap, VecDeque},
ffi::CStr,
fmt,
hash::Hash,
marker::PhantomData,
mem::{self, MaybeUninit},
num::NonZeroUsize,
ops::{Deref, DerefMut, Index, IndexMut},
ptr,
ptr::NonNull,
result::Result,
sync::LazyLock,
};
use ahash::HashMapExt;
use libc::c_void;
use libseccomp::ScmpSyscall;
use nix::{
errno::Errno,
sys::{
mman::{mmap_anonymous, mprotect, munmap, MapFlags, ProtFlags},
prctl::set_vma_anon_name,
},
unistd::{sysconf, SysconfVar},
};
use crate::{
config::HAVE_MADV_GUARD,
hash::{SydHashMap, SydIndexMap, SydRandomState},
};
static SYS_MSEAL: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
ScmpSyscall::from_name("mseal")
.map(i32::from)
.map(libc::c_long::from)
.ok()
});
pub fn check_mseal_support() -> bool {
let num = if let Some(num) = *SYS_MSEAL {
num
} else {
return false;
};
Errno::result(unsafe { libc::syscall(num, 0, 0, 0) }).is_ok()
}
pub fn check_madvise_guard_support() -> bool {
*HAVE_MADV_GUARD
}
pub fn mseal(addr: NonNull<c_void>, len: NonZeroUsize) -> Result<(), Errno> {
let num = SYS_MSEAL.ok_or(Errno::ENOSYS)?;
Errno::result(unsafe { libc::syscall(num, addr, len.get(), 0) }).map(drop)
}
pub fn mprotect_none(addr: NonNull<c_void>, len: NonZeroUsize) -> Result<(), Errno> {
unsafe { mprotect(addr, len.get(), ProtFlags::PROT_NONE) }
}
pub fn mprotect_readonly(addr: NonNull<c_void>, len: NonZeroUsize) -> Result<(), Errno> {
unsafe { mprotect(addr, len.get(), ProtFlags::PROT_READ) }
}
const MADV_GUARD_INSTALL: i32 = 102;
const MADV_GUARD_REMOVE: i32 = 103;
pub fn madvise_guard_install(addr: NonNull<c_void>, len: NonZeroUsize) -> Result<(), Errno> {
Errno::result(unsafe { libc::madvise(addr.as_ptr(), len.get(), MADV_GUARD_INSTALL) }).map(drop)
}
pub fn madvise_guard_remove(addr: NonNull<c_void>, len: NonZeroUsize) -> Result<(), Errno> {
Errno::result(unsafe { libc::madvise(addr.as_ptr(), len.get(), MADV_GUARD_REMOVE) }).map(drop)
}
#[derive(Debug)]
pub struct SealBox<T> {
map_ptr: NonNull<c_void>,
map_len: NonZeroUsize,
map_nul: bool, _marker: PhantomData<T>,
}
impl<T> SealBox<T> {
pub fn new(data: T) -> Result<Self, Errno> {
#[expect(clippy::cast_possible_truncation)]
#[expect(clippy::cast_sign_loss)]
let page = sysconf(SysconfVar::PAGE_SIZE)?.ok_or(Errno::EINVAL)? as usize;
let size = mem::size_of::<T>();
let (map_len, map_prot) = if size == 0 {
(page, ProtFlags::PROT_NONE)
} else {
let map_len = size.checked_next_multiple_of(page).ok_or(Errno::EINVAL)?;
(map_len, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE)
};
let map_len = NonZeroUsize::new(map_len).ok_or(Errno::EINVAL)?;
let map_ptr = unsafe { mmap_anonymous(None, map_len, map_prot, MapFlags::MAP_PRIVATE)? };
if size != 0 {
unsafe {
let dst = map_ptr.cast::<T>().as_ptr();
ptr::write(dst, data);
}
}
Ok(SealBox {
map_ptr,
map_len,
map_nul: size == 0,
_marker: PhantomData,
})
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<Sealed<T>, Errno> {
if !self.map_nul {
mprotect_readonly(self.map_ptr, self.map_len)?;
} else if check_madvise_guard_support() {
madvise_guard_install(self.map_ptr, self.map_len)?;
}
if vma_name.is_some() {
let _ = set_vma_anon_name(self.map_ptr, self.map_len, vma_name);
}
match mseal(self.map_ptr, self.map_len) {
Ok(_) | Err(Errno::EPERM | Errno::ENOSYS) => {}
Err(errno) => return Err(errno),
}
let ptr = self.map_ptr.as_ptr().cast::<T>();
let sealed = Sealed {
ptr,
map_ptr: self.map_ptr,
map_len: self.map_len,
};
mem::forget(self);
Ok(sealed)
}
pub fn as_mut_ptr(&self) -> *mut T {
self.map_ptr.as_ptr().cast::<T>()
}
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.map_ptr.as_ptr().cast::<T>() }
}
pub fn seal_value(data: T, vma_name: Option<&CStr>) -> Result<Sealed<T>, Errno> {
Self::new(data)?.seal(vma_name)
}
}
impl<T> SealBox<MaybeUninit<T>> {
pub fn new_uninit() -> Result<Self, Errno> {
#[expect(clippy::cast_possible_truncation)]
#[expect(clippy::cast_sign_loss)]
let page = sysconf(SysconfVar::PAGE_SIZE)?.ok_or(Errno::EINVAL)? as usize;
let size = mem::size_of::<T>();
let (map_len, map_prot) = if size == 0 {
(page, ProtFlags::PROT_NONE)
} else {
let map_len = size.checked_next_multiple_of(page).ok_or(Errno::EINVAL)?;
(map_len, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE)
};
let map_len = NonZeroUsize::new(map_len).ok_or(Errno::EINVAL)?;
let map_ptr = unsafe { mmap_anonymous(None, map_len, map_prot, MapFlags::MAP_PRIVATE)? };
Ok(SealBox {
map_ptr,
map_len,
map_nul: size == 0,
_marker: PhantomData,
})
}
pub fn write(&mut self, value: T) {
unsafe { ptr::write(self.map_ptr.as_ptr().cast::<T>(), value) }
}
pub unsafe fn assume_init(self) -> SealBox<T> {
let map_ptr = self.map_ptr;
let map_len = self.map_len;
let map_nul = self.map_nul;
mem::forget(self);
SealBox {
map_ptr,
map_len,
map_nul,
_marker: PhantomData,
}
}
}
impl<T> Deref for SealBox<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.map_ptr.as_ptr().cast::<T>() }
}
}
impl<T> Drop for SealBox<T> {
fn drop(&mut self) {
let _ = unsafe { munmap(self.map_ptr, self.map_len.get()) };
}
}
pub struct Sealed<T> {
ptr: *const T,
map_ptr: NonNull<c_void>,
map_len: NonZeroUsize,
}
impl<T> Sealed<T> {
pub fn as_ptr(&self) -> *const T {
self.ptr
}
pub fn mapping(&self) -> (NonNull<c_void>, NonZeroUsize) {
(self.map_ptr, self.map_len)
}
}
impl<T> Deref for Sealed<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.ptr }
}
}
#[derive(Debug)]
pub struct SealBoxSlice<E> {
map_ptr: NonNull<c_void>,
map_len: NonZeroUsize,
len: usize,
_marker: PhantomData<E>,
}
impl<E> SealBoxSlice<E> {
pub fn from_slice(slice: &[E]) -> Result<Self, Errno>
where
E: Clone,
{
let len = slice.len();
#[expect(clippy::cast_possible_truncation)]
#[expect(clippy::cast_sign_loss)]
let page = sysconf(SysconfVar::PAGE_SIZE)?.ok_or(Errno::EINVAL)? as usize;
if len == 0 {
let map_len = NonZeroUsize::new(page).ok_or(Errno::EINVAL)?;
let map_ptr = unsafe {
mmap_anonymous(None, map_len, ProtFlags::PROT_NONE, MapFlags::MAP_PRIVATE)
}?;
return Ok(SealBoxSlice {
map_ptr,
map_len,
len: 0,
_marker: PhantomData,
});
}
let elem_size = mem::size_of::<E>();
if elem_size == 0 {
return Err(Errno::EINVAL);
}
let data_size = elem_size.checked_mul(len).ok_or(Errno::EINVAL)?;
let map_len = data_size
.checked_next_multiple_of(page)
.ok_or(Errno::EINVAL)?;
let map_len = NonZeroUsize::new(map_len).ok_or(Errno::EINVAL)?;
let map_ptr = unsafe {
mmap_anonymous(
None,
map_len,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE,
)?
};
let dst = map_ptr.cast::<E>().as_ptr();
for (idx, item) in slice.iter().enumerate() {
unsafe { ptr::write(dst.add(idx), item.clone()) };
}
Ok(SealBoxSlice {
map_ptr,
map_len,
len,
_marker: PhantomData,
})
}
pub fn new_deque(mut deque: VecDeque<E>) -> Result<Self, Errno>
where
E: Clone,
{
Self::from_slice(deque.make_contiguous())
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<E>, Errno> {
if self.len > 0 {
mprotect_readonly(self.map_ptr, self.map_len)?;
} else if check_madvise_guard_support() {
madvise_guard_install(self.map_ptr, self.map_len)?;
}
if vma_name.is_some() {
let _ = set_vma_anon_name(self.map_ptr, self.map_len, vma_name);
}
match mseal(self.map_ptr, self.map_len) {
Ok(_) | Err(Errno::EPERM | Errno::ENOSYS) => {}
Err(errno) => return Err(errno),
}
let ptr = self.map_ptr.as_ptr().cast::<E>();
let sealed = SealedSlice {
ptr,
len: self.len,
map_ptr: self.map_ptr,
map_len: self.map_len,
};
mem::forget(self);
Ok(sealed)
}
}
impl<E> Drop for SealBoxSlice<E> {
fn drop(&mut self) {
let _ = unsafe { munmap(self.map_ptr, self.map_len.get()) };
}
}
pub struct SealedSlice<E> {
ptr: *const E,
len: usize,
map_ptr: NonNull<c_void>,
map_len: NonZeroUsize,
}
impl<E> SealedSlice<E> {
pub fn as_ptr(&self) -> *const E {
self.ptr
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn mapping(&self) -> (NonNull<c_void>, NonZeroUsize) {
(self.map_ptr, self.map_len)
}
}
impl<E> Deref for SealedSlice<E> {
type Target = [E];
fn deref(&self) -> &[E] {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl<K: Ord, V> SealBoxSlice<(K, V)> {
pub fn from_hashmap(map: HashMap<K, V>) -> Result<Self, Errno>
where
K: Clone,
V: Clone,
{
let mut vec: Vec<(K, V)> = map.into_iter().collect();
vec.sort_by(|a, b| a.0.cmp(&b.0));
Self::from_slice(&vec)
}
pub fn from_sydhashmap(map: SydHashMap<K, V>) -> Result<Self, Errno>
where
K: Clone,
V: Clone,
{
let mut vec: Vec<(K, V)> = map.into_iter().collect();
vec.sort_by(|a, b| a.0.cmp(&b.0));
Self::from_slice(&vec)
}
pub fn from_sydindexmap(map: SydIndexMap<K, V>) -> Result<Self, Errno>
where
K: Clone,
V: Clone,
{
let mut vec: Vec<(K, V)> = map.into_iter().collect();
vec.sort_by(|a, b| a.0.cmp(&b.0));
Self::from_slice(&vec)
}
}
pub trait SealableValue: Sized {
type Out;
fn seal(self, vma_name: Option<&CStr>) -> Result<Self::Out, Errno>;
}
impl<T> SealableValue for T {
type Out = Sealed<T>;
fn seal(self, vma_name: Option<&CStr>) -> Result<Self::Out, Errno> {
SealBox::new(self)?.seal(vma_name)
}
}
pub trait SealableSlice<E> {
fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<E>, Errno>
where
E: Clone;
}
impl<E> SealableSlice<E> for Vec<E> {
fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<E>, Errno>
where
E: Clone,
{
SealBoxSlice::from_slice(&self)?.seal(vma_name)
}
}
impl<E> SealableSlice<E> for VecDeque<E> {
fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<E>, Errno>
where
E: Clone,
{
SealBoxSlice::new_deque(self)?.seal(vma_name)
}
}
impl<K: Ord + Clone, V: Clone> SealableSlice<(K, V)> for HashMap<K, V> {
fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<(K, V)>, Errno> {
SealBoxSlice::from_hashmap(self)?.seal(vma_name)
}
}
impl<K: Hash + Eq + Ord + Clone, V: Clone> SealableSlice<(K, V)> for SydHashMap<K, V> {
fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<(K, V)>, Errno> {
SealBoxSlice::from_sydhashmap(self)?.seal(vma_name)
}
}
impl<K: Hash + Eq + Ord + Clone, V: Clone> SealableSlice<(K, V)> for SydIndexMap<K, V> {
fn seal(self, vma_name: Option<&CStr>) -> Result<SealedSlice<(K, V)>, Errno> {
SealBoxSlice::from_sydindexmap(self)?.seal(vma_name)
}
}
pub enum Sealable<T: Copy> {
Unsealed(T),
Sealed(Sealed<T>),
}
impl<T: Copy> Sealable<T> {
pub fn new(val: T) -> Self {
Sealable::Unsealed(val)
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<Self, Errno> {
match self {
Sealable::Unsealed(v) => {
let sealed = SealBox::new(v)?.seal(vma_name)?;
Ok(Sealable::Sealed(sealed))
}
Sealable::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn get(&self) -> &T {
match self {
Sealable::Unsealed(v) => v,
Sealable::Sealed(s) => s,
}
}
}
impl<T: Copy> Deref for Sealable<T> {
type Target = T;
fn deref(&self) -> &T {
self.get()
}
}
impl<T: Copy> DerefMut for Sealable<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Sealable::Unsealed(v) => v,
Sealable::Sealed(_) => panic!("cannot mutably borrow a sealable"),
}
}
}
impl<T: Copy + fmt::Debug> fmt::Debug for Sealable<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Sealable").field(self.get()).finish()
}
}
impl<T: Copy + PartialEq> PartialEq for Sealable<T> {
fn eq(&self, other: &Self) -> bool {
*self.get() == *other.get()
}
}
impl<T: Copy + Eq> Eq for Sealable<T> {}
impl<T: Copy + Default> Default for Sealable<T> {
fn default() -> Self {
Sealable::Unsealed(T::default())
}
}
pub enum SealableVec<T> {
Unsealed(Vec<T>),
Sealed(SealedSlice<T>),
}
impl<T> SealableVec<T> {
pub fn new(vec: Vec<T>) -> Self {
SealableVec::Unsealed(vec)
}
pub fn with_capacity(cap: usize) -> Self {
SealableVec::Unsealed(Vec::with_capacity(cap))
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<SealableVec<T>, Errno>
where
T: Clone,
{
match self {
SealableVec::Unsealed(v) => {
let sealed = SealBoxSlice::from_slice(&v)?.seal(vma_name)?;
Ok(SealableVec::Sealed(sealed))
}
_ => Err(Errno::EPERM),
}
}
pub fn len(&self) -> usize {
match self {
SealableVec::Unsealed(v) => v.len(),
SealableVec::Sealed(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
match self {
SealableVec::Unsealed(v) => v.capacity(),
SealableVec::Sealed(s) => s.len(),
}
}
pub fn get(&self, idx: usize) -> Option<&T> {
match self {
SealableVec::Unsealed(v) => v.get(idx),
SealableVec::Sealed(s) => s.get(idx),
}
}
pub fn first(&self) -> Option<&T> {
self.get(0)
}
pub fn last(&self) -> Option<&T> {
self.get(self.len().checked_sub(1)?)
}
pub fn contains<U>(&self, x: &U) -> bool
where
T: PartialEq<U>,
{
self.iter().any(|e| e == x)
}
pub fn position<P>(&self, predicate: P) -> Option<usize>
where
P: FnMut(&T) -> bool,
{
self.iter().position(predicate)
}
pub fn iter(&self) -> std::slice::Iter<'_, T> {
match self {
SealableVec::Unsealed(v) => v.iter(),
SealableVec::Sealed(s) => s.iter(),
}
}
pub fn as_slice(&self) -> &[T] {
self
}
pub fn push(&mut self, value: T) -> Result<(), Errno> {
match self {
SealableVec::Unsealed(v) => {
v.push(value);
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn pop(&mut self) -> Option<T> {
match self {
SealableVec::Unsealed(v) => v.pop(),
SealableVec::Sealed(_) => None,
}
}
pub fn insert(&mut self, index: usize, element: T) -> Result<(), Errno> {
match self {
SealableVec::Unsealed(v) => {
v.insert(index, element);
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn remove(&mut self, index: usize) -> Option<T> {
match self {
SealableVec::Unsealed(v) => Some(v.remove(index)),
SealableVec::Sealed(_) => None,
}
}
pub fn clear(&mut self) {
if let SealableVec::Unsealed(v) = self {
v.clear();
}
}
pub fn reserve(&mut self, additional: usize) -> Result<(), Errno> {
match self {
SealableVec::Unsealed(v) => {
v.reserve(additional);
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn shrink_to_fit(&mut self) -> Result<(), Errno> {
match self {
SealableVec::Unsealed(v) => {
v.shrink_to_fit();
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn append(&mut self, other: &mut Vec<T>) -> Result<(), Errno> {
match self {
SealableVec::Unsealed(v) => {
v.append(other);
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn split_off(&mut self, at: usize) -> Result<Vec<T>, Errno> {
match self {
SealableVec::Unsealed(v) => Ok(v.split_off(at)),
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn retain<F>(&mut self, f: F) -> Result<(), Errno>
where
F: FnMut(&T) -> bool,
{
match self {
SealableVec::Unsealed(v) => {
v.retain(f);
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) -> Result<(), Errno> {
match self {
SealableVec::Unsealed(v) => {
v.extend(iter);
Ok(())
}
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn drain<R>(&mut self, range: R) -> Result<std::vec::Drain<'_, T>, Errno>
where
R: std::ops::RangeBounds<usize>,
{
match self {
SealableVec::Unsealed(v) => Ok(v.drain(range)),
SealableVec::Sealed(_) => Err(Errno::EPERM),
}
}
}
impl<T> Deref for SealableVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
match self {
SealableVec::Unsealed(v) => v.as_slice(),
SealableVec::Sealed(s) => s.deref(),
}
}
}
impl<T> DerefMut for SealableVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
SealableVec::Unsealed(v) => v.as_mut_slice(),
SealableVec::Sealed(_) => panic!("cannot mutably borrow a sealed Vec"),
}
}
}
impl<T> Index<usize> for SealableVec<T> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.deref()[i]
}
}
impl<T> IndexMut<usize> for SealableVec<T> {
fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.deref_mut()[i]
}
}
impl<T: PartialEq> PartialEq for SealableVec<T> {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<T: Eq> Eq for SealableVec<T> {}
impl<T> Default for SealableVec<T> {
fn default() -> Self {
SealableVec::Unsealed(Vec::new())
}
}
impl<T: fmt::Debug> fmt::Debug for SealableVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T> From<Vec<T>> for SealableVec<T> {
fn from(v: Vec<T>) -> Self {
SealableVec::Unsealed(v)
}
}
pub enum SealableVecDeque<T> {
Unsealed(VecDeque<T>),
Sealed(SealedSlice<T>),
}
impl<T> SealableVecDeque<T> {
pub fn new(dq: VecDeque<T>) -> Self {
SealableVecDeque::Unsealed(dq)
}
pub fn with_capacity(cap: usize) -> Self {
SealableVecDeque::Unsealed(VecDeque::with_capacity(cap))
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<SealableVecDeque<T>, Errno>
where
T: Clone,
{
match self {
SealableVecDeque::Unsealed(dq) => {
let sealed = SealBoxSlice::new_deque(dq)?.seal(vma_name)?;
Ok(SealableVecDeque::Sealed(sealed))
}
_ => Err(Errno::EPERM),
}
}
pub fn len(&self) -> usize {
match self {
SealableVecDeque::Unsealed(dq) => dq.len(),
SealableVecDeque::Sealed(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity(&self) -> usize {
match self {
SealableVecDeque::Unsealed(dq) => dq.capacity(),
SealableVecDeque::Sealed(s) => s.len(),
}
}
pub fn get(&self, idx: usize) -> Option<&T> {
match self {
SealableVecDeque::Unsealed(dq) => dq.get(idx),
SealableVecDeque::Sealed(s) => s.get(idx),
}
}
pub fn front(&self) -> Option<&T> {
self.get(0)
}
pub fn back(&self) -> Option<&T> {
self.get(self.len().checked_sub(1)?)
}
pub fn contains<U>(&self, x: &U) -> bool
where
T: PartialEq<U>,
{
self.iter().any(|e| e == x)
}
pub fn iter(&self) -> std::iter::Chain<std::slice::Iter<'_, T>, std::slice::Iter<'_, T>> {
match self {
SealableVecDeque::Unsealed(dq) => {
let (head, tail) = dq.as_slices();
head.iter().chain(tail.iter())
}
SealableVecDeque::Sealed(s) => s.iter().chain([].iter()),
}
}
pub fn as_slices(&self) -> (&[T], &[T]) {
match self {
SealableVecDeque::Unsealed(dq) => dq.as_slices(),
SealableVecDeque::Sealed(s) => (s.deref(), &[]),
}
}
pub fn push_back(&mut self, elem: T) -> Result<(), Errno> {
match self {
SealableVecDeque::Unsealed(dq) => {
dq.push_back(elem);
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn push_front(&mut self, elem: T) -> Result<(), Errno> {
match self {
SealableVecDeque::Unsealed(dq) => {
dq.push_front(elem);
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn pop_back(&mut self) -> Option<T> {
match self {
SealableVecDeque::Unsealed(dq) => dq.pop_back(),
SealableVecDeque::Sealed(_) => None,
}
}
pub fn pop_front(&mut self) -> Option<T> {
match self {
SealableVecDeque::Unsealed(dq) => dq.pop_front(),
SealableVecDeque::Sealed(_) => None,
}
}
pub fn remove(&mut self, index: usize) -> Option<T> {
match self {
SealableVecDeque::Unsealed(v) => v.remove(index),
SealableVecDeque::Sealed(_) => None,
}
}
pub fn clear(&mut self) {
if let SealableVecDeque::Unsealed(dq) = self {
dq.clear();
}
}
pub fn reserve(&mut self, additional: usize) -> Result<(), Errno> {
match self {
SealableVecDeque::Unsealed(dq) => {
dq.reserve(additional);
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn make_contiguous(&mut self) -> Result<(), Errno> {
match self {
SealableVecDeque::Unsealed(dq) => {
dq.make_contiguous();
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn shrink_to_fit(&mut self) -> Result<(), Errno> {
match self {
SealableVecDeque::Unsealed(dq) => {
dq.shrink_to_fit();
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn retain<F>(&mut self, f: F) -> Result<(), Errno>
where
F: FnMut(&T) -> bool,
{
match self {
SealableVecDeque::Unsealed(v) => {
v.retain(f);
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) -> Result<(), Errno> {
match self {
SealableVecDeque::Unsealed(v) => {
v.extend(iter);
Ok(())
}
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn drain<R>(&mut self, range: R) -> Result<std::collections::vec_deque::Drain<'_, T>, Errno>
where
R: std::ops::RangeBounds<usize>,
{
match self {
SealableVecDeque::Unsealed(v) => Ok(v.drain(range)),
SealableVecDeque::Sealed(_) => Err(Errno::EPERM),
}
}
}
impl<T> Deref for SealableVecDeque<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
match self {
SealableVecDeque::Unsealed(dq) => {
let (head, _) = dq.as_slices();
head
}
SealableVecDeque::Sealed(s) => s.deref(),
}
}
}
impl<T> DerefMut for SealableVecDeque<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
SealableVecDeque::Unsealed(dq) => {
let (head, _) = dq.as_mut_slices();
head
}
SealableVecDeque::Sealed(_) => panic!("cannot mutably borrow a sealed VecDeque"),
}
}
}
impl<T> Index<usize> for SealableVecDeque<T> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.deref()[i]
}
}
impl<T> IndexMut<usize> for SealableVecDeque<T> {
fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.deref_mut()[i]
}
}
impl<T: PartialEq> PartialEq for SealableVecDeque<T> {
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl<T: Eq> Eq for SealableVecDeque<T> {}
impl<T> Default for SealableVecDeque<T> {
fn default() -> Self {
SealableVecDeque::Unsealed(VecDeque::new())
}
}
impl<T: fmt::Debug> fmt::Debug for SealableVecDeque<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<T> From<VecDeque<T>> for SealableVecDeque<T> {
fn from(dq: VecDeque<T>) -> Self {
SealableVecDeque::Unsealed(dq)
}
}
impl<'a, T> IntoIterator for &'a SealableVec<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a SealableVecDeque<T> {
type Item = &'a T;
type IntoIter = std::iter::Chain<std::slice::Iter<'a, T>, std::slice::Iter<'a, T>>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub enum SealableHashMap<K, V> {
Unsealed(HashMap<K, V>),
Sealed(SealedSlice<(K, V)>),
}
impl<K, V> SealableHashMap<K, V> {
pub fn new(map: HashMap<K, V>) -> Self {
SealableHashMap::Unsealed(map)
}
pub fn with_capacity(cap: usize) -> Self {
SealableHashMap::Unsealed(HashMap::with_capacity(cap))
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<Self, Errno>
where
K: Ord + Clone,
V: Clone,
{
match self {
SealableHashMap::Unsealed(map) => {
let sealed = SealBoxSlice::from_hashmap(map)?.seal(vma_name)?;
Ok(SealableHashMap::Sealed(sealed))
}
SealableHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn len(&self) -> usize {
match self {
SealableHashMap::Unsealed(m) => m.len(),
SealableHashMap::Sealed(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q> + Ord + Eq + Hash,
Q: Ord + Eq + Hash + ?Sized,
{
match self {
SealableHashMap::Unsealed(m) => m.get(key),
SealableHashMap::Sealed(s) => s
.binary_search_by(|(k, _)| k.borrow().cmp(key))
.ok()
.map(|idx| &s[idx].1),
}
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord + Eq + Hash,
Q: Ord + Eq + Hash + ?Sized,
{
self.get(key).is_some()
}
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, Errno>
where
K: Eq + Hash,
{
match self {
SealableHashMap::Unsealed(m) => Ok(m.insert(key, value)),
SealableHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q> + Eq + Hash,
Q: Eq + Hash + ?Sized,
{
match self {
SealableHashMap::Unsealed(m) => m.remove(key),
SealableHashMap::Sealed(_) => None,
}
}
pub fn clear(&mut self) {
if let SealableHashMap::Unsealed(m) = self {
m.clear();
}
}
pub fn reserve(&mut self, additional: usize) -> Result<(), Errno>
where
K: Eq + Hash,
{
match self {
SealableHashMap::Unsealed(m) => {
m.reserve(additional);
Ok(())
}
SealableHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn capacity(&self) -> usize {
match self {
SealableHashMap::Unsealed(m) => m.capacity(),
SealableHashMap::Sealed(s) => s.len(),
}
}
pub fn retain<F>(&mut self, f: F) -> Result<(), Errno>
where
F: FnMut(&K, &mut V) -> bool,
{
match self {
SealableHashMap::Unsealed(m) => {
m.retain(f);
Ok(())
}
SealableHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
}
impl<K, V> Default for SealableHashMap<K, V> {
fn default() -> Self {
SealableHashMap::Unsealed(HashMap::new())
}
}
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SealableHashMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SealableHashMap::Unsealed(m) => m.fmt(f),
SealableHashMap::Sealed(s) => {
let mut dm = f.debug_map();
for pair in s.iter() {
dm.entry(&pair.0, &pair.1);
}
dm.finish()
}
}
}
}
impl<K: Ord + Eq + Hash, V: PartialEq> PartialEq for SealableHashMap<K, V> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
match self {
SealableHashMap::Unsealed(m) => {
for (k, v) in m {
if other.get(k) != Some(v) {
return false;
}
}
}
SealableHashMap::Sealed(s) => {
for (k, v) in s.iter() {
if other.get(k) != Some(v) {
return false;
}
}
}
}
true
}
}
impl<K: Ord + Eq + Hash, V: Eq> Eq for SealableHashMap<K, V> {}
impl<K, V> From<HashMap<K, V>> for SealableHashMap<K, V> {
fn from(m: HashMap<K, V>) -> Self {
SealableHashMap::Unsealed(m)
}
}
impl<'a, K, V> IntoIterator for &'a SealableHashMap<K, V>
where
K: Borrow<K> + fmt::Debug + Ord + Eq + Hash,
{
type Item = (&'a K, &'a V);
type IntoIter = Box<dyn Iterator<Item = (&'a K, &'a V)> + 'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
SealableHashMap::Unsealed(m) => Box::new(m.iter()),
SealableHashMap::Sealed(s) => Box::new(s.iter().map(|(k, v)| (k, v))),
}
}
}
pub enum SealableSydHashMap<K, V> {
Unsealed(SydHashMap<K, V>),
Sealed(SealedSlice<(K, V)>),
}
impl<K, V> SealableSydHashMap<K, V> {
pub fn new(map: SydHashMap<K, V>) -> Self {
SealableSydHashMap::Unsealed(map)
}
pub fn with_capacity(cap: usize) -> Self {
SealableSydHashMap::Unsealed(SydHashMap::with_capacity(cap))
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<Self, Errno>
where
K: Ord + Clone,
V: Clone,
{
match self {
SealableSydHashMap::Unsealed(map) => {
let sealed = SealBoxSlice::from_sydhashmap(map)?.seal(vma_name)?;
Ok(SealableSydHashMap::Sealed(sealed))
}
SealableSydHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn len(&self) -> usize {
match self {
SealableSydHashMap::Unsealed(m) => m.len(),
SealableSydHashMap::Sealed(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q> + Ord + Eq + Hash,
Q: Ord + Eq + Hash + ?Sized,
{
match self {
SealableSydHashMap::Unsealed(m) => m.get(key),
SealableSydHashMap::Sealed(s) => s
.binary_search_by(|(k, _)| k.borrow().cmp(key))
.ok()
.map(|idx| &s[idx].1),
}
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord + Eq + Hash,
Q: Ord + Eq + Hash + ?Sized,
{
self.get(key).is_some()
}
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, Errno>
where
K: Eq + Hash,
{
match self {
SealableSydHashMap::Unsealed(m) => Ok(m.insert(key, value)),
SealableSydHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q> + Eq + Hash,
Q: Eq + Hash + ?Sized,
{
match self {
SealableSydHashMap::Unsealed(m) => m.remove(key),
SealableSydHashMap::Sealed(_) => None,
}
}
pub fn clear(&mut self) {
if let SealableSydHashMap::Unsealed(m) = self {
m.clear();
}
}
pub fn reserve(&mut self, additional: usize) -> Result<(), Errno>
where
K: Eq + Hash,
{
match self {
SealableSydHashMap::Unsealed(m) => {
m.reserve(additional);
Ok(())
}
SealableSydHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn capacity(&self) -> usize {
match self {
SealableSydHashMap::Unsealed(m) => m.capacity(),
SealableSydHashMap::Sealed(s) => s.len(),
}
}
pub fn retain<F>(&mut self, f: F) -> Result<(), Errno>
where
F: FnMut(&K, &mut V) -> bool,
{
match self {
SealableSydHashMap::Unsealed(m) => {
m.retain(f);
Ok(())
}
SealableSydHashMap::Sealed(_) => Err(Errno::EPERM),
}
}
}
impl<K, V> Default for SealableSydHashMap<K, V> {
fn default() -> Self {
SealableSydHashMap::Unsealed(SydHashMap::new())
}
}
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SealableSydHashMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SealableSydHashMap::Unsealed(m) => m.fmt(f),
SealableSydHashMap::Sealed(s) => {
let mut dm = f.debug_map();
for pair in s.iter() {
dm.entry(&pair.0, &pair.1);
}
dm.finish()
}
}
}
}
impl<K: Ord + Eq + Hash, V: PartialEq> PartialEq for SealableSydHashMap<K, V> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
match self {
SealableSydHashMap::Unsealed(m) => {
for (k, v) in m {
if other.get(k) != Some(v) {
return false;
}
}
}
SealableSydHashMap::Sealed(s) => {
for (k, v) in s.iter() {
if other.get(k) != Some(v) {
return false;
}
}
}
}
true
}
}
impl<K: Ord + Eq + Hash, V: Eq> Eq for SealableSydHashMap<K, V> {}
impl<K, V> From<SydHashMap<K, V>> for SealableSydHashMap<K, V> {
fn from(m: SydHashMap<K, V>) -> Self {
SealableSydHashMap::Unsealed(m)
}
}
impl<'a, K, V> IntoIterator for &'a SealableSydHashMap<K, V>
where
K: Borrow<K> + fmt::Debug + Ord + Eq + Hash,
{
type Item = (&'a K, &'a V);
type IntoIter = Box<dyn Iterator<Item = (&'a K, &'a V)> + 'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
SealableSydHashMap::Unsealed(m) => Box::new(m.iter()),
SealableSydHashMap::Sealed(s) => Box::new(s.iter().map(|(k, v)| (k, v))),
}
}
}
pub enum SealableSydIndexMap<K, V> {
Unsealed(SydIndexMap<K, V>),
Sealed(SealedSlice<(K, V)>),
}
impl<K, V> SealableSydIndexMap<K, V> {
pub fn new(map: SydIndexMap<K, V>) -> Self {
SealableSydIndexMap::Unsealed(map)
}
pub fn with_capacity(cap: usize) -> Self {
SealableSydIndexMap::Unsealed(SydIndexMap::with_capacity_and_hasher(
cap,
SydRandomState::new(),
))
}
pub fn seal(self, vma_name: Option<&CStr>) -> Result<Self, Errno>
where
K: Ord + Clone,
V: Clone,
{
match self {
SealableSydIndexMap::Unsealed(map) => {
let sealed = SealBoxSlice::from_sydindexmap(map)?.seal(vma_name)?;
Ok(SealableSydIndexMap::Sealed(sealed))
}
SealableSydIndexMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn len(&self) -> usize {
match self {
SealableSydIndexMap::Unsealed(m) => m.len(),
SealableSydIndexMap::Sealed(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
K: Borrow<Q> + Ord + Eq + Hash,
Q: Ord + Eq + Hash + ?Sized,
{
match self {
SealableSydIndexMap::Unsealed(m) => m.get(key),
SealableSydIndexMap::Sealed(s) => s
.binary_search_by(|(k, _)| k.borrow().cmp(key))
.ok()
.map(|idx| &s[idx].1),
}
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
K: Borrow<Q> + Ord + Eq + Hash,
Q: Ord + Eq + Hash + ?Sized,
{
self.get(key).is_some()
}
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, Errno>
where
K: Eq + Hash,
{
match self {
SealableSydIndexMap::Unsealed(m) => Ok(m.insert(key, value)),
SealableSydIndexMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q> + Eq + Hash,
Q: Eq + Hash + ?Sized,
{
match self {
SealableSydIndexMap::Unsealed(m) => m.shift_remove(key),
SealableSydIndexMap::Sealed(_) => None,
}
}
pub fn clear(&mut self) {
if let SealableSydIndexMap::Unsealed(m) = self {
m.clear();
}
}
pub fn reserve(&mut self, additional: usize) -> Result<(), Errno>
where
K: Eq + Hash,
{
match self {
SealableSydIndexMap::Unsealed(m) => {
m.reserve(additional);
Ok(())
}
SealableSydIndexMap::Sealed(_) => Err(Errno::EPERM),
}
}
pub fn capacity(&self) -> usize {
match self {
SealableSydIndexMap::Unsealed(m) => m.capacity(),
SealableSydIndexMap::Sealed(s) => s.len(),
}
}
pub fn retain<F>(&mut self, f: F) -> Result<(), Errno>
where
F: FnMut(&K, &mut V) -> bool,
{
match self {
SealableSydIndexMap::Unsealed(m) => {
m.retain(f);
Ok(())
}
SealableSydIndexMap::Sealed(_) => Err(Errno::EPERM),
}
}
}
impl<K, V> Default for SealableSydIndexMap<K, V> {
fn default() -> Self {
SealableSydIndexMap::Unsealed(SydIndexMap::default())
}
}
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SealableSydIndexMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SealableSydIndexMap::Unsealed(m) => m.fmt(f),
SealableSydIndexMap::Sealed(s) => {
let mut dm = f.debug_map();
for pair in s.iter() {
dm.entry(&pair.0, &pair.1);
}
dm.finish()
}
}
}
}
impl<K: Ord + Eq + Hash, V: PartialEq> PartialEq for SealableSydIndexMap<K, V> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
match self {
SealableSydIndexMap::Unsealed(m) => {
for (k, v) in m {
if other.get(k) != Some(v) {
return false;
}
}
}
SealableSydIndexMap::Sealed(s) => {
for (k, v) in s.iter() {
if other.get(k) != Some(v) {
return false;
}
}
}
}
true
}
}
impl<K: Ord + Eq + Hash, V: Eq> Eq for SealableSydIndexMap<K, V> {}
impl<K, V> From<SydIndexMap<K, V>> for SealableSydIndexMap<K, V> {
fn from(m: SydIndexMap<K, V>) -> Self {
SealableSydIndexMap::Unsealed(m)
}
}
impl<'a, K, V> IntoIterator for &'a SealableSydIndexMap<K, V>
where
K: Borrow<K> + fmt::Debug + Ord + Eq + Hash,
{
type Item = (&'a K, &'a V);
type IntoIter = Box<dyn DoubleEndedIterator<Item = (&'a K, &'a V)> + 'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
SealableSydIndexMap::Unsealed(m) => Box::new(m.iter()),
SealableSydIndexMap::Sealed(s) => Box::new(s.iter().map(|(k, v)| (k, v))),
}
}
}
unsafe impl<T: Send> Send for SealBox<T> {}
unsafe impl<T: Sync> Sync for SealBox<T> {}
unsafe impl<T: Send> Send for Sealed<T> {}
unsafe impl<T: Sync> Sync for Sealed<T> {}
unsafe impl<T: Copy + Send> Send for Sealable<T> {}
unsafe impl<T: Copy + Sync> Sync for Sealable<T> {}
unsafe impl<E: Send> Send for SealBoxSlice<E> {}
unsafe impl<E: Sync> Sync for SealBoxSlice<E> {}
unsafe impl<E: Send> Send for SealedSlice<E> {}
unsafe impl<E: Sync> Sync for SealedSlice<E> {}
unsafe impl<T: Send> Send for SealableVec<T> {}
unsafe impl<T: Sync> Sync for SealableVec<T> {}
unsafe impl<T: Send> Send for SealableVecDeque<T> {}
unsafe impl<T: Sync> Sync for SealableVecDeque<T> {}
unsafe impl<K: Send, V: Send> Send for SealableHashMap<K, V> {}
unsafe impl<K: Send, V: Sync> Sync for SealableHashMap<K, V> {}
unsafe impl<K: Send, V: Send> Send for SealableSydHashMap<K, V> {}
unsafe impl<K: Send, V: Sync> Sync for SealableSydHashMap<K, V> {}
unsafe impl<K: Send, V: Send> Send for SealableSydIndexMap<K, V> {}
unsafe impl<K: Send, V: Sync> Sync for SealableSydIndexMap<K, V> {}
#[cfg(test)]
mod tests {
use nix::{
errno::Errno,
sys::{
mman::{madvise, mremap, MRemapFlags, MmapAdvise, ProtFlags},
signal::Signal,
wait::{waitpid, WaitStatus},
},
unistd::{fork, ForkResult},
};
use super::*;
fn is_sealed(ptr: NonNull<c_void>, len: NonZeroUsize) -> bool {
matches!(
unsafe { mprotect(ptr, len.get(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE) },
Err(Errno::EPERM)
)
}
#[test]
fn test_unmap_sealed_fails() {
if !check_mseal_support() {
return;
}
let s = SealBox::seal_value(0xDEADu32, None).unwrap();
let (ptr, size) = s.mapping();
assert_eq!(
unsafe { munmap(ptr, size.get()) }.unwrap_err(),
Errno::EPERM
);
}
#[test]
fn test_mremap_sealed_fails() {
if !check_mseal_support() {
return;
}
let s = SealBox::seal_value(1234usize, None).unwrap();
let (ptr, size) = s.mapping();
assert_eq!(
unsafe {
mremap(
ptr,
size.get(),
size.get(),
MRemapFlags::MREMAP_MAYMOVE,
None,
)
}
.unwrap_err(),
Errno::EPERM
);
}
#[test]
fn test_madvise_dontneed_sealed_fails() {
if !check_mseal_support() {
return;
}
let s = SealBox::seal_value(66u16, None).unwrap();
let (ptr, size) = s.mapping();
assert_eq!(
unsafe { madvise(ptr, size.get(), MmapAdvise::MADV_DONTNEED) }.unwrap_err(),
Errno::EPERM
);
}
#[test]
fn test_madvise_free_sealed_fails() {
if !check_mseal_support() {
return;
}
let s = SealBox::seal_value(66u16, None).unwrap();
let (ptr, size) = s.mapping();
assert_eq!(
unsafe { madvise(ptr, size.get(), MmapAdvise::MADV_FREE) }.unwrap_err(),
Errno::EPERM
);
}
#[test]
fn test_seal_scalar() {
if !check_mseal_support() {
return;
}
let sb = SealBox::new(7u8).unwrap();
let s = sb.seal(None).unwrap();
assert_eq!(*s, 7);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_new_uninit_and_assume_init() {
if !check_mseal_support() {
return;
}
let mut sb = SealBox::<MaybeUninit<u32>>::new_uninit().unwrap();
sb.write(42);
let sb = unsafe { sb.assume_init() };
let s = sb.seal(None).unwrap();
assert_eq!(*s, 42);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_seal_slice() {
if !check_mseal_support() {
return;
}
let sb = SealBoxSlice::from_slice(&[1u16, 2, 3]).unwrap();
let s = sb.seal(None).unwrap();
assert_eq!(&*s, &[1, 2, 3]);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_seal_deque() {
if !check_mseal_support() {
return;
}
let mut dq = VecDeque::new();
dq.push_back(10u32);
dq.push_back(20);
let sb = SealBoxSlice::new_deque(dq).unwrap();
let s = sb.seal(None).unwrap();
assert_eq!(&*s, &[10, 20]);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_seal_hashmap() {
if !check_mseal_support() {
return;
}
let mut m = HashMap::new();
m.insert("a", 1);
m.insert("b", 2);
let sb: SealBoxSlice<(&str, i32)> = SealBoxSlice::from_hashmap(m).unwrap();
let s = sb.seal(None).unwrap();
assert_eq!(&*s, &[("a", 1), ("b", 2)]);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_seal_sydhashmap() {
if !check_mseal_support() {
return;
}
let mut m = SydHashMap::new();
m.insert("x", 100);
m.insert("y", 200);
let sb: SealBoxSlice<(&str, i32)> = SealBoxSlice::from_sydhashmap(m).unwrap();
let s = sb.seal(None).unwrap();
assert_eq!(&*s, &[("x", 100), ("y", 200)]);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_seal_sydindexmap() {
if !check_mseal_support() {
return;
}
let mut m = SydIndexMap::default();
m.insert("x", 100);
m.insert("y", 200);
let sb: SealBoxSlice<(&str, i32)> = SealBoxSlice::from_sydindexmap(m).unwrap();
let s = sb.seal(None).unwrap();
assert_eq!(&*s, &[("x", 100), ("y", 200)]);
let (ptr, size) = s.mapping();
assert!(is_sealed(ptr, size));
}
#[test]
fn test_multi_page_slice_seal() {
if !check_mseal_support() {
return;
}
let page = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = page * 2 + 123; let data = vec![0xABu8; len];
let sb_slice = SealBoxSlice::from_slice(&data).expect("allocation failed");
let sealed = sb_slice.seal(None).expect("seal failed");
assert_eq!(&*sealed, &data[..]);
let (ptr, size) = sealed.mapping();
assert!(is_sealed(ptr, size));
assert_eq!(size.get() % page, 0);
assert!(size.get() >= len);
}
#[test]
fn test_vec_unsealed_basic() {
if !check_mseal_support() {
return;
}
let mut sv = SealableVec::new(vec![1, 2, 3]);
assert_eq!(sv.len(), 3);
assert!(sv.push(4).is_ok());
assert_eq!(&*sv, &[1, 2, 3, 4]);
assert_eq!(sv.pop(), Some(4));
}
#[test]
fn test_vec_sealed_readonly() {
if !check_mseal_support() {
return;
}
let mut sv = SealableVec::new(vec![10, 20, 30]).seal(None).unwrap();
assert_eq!(sv.len(), 3);
assert_eq!(sv.get(1), Some(&20));
assert!(matches!(sv.push(40), Err(Errno::EPERM)));
}
#[test]
fn test_deque_unsealed_basic() {
if !check_mseal_support() {
return;
}
let mut sd = SealableVecDeque::from(VecDeque::from([1, 2]));
sd.push_back(3).unwrap();
sd.push_front(0).unwrap();
sd.make_contiguous().unwrap();
assert_eq!(&*sd, &[0, 1, 2, 3]);
assert_eq!(sd.pop_front(), Some(0));
}
#[test]
fn test_deque_sealed_readonly() {
if !check_mseal_support() {
return;
}
let mut sd = SealableVecDeque::from(VecDeque::from([5, 6, 7]))
.seal(None)
.unwrap();
assert_eq!(sd.len(), 3);
assert_eq!(sd.front(), Some(&5));
assert!(matches!(sd.push_back(8), Err(Errno::EPERM)));
}
#[test]
fn test_from_slice_string() {
if !check_mseal_support() {
return;
}
let data = vec!["foo".to_string(), "bar".to_string(), "baz".to_string()];
let sealed = SealBoxSlice::from_slice(&data)
.expect("from_slice failed")
.seal(None)
.expect("seal failed");
assert_eq!(&*sealed, &data[..]);
}
#[test]
fn test_slice_independence() {
if !check_mseal_support() {
return;
}
let mut data = vec!["hello".to_string(), "world".to_string()];
let sealed = SealBoxSlice::from_slice(&data).unwrap().seal(None).unwrap();
data[0].clear();
assert_eq!(&*sealed, &["hello".to_string(), "world".to_string()][..]);
}
#[test]
fn test_multi_page_string() {
if !check_mseal_support() {
return;
}
let page = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = (page * 2 / mem::size_of::<String>()) + 5;
let data = vec!["x".repeat(50); len];
let sealed = SealBoxSlice::from_slice(&data).unwrap().seal(None).unwrap();
assert_eq!(sealed.len(), len);
for s in sealed.iter() {
assert_eq!(s, &"x".repeat(50));
}
let (_ptr, map_len) = sealed.mapping();
assert_eq!(map_len.get() % page, 0);
assert!(map_len.get() >= len * mem::size_of::<String>());
}
#[test]
fn test_empty_slice() {
if !check_mseal_support() {
return;
}
let data: Vec<String> = Vec::new();
let sealed = SealBoxSlice::from_slice(&data).unwrap().seal(None).unwrap();
assert!(sealed.is_empty());
assert_eq!(sealed.len(), 0);
}
#[test]
fn test_zero_sized_type_error() {
if !check_mseal_support() {
return;
}
let arr = [(), (), ()];
assert!(SealBoxSlice::from_slice(&arr).is_err());
}
#[test]
fn test_hashmap_default_and_new() {
if !check_mseal_support() {
return;
}
let m: SealableHashMap<i32, i32> = SealableHashMap::default();
assert!(m.is_empty());
assert_eq!(m.len(), 0);
let mut base = HashMap::new();
base.insert(1, 10);
let m2 = SealableHashMap::new(base.clone());
assert!(!m2.is_empty());
assert_eq!(m2.len(), 1);
assert_eq!(m2.get(&1), Some(&10));
}
#[test]
fn test_hashmap_unsealed_insert_get_remove() {
if !check_mseal_support() {
return;
}
let mut m = SealableHashMap::with_capacity(4);
assert!(m.is_empty());
assert_eq!(m.insert(1, 100).unwrap(), None);
assert_eq!(m.insert(1, 200).unwrap(), Some(100));
assert_eq!(m.get(&1), Some(&200));
assert!(m.contains_key(&1));
assert_eq!(m.remove(&1), Some(200));
assert!(!m.contains_key(&1));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_hashmap_unsealed_clear_reserve_capacity() {
if !check_mseal_support() {
return;
}
let mut m = SealableHashMap::new(HashMap::from([(2, 20), (3, 30)]));
let old_cap = m.capacity();
m.reserve(10).unwrap();
assert!(m.capacity() >= old_cap);
m.clear();
assert!(m.is_empty());
assert_eq!(m.len(), 0);
}
#[test]
fn test_hashmap_seal_empty_and_sealed_properties() {
if !check_mseal_support() {
return;
}
let m: SealableHashMap<&str, i32> = SealableHashMap::default();
let sealed = m.seal(None).unwrap();
assert!(sealed.is_empty());
assert_eq!(sealed.len(), 0);
assert!(!sealed.contains_key(&"x"));
assert_eq!(sealed.get(&"x"), None);
assert_eq!(sealed.capacity(), 0);
}
#[test]
fn test_hashmap_seal_and_readonly_behavior() {
if !check_mseal_support() {
return;
}
let base = HashMap::from([("a", 1), ("b", 2), ("c", 3)]);
let m = SealableHashMap::new(base);
let mut sealed = m.seal(None).unwrap();
assert_eq!(sealed.len(), 3);
assert!(sealed.contains_key(&"b"));
assert_eq!(sealed.get(&"b"), Some(&2));
assert_eq!(sealed.insert("d", 4), Err(Errno::EPERM));
assert_eq!(sealed.remove(&"a"), None);
assert_eq!(sealed.reserve(5), Err(Errno::EPERM));
sealed.clear(); assert_eq!(sealed.len(), 3);
}
#[test]
fn test_hashmap_iter_unsealed_and_sealed() {
if !check_mseal_support() {
return;
}
let entries = vec![(10, "x"), (5, "y"), (20, "z")];
let mut map = HashMap::new();
for &(k, v) in &entries {
map.insert(k, v);
}
let unsealed = SealableHashMap::new(map.clone());
let sealed = SealableHashMap::new(map).seal(None).unwrap();
let mut u: Vec<_> = unsealed.into_iter().map(|(&k, &v)| (k, v)).collect();
let mut s: Vec<_> = sealed.into_iter().map(|(&k, &v)| (k, v)).collect();
u.sort_unstable_by_key(|&(k, _)| k);
s.sort_unstable_by_key(|&(k, _)| k);
let mut expected = entries.clone();
expected.sort_unstable_by_key(|&(k, _)| k);
assert_eq!(u, expected);
assert_eq!(s, expected);
}
#[test]
fn test_hashmap_partial_eq_and_eq() {
if !check_mseal_support() {
return;
}
let mut h1 = HashMap::new();
h1.insert("k1", 100);
h1.insert("k2", 200);
let m1 = SealableHashMap::new(h1.clone());
let m2 = SealableHashMap::new(h1.clone());
assert_eq!(m1, m2);
let sealed1 = SealableHashMap::new(h1.clone()).seal(None).unwrap();
assert_eq!(m2, sealed1);
let mut h3 = h1.clone();
h3.insert("k3", 300);
let m3 = SealableHashMap::new(h3);
assert_ne!(m3, sealed1);
}
#[test]
fn test_sydhashmap_default_and_new() {
if !check_mseal_support() {
return;
}
let m: SealableSydHashMap<i32, i32> = SealableSydHashMap::default();
assert!(m.is_empty());
assert_eq!(m.len(), 0);
let mut base = SydHashMap::new();
base.insert(1, 10);
let m2 = SealableSydHashMap::new(base.clone());
assert!(!m2.is_empty());
assert_eq!(m2.len(), 1);
assert_eq!(m2.get(&1), Some(&10));
}
#[test]
fn test_sydhashmap_unsealed_insert_get_remove() {
if !check_mseal_support() {
return;
}
let mut m = SealableSydHashMap::with_capacity(4);
assert!(m.is_empty());
assert_eq!(m.insert(1, 100).unwrap(), None);
assert_eq!(m.insert(1, 200).unwrap(), Some(100));
assert_eq!(m.get(&1), Some(&200));
assert!(m.contains_key(&1));
assert_eq!(m.remove(&1), Some(200));
assert!(!m.contains_key(&1));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_sydhashmap_unsealed_clear_reserve_capacity() {
if !check_mseal_support() {
return;
}
let mut m = SydHashMap::new();
m.extend([(2, 20), (3, 30)]);
let mut m = SealableSydHashMap::from(m);
let old_cap = m.capacity();
m.reserve(10).unwrap();
assert!(m.capacity() >= old_cap);
m.clear();
assert!(m.is_empty());
assert_eq!(m.len(), 0);
}
#[test]
fn test_sydhashmap_seal_empty_and_sealed_properties() {
if !check_mseal_support() {
return;
}
let m: SealableSydHashMap<&str, i32> = SealableSydHashMap::default();
let sealed = m.seal(None).unwrap();
assert!(sealed.is_empty());
assert_eq!(sealed.len(), 0);
assert!(!sealed.contains_key(&"x"));
assert_eq!(sealed.get(&"x"), None);
assert_eq!(sealed.capacity(), 0);
}
#[test]
fn test_sydhashmap_seal_and_readonly_behavior() {
let mut base = SydHashMap::new();
base.extend([("a", 1), ("b", 2), ("c", 3)]);
let m = SealableSydHashMap::new(base);
let mut sealed = m.seal(None).unwrap();
assert_eq!(sealed.len(), 3);
assert!(sealed.contains_key(&"b"));
assert_eq!(sealed.get(&"b"), Some(&2));
assert_eq!(sealed.insert("d", 4), Err(Errno::EPERM));
assert_eq!(sealed.remove(&"a"), None);
assert_eq!(sealed.reserve(5), Err(Errno::EPERM));
sealed.clear(); assert_eq!(sealed.len(), 3);
}
#[test]
fn test_sydhashmap_iter_unsealed_and_sealed() {
if !check_mseal_support() {
return;
}
let entries = vec![(10, "x"), (5, "y"), (20, "z")];
let mut map = SydHashMap::new();
for &(k, v) in &entries {
map.insert(k, v);
}
let unsealed = SealableSydHashMap::new(map.clone());
let sealed = SealableSydHashMap::new(map).seal(None).unwrap();
let mut u: Vec<_> = unsealed.into_iter().map(|(&k, &v)| (k, v)).collect();
let mut s: Vec<_> = sealed.into_iter().map(|(&k, &v)| (k, v)).collect();
u.sort_unstable_by_key(|&(k, _)| k);
s.sort_unstable_by_key(|&(k, _)| k);
let mut expected = entries.clone();
expected.sort_unstable_by_key(|&(k, _)| k);
assert_eq!(u, expected);
assert_eq!(s, expected);
}
#[test]
fn test_sydhashmap_partial_eq_and_eq() {
if !check_mseal_support() {
return;
}
let mut h1 = SydHashMap::new();
h1.insert("k1", 100);
h1.insert("k2", 200);
let m1 = SealableSydHashMap::new(h1.clone());
let m2 = SealableSydHashMap::new(h1.clone());
assert_eq!(m1, m2);
let sealed1 = SealableSydHashMap::new(h1.clone()).seal(None).unwrap();
assert_eq!(m2, sealed1);
let mut h3 = h1.clone();
h3.insert("k3", 300);
let m3 = SealableSydHashMap::new(h3);
assert_ne!(m3, sealed1);
}
#[test]
fn test_sydindexmap_default_and_new() {
if !check_mseal_support() {
return;
}
let m: SealableSydIndexMap<i32, i32> = SealableSydIndexMap::default();
assert!(m.is_empty());
assert_eq!(m.len(), 0);
let mut base = SydIndexMap::default();
base.insert(1, 10);
let m2 = SealableSydIndexMap::new(base.clone());
assert!(!m2.is_empty());
assert_eq!(m2.len(), 1);
assert_eq!(m2.get(&1), Some(&10));
}
#[test]
fn test_sydindexmap_unsealed_insert_get_remove() {
if !check_mseal_support() {
return;
}
let mut m = SealableSydIndexMap::with_capacity(4);
assert!(m.is_empty());
assert_eq!(m.insert(1, 100).unwrap(), None);
assert_eq!(m.insert(1, 200).unwrap(), Some(100));
assert_eq!(m.get(&1), Some(&200));
assert!(m.contains_key(&1));
assert_eq!(m.remove(&1), Some(200));
assert!(!m.contains_key(&1));
assert_eq!(m.remove(&1), None);
}
#[test]
fn test_sydindexmap_unsealed_clear_reserve_capacity() {
if !check_mseal_support() {
return;
}
let mut m = SydIndexMap::default();
m.extend([(2, 20), (3, 30)]);
let mut m = SealableSydIndexMap::from(m);
let old_cap = m.capacity();
m.reserve(10).unwrap();
assert!(m.capacity() >= old_cap);
m.clear();
assert!(m.is_empty());
assert_eq!(m.len(), 0);
}
#[test]
fn test_sydindexmap_seal_empty_and_sealed_properties() {
if !check_mseal_support() {
return;
}
let m: SealableSydIndexMap<&str, i32> = SealableSydIndexMap::default();
let sealed = m.seal(None).unwrap();
assert!(sealed.is_empty());
assert_eq!(sealed.len(), 0);
assert!(!sealed.contains_key(&"x"));
assert_eq!(sealed.get(&"x"), None);
assert_eq!(sealed.capacity(), 0);
}
#[test]
fn test_sydindexmap_seal_and_readonly_behavior() {
let mut base = SydIndexMap::default();
base.extend([("a", 1), ("b", 2), ("c", 3)]);
let m = SealableSydIndexMap::new(base);
let mut sealed = m.seal(None).unwrap();
assert_eq!(sealed.len(), 3);
assert!(sealed.contains_key(&"b"));
assert_eq!(sealed.get(&"b"), Some(&2));
assert_eq!(sealed.insert("d", 4), Err(Errno::EPERM));
assert_eq!(sealed.remove(&"a"), None);
assert_eq!(sealed.reserve(5), Err(Errno::EPERM));
sealed.clear(); assert_eq!(sealed.len(), 3);
}
#[test]
fn test_sydindexmap_iter_unsealed_and_sealed() {
if !check_mseal_support() {
return;
}
let entries = vec![(10, "x"), (5, "y"), (20, "z")];
let mut map = SydIndexMap::default();
for &(k, v) in &entries {
map.insert(k, v);
}
let unsealed = SealableSydIndexMap::new(map.clone());
let sealed = SealableSydIndexMap::new(map).seal(None).unwrap();
let mut u: Vec<_> = unsealed.into_iter().map(|(&k, &v)| (k, v)).collect();
let mut s: Vec<_> = sealed.into_iter().map(|(&k, &v)| (k, v)).collect();
u.sort_unstable_by_key(|&(k, _)| k);
s.sort_unstable_by_key(|&(k, _)| k);
let mut expected = entries.clone();
expected.sort_unstable_by_key(|&(k, _)| k);
assert_eq!(u, expected);
assert_eq!(s, expected);
}
#[test]
fn test_sydindexmap_partial_eq_and_eq() {
if !check_mseal_support() {
return;
}
let mut h1 = SydIndexMap::default();
h1.insert("k1", 100);
h1.insert("k2", 200);
let m1 = SealableSydIndexMap::new(h1.clone());
let m2 = SealableSydIndexMap::new(h1.clone());
assert_eq!(m1, m2);
let sealed1 = SealableSydIndexMap::new(h1.clone()).seal(None).unwrap();
assert_eq!(m2, sealed1);
let mut h3 = h1.clone();
h3.insert("k3", 300);
let m3 = SealableSydIndexMap::new(h3);
assert_ne!(m3, sealed1);
}
#[test]
fn test_hashmap_retain_removes_odds() {
let mut shm = SealableHashMap::new(HashMap::from([(1, 10), (2, 20), (3, 30), (4, 40)]));
shm.retain(|k, _v| *k % 2 == 0).unwrap();
let collected: Vec<_> = shm.into_iter().map(|(&k, &v)| (k, v)).collect();
assert_eq!(collected.len(), 2);
assert!(collected.contains(&(2, 20)));
assert!(collected.contains(&(4, 40)));
}
#[test]
fn test_hashmap_retain_mutates_values() {
let mut shm = SealableHashMap::new(HashMap::from([(1, 1), (2, 2), (3, 3)]));
shm.retain(|k, v| {
*v *= 2;
*k >= 2
})
.unwrap();
assert_eq!(shm.len(), 2);
assert_eq!(shm.get(&2), Some(&4));
assert_eq!(shm.get(&3), Some(&6));
}
#[test]
fn test_hashmap_retain_all() {
let mut shm = SealableHashMap::new(HashMap::from([('a', 100), ('b', 200)]));
shm.retain(|_, _| true).unwrap();
assert_eq!(shm.len(), 2);
assert_eq!(shm.get(&'a'), Some(&100));
assert_eq!(shm.get(&'b'), Some(&200));
}
#[test]
fn test_hashmap_retain_none() {
let mut shm = SealableHashMap::new(HashMap::from([("x", 9), ("y", 8)]));
shm.retain(|_, _| false).unwrap();
assert!(shm.is_empty());
}
#[test]
fn test_hashmap_retain_on_empty_map() {
let mut shm: SealableHashMap<i32, i32> = SealableHashMap::default();
shm.retain(|_, _| unreachable!()).unwrap();
assert!(shm.is_empty());
}
#[test]
fn test_hashmap_sealed_retain_error() {
let shm = SealableHashMap::new(HashMap::from([(1, 1)]));
let mut sealed = shm.seal(None).unwrap();
let err = sealed.retain(|_, _| true).unwrap_err();
assert_eq!(err, Errno::EPERM);
}
#[test]
fn test_sydhashmap_retain_removes_small_values() {
let mut sahm = SydHashMap::new();
sahm.extend([(10, 1), (20, 2), (30, 3), (40, 4)]);
let mut sahm = SealableSydHashMap::new(sahm);
sahm.retain(|_, v| *v > 2).unwrap();
let mut collected: Vec<_> = sahm.into_iter().map(|(&k, &v)| (k, v)).collect();
collected.sort_unstable();
assert_eq!(collected, vec![(30, 3), (40, 4)]);
}
#[ignore]
#[test]
fn test_sydhashmap_retain_mutates_keys_and_values() {
let mut sahm = SydHashMap::new();
sahm.extend([
("one".to_string(), 1),
("two".to_string(), 2),
("three".to_string(), 3),
]);
let mut sahm = SealableSydHashMap::new(sahm);
sahm.retain(|k, v| {
if k.len() % 2 == 0 {
*v += 10;
true
} else {
false
}
})
.unwrap();
assert_eq!(sahm.len(), 1);
assert_eq!(sahm.get("two"), Some(&12));
}
#[test]
fn test_sydhashmap_retain_all_and_none() {
let mut sahm = SydHashMap::new();
sahm.extend([(1, 100)]);
let mut sahm = SealableSydHashMap::new(sahm);
sahm.retain(|_, _| true).unwrap();
assert_eq!(sahm.len(), 1);
sahm.retain(|_, _| false).unwrap();
assert!(sahm.is_empty());
}
#[test]
fn test_sydhashmap_retain_on_empty_map() {
let mut sahm: SealableSydHashMap<u8, u8> = SealableSydHashMap::default();
sahm.retain(|_, _| unreachable!()).unwrap();
assert!(sahm.is_empty());
}
#[test]
fn test_sydhashmap_sealed_retain_error() {
let mut sahm = SydHashMap::new();
sahm.extend([(0, 0)]);
let sahm = SealableSydHashMap::new(sahm);
let mut sealed = sahm.seal(None).unwrap();
let err = sealed.retain(|_, _| true).unwrap_err();
assert_eq!(err, Errno::EPERM);
}
#[test]
fn test_sydindexmap_retain_removes_small_values() {
let mut sahm = SydIndexMap::default();
sahm.extend([(10, 1), (20, 2), (30, 3), (40, 4)]);
let mut sahm = SealableSydIndexMap::new(sahm);
sahm.retain(|_, v| *v > 2).unwrap();
let mut collected: Vec<_> = sahm.into_iter().map(|(&k, &v)| (k, v)).collect();
collected.sort_unstable();
assert_eq!(collected, vec![(30, 3), (40, 4)]);
}
#[ignore]
#[test]
fn test_sydindexmap_retain_mutates_keys_and_values() {
let mut sahm = SydIndexMap::default();
sahm.extend([
("one".to_string(), 1),
("two".to_string(), 2),
("three".to_string(), 3),
]);
let mut sahm = SealableSydIndexMap::new(sahm);
sahm.retain(|k, v| {
if k.len() % 2 == 0 {
*v += 10;
true
} else {
false
}
})
.unwrap();
assert_eq!(sahm.len(), 1);
assert_eq!(sahm.get("two"), Some(&12));
}
#[test]
fn test_sydindexmap_retain_all_and_none() {
let mut sahm = SydIndexMap::default();
sahm.extend([(1, 100)]);
let mut sahm = SealableSydIndexMap::new(sahm);
sahm.retain(|_, _| true).unwrap();
assert_eq!(sahm.len(), 1);
sahm.retain(|_, _| false).unwrap();
assert!(sahm.is_empty());
}
#[test]
fn test_sydindexmap_retain_on_empty_map() {
let mut sahm: SealableSydIndexMap<u8, u8> = SealableSydIndexMap::default();
sahm.retain(|_, _| unreachable!()).unwrap();
assert!(sahm.is_empty());
}
#[test]
fn test_sydindexmap_sealed_retain_error() {
let mut sahm = SydIndexMap::default();
sahm.extend([(0, 0)]);
let sahm = SealableSydIndexMap::new(sahm);
let mut sealed = sahm.seal(None).unwrap();
let err = sealed.retain(|_, _| true).unwrap_err();
assert_eq!(err, Errno::EPERM);
}
fn page_size() -> NonZeroUsize {
sysconf(SysconfVar::PAGE_SIZE)
.unwrap()
.map(usize::try_from)
.unwrap()
.map(NonZeroUsize::try_from)
.unwrap()
.unwrap()
}
fn map_region(len: NonZeroUsize) -> NonNull<c_void> {
let result = unsafe {
mmap_anonymous(
None,
len,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE,
)
};
assert!(result.is_ok(), "mmap_anonymous:{result:?}");
result.unwrap()
}
fn unmap_region(ptr: NonNull<c_void>, len: NonZeroUsize) {
let result = unsafe { munmap(ptr, len.get()) };
assert!(result.is_ok(), "munmap:{result:?}");
}
#[test]
fn test_madv_guard_install_idempotent() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let region = map_region(page);
match madvise_guard_install(region, page) {
Ok(()) => {}
Err(Errno::EINVAL) => {
unmap_region(region, page);
return;
}
Err(errno) => panic!("unexpected error on install: {errno}"),
}
madvise_guard_install(region, page).expect("second install failed");
let _ = madvise_guard_remove(region, page);
unmap_region(region, page);
}
#[test]
fn test_madv_guard_remove_idempotent() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let region = map_region(page);
match madvise_guard_install(region, page) {
Ok(()) => {}
Err(Errno::EINVAL) => {
unmap_region(region, page);
return;
}
Err(errno) => panic!("unexpected error on install: {errno}"),
}
madvise_guard_remove(region, page).expect("first remove failed");
madvise_guard_remove(region, page).expect("second remove failed");
unmap_region(region, page);
}
#[test]
fn test_madv_guard_remove_without_install() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let region = map_region(page);
match madvise_guard_remove(region, page) {
Ok(()) => {} Err(Errno::EINVAL) => {} Err(errno) => panic!("unexpected error: {errno}"),
}
unmap_region(region, page);
}
#[test]
fn test_madv_guard_install_partial_fault() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let page2 = NonZeroUsize::new(page.get() * 2).unwrap();
let region = map_region(page2);
match madvise_guard_install(region, page) {
Ok(()) => {}
Err(Errno::EINVAL) => {
unmap_region(region, page2);
return;
}
Err(errno) => panic!("unexpected error: {errno}"),
}
match unsafe { fork() } {
Ok(ForkResult::Parent { child }) => match waitpid(child, None).unwrap() {
WaitStatus::Signaled(_, Signal::SIGSEGV, _) => {}
other => panic!("expected SIGSEGV, got {other:?}"),
},
Ok(ForkResult::Child) => {
unsafe { (region.as_ptr() as *mut u8).write_volatile(0) };
std::process::exit(1);
}
Err(errno) => panic!("fork failed: {errno}"),
}
let _ = madvise_guard_remove(region, page);
unmap_region(region, page2);
}
#[test]
fn test_madv_guard_install_partial_no_fault() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let page2 = NonZeroUsize::new(page.get() * 2).unwrap();
let region = map_region(page2);
match madvise_guard_install(region, page) {
Ok(()) => {}
Err(Errno::EINVAL) => {
unmap_region(region, page2);
return;
}
Err(errno) => panic!("unexpected error: {errno}"),
}
match unsafe { fork() } {
Ok(ForkResult::Parent { child }) => match waitpid(child, None).unwrap() {
WaitStatus::Exited(_, 0) => {}
other => panic!("expected exit(0), got {other:?}"),
},
Ok(ForkResult::Child) => {
unsafe { (region.as_ptr().add(page.get()) as *mut u8).write_volatile(42) };
std::process::exit(0);
}
Err(errno) => panic!("fork failed: {errno}"),
}
let _ = madvise_guard_remove(region, page);
unmap_region(region, page2);
}
#[test]
fn test_madv_guard_remove_partial_no_fault() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let page2 = NonZeroUsize::new(page.get() * 2).unwrap();
let region = map_region(page2);
match madvise_guard_install(region, page2) {
Ok(()) => {}
Err(Errno::EINVAL) => {
unmap_region(region, page2);
return;
}
Err(errno) => panic!("unexpected error: {errno}"),
}
let _ = madvise_guard_remove(
unsafe { NonNull::new_unchecked(region.as_ptr().add(page.get())) },
page,
);
match unsafe { fork() } {
Ok(ForkResult::Parent { child }) => match waitpid(child, None).unwrap() {
WaitStatus::Exited(_, 0) => {}
other => panic!("expected exit(0), got {other:?}"),
},
Ok(ForkResult::Child) => {
unsafe { (region.as_ptr().add(page.get()) as *mut u8).write_volatile(99) };
std::process::exit(0);
}
Err(errno) => panic!("fork failed: {errno}"),
}
let _ = madvise_guard_remove(region, page2);
unmap_region(region, page2);
}
#[test]
fn test_madv_guard_multiple_regions() {
if !check_madvise_guard_support() {
return;
}
let page = page_size();
let r1 = map_region(page);
let r2 = map_region(page);
match madvise_guard_install(r1, page) {
Ok(()) => {}
Err(Errno::EINVAL) => {
unmap_region(r1, page);
unmap_region(r2, page);
return;
}
Err(errno) => panic!("unexpected error: {errno}"),
}
match unsafe { fork() } {
Ok(ForkResult::Parent { child }) => match waitpid(child, None).unwrap() {
WaitStatus::Exited(_, 0) => {}
other => panic!("expected exit(0), got {other:?}"),
},
Ok(ForkResult::Child) => {
unsafe { (r2.as_ptr() as *mut u8).write_volatile(7) };
std::process::exit(0);
}
Err(errno) => panic!("fork failed: {errno}"),
}
match unsafe { fork() } {
Ok(ForkResult::Parent { child }) => match waitpid(child, None).unwrap() {
WaitStatus::Signaled(_, Signal::SIGSEGV, _) => {}
other => panic!("expected SIGSEGV, got {other:?}"),
},
Ok(ForkResult::Child) => {
unsafe { (r1.as_ptr() as *mut u8).write_volatile(5) };
std::process::exit(1);
}
Err(errno) => panic!("fork failed: {errno}"),
}
let _ = madvise_guard_remove(r1, page);
unmap_region(r1, page);
unmap_region(r2, page);
}
}