Struct rkyv::validation::ArchiveContext[][src]

pub struct ArchiveContext { /* fields omitted */ }

Context to perform archive validation.

When implementing archiveable containers, an archived type may point to some bytes elsewhere in the archive using a RelPtr. Before checking those bytes, they must be claimed in the context. This prevents infinite-loop attacks by malicious actors by ensuring that each block of memory has one and only one owner.

Example

use core::{fmt, marker::PhantomData};
use std::error::Error;
use rkyv::{
    validation::{ArchiveContext, ArchiveMemoryError},
    Archive,
    RelPtr,
    Resolve,
    Write,
};
use bytecheck::{CheckBytes, Unreachable};

pub struct MyBox<T> {
    value: *mut T,
}

impl<T> MyBox<T> {
    fn new(value: T) -> Self {
        Self {
            value: Box::into_raw(Box::new(value)),
        }
    }

    fn value(&self) -> &T {
        unsafe { &*self.value }
    }
}

impl<T> Drop for MyBox<T> {
    fn drop(&mut self) {
        unsafe {
            Box::from_raw(self.value);
        }
    }
}

// A transparent representation guarantees us the same representation as
// a RelPtr
#[repr(transparent)]
pub struct ArchivedMyBox<T> {
    value: RelPtr,
    _phantom: PhantomData<T>,
}

impl<T> ArchivedMyBox<T> {
    fn value(&self) -> &T {
        unsafe { &*self.value.as_ptr() }
    }
}

pub struct ArchivedMyBoxResolver {
    value_pos: usize,
}

impl<T: Archive> Resolve<MyBox<T>> for ArchivedMyBoxResolver {
    type Archived = ArchivedMyBox<T::Archived>;

    fn resolve(self, pos: usize, value: &MyBox<T>) -> Self::Archived {
        unsafe {
            ArchivedMyBox {
                value: RelPtr::new(pos, self.value_pos),
                _phantom: PhantomData,
            }
        }
    }
}

impl<T: Archive> Archive for MyBox<T> {
    type Archived = ArchivedMyBox<T::Archived>;
    type Resolver = ArchivedMyBoxResolver;

    fn archive<W: Write + ?Sized>(&self, writer: &mut W) -> Result<Self::Resolver, W::Error> {
        Ok(ArchivedMyBoxResolver {
            value_pos: writer.archive(self.value())?,
        })
    }
}

#[derive(Debug)]
pub enum ArchivedMyBoxError<T> {
    MemoryError(ArchiveMemoryError),
    CheckValueError(T),
}

impl<T: fmt::Display> fmt::Display for ArchivedMyBoxError<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ArchivedMyBoxError::MemoryError(e) => write!(f, "memory error: {}", e),
            ArchivedMyBoxError::CheckValueError(e) => write!(f, "check value error: {}", e),
        }
    }
}

impl<T: Error> Error for ArchivedMyBoxError<T> {}

impl<T> From<Unreachable> for ArchivedMyBoxError<T> {
    fn from(e: Unreachable) -> Self {
        unreachable!()
    }
}

impl<T> From<ArchiveMemoryError> for ArchivedMyBoxError<T> {
    fn from(e: ArchiveMemoryError) -> Self {
        ArchivedMyBoxError::MemoryError(e)
    }
}

impl<T: CheckBytes<ArchiveContext>> CheckBytes<ArchiveContext> for ArchivedMyBox<T> {
    type Error = ArchivedMyBoxError<T::Error>;

    unsafe fn check_bytes<'a>(
        bytes: *const u8,
        context: &mut ArchiveContext
    ) -> Result<&'a Self, Self::Error> {
        let rel_ptr = RelPtr::check_bytes(bytes, context)?;
        let value_bytes = context.claim::<T>(rel_ptr, 1)?;
        T::check_bytes(value_bytes, context)
            .map_err(|e| ArchivedMyBoxError::CheckValueError(e))?;
        Ok(&*bytes.cast())
    }
}

Implementations

impl ArchiveContext[src]

pub fn new(bytes: &[u8]) -> Self[src]

Creates a new archive context for the given byte slice

pub unsafe fn claim<T: CheckBytes<ArchiveContext>>(
    &mut self,
    rel_ptr: &RelPtr,
    count: usize
) -> Result<*const u8, ArchiveMemoryError>
[src]

Claims count items pointed to by the given relative pointer.

Safety

rel_ptr must be inside the archive this context was created for.

pub unsafe fn claim_bytes(
    &mut self,
    base: *const u8,
    offset: isize,
    count: usize,
    align: usize
) -> Result<*const u8, ArchiveMemoryError>
[src]

Claims count bytes located offset bytes away from base.

Safety

base must be inside the archive this context was created for.

Trait Implementations

impl<T: CheckBytes<ArchiveContext>> CheckBytes<ArchiveContext> for ArchivedRef<T>[src]

type Error = ArchivedRefError<T::Error>

The error that may result from validating the type.

impl<T: CheckBytes<ArchiveContext>> CheckBytes<ArchiveContext> for ArchivedSlice<T>[src]

type Error = ArchivedSliceError<T::Error>

The error that may result from validating the type.

impl CheckBytes<ArchiveContext> for ArchivedStringSlice[src]

type Error = ArchivedStringSliceError

The error that may result from validating the type.

impl<K: CheckBytes<ArchiveContext> + Eq + Hash, V: CheckBytes<ArchiveContext>> CheckBytes<ArchiveContext> for ArchivedHashMap<K, V>[src]

type Error = ArchivedHashMapError<K::Error, V::Error>

The error that may result from validating the type.

impl<K: CheckBytes<ArchiveContext> + Hash + Eq> CheckBytes<ArchiveContext> for ArchivedHashSet<K>[src]

type Error = ArchivedHashMapError<K::Error, <() as CheckBytes<ArchiveContext>>::Error>

The error that may result from validating the type.

impl CheckBytes<ArchiveContext> for RelPtr[src]

type Error = Unreachable

The error that may result from validating the type.

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.