rkyv/collections/hash_index/
validation.rs1use crate::{collections::ArchivedHashIndex, validation::ArchiveContext, Archived, RelPtr};
4use bytecheck::{CheckBytes, Error, SliceCheckError};
5use core::{
6 alloc::{Layout, LayoutError},
7 convert::Infallible,
8 fmt, ptr,
9};
10
11#[derive(Debug)]
13pub enum HashIndexError<C> {
14 LayoutError(LayoutError),
16 InvalidDisplacement {
18 index: usize,
20 value: u32,
22 },
23 ContextError(C),
25}
26
27impl<C> From<LayoutError> for HashIndexError<C> {
28 #[inline]
29 fn from(e: LayoutError) -> Self {
30 Self::LayoutError(e)
31 }
32}
33
34impl<C> From<Infallible> for HashIndexError<C> {
35 #[inline]
36 fn from(_: Infallible) -> Self {
37 unsafe { core::hint::unreachable_unchecked() }
38 }
39}
40
41impl<C> From<SliceCheckError<Infallible>> for HashIndexError<C> {
42 #[inline]
43 fn from(_: SliceCheckError<Infallible>) -> Self {
44 unsafe { core::hint::unreachable_unchecked() }
45 }
46}
47
48impl<C: fmt::Display> fmt::Display for HashIndexError<C> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 HashIndexError::LayoutError(e) => write!(f, "layout error: {}", e),
52 HashIndexError::InvalidDisplacement { index, value } => write!(
53 f,
54 "invalid displacement: value {} at index {}",
55 value, index,
56 ),
57 HashIndexError::ContextError(e) => e.fmt(f),
58 }
59 }
60}
61
62#[cfg(feature = "std")]
63const _: () = {
64 use std::error::Error;
65
66 impl<C: Error + 'static> Error for HashIndexError<C> {
67 fn source(&self) -> Option<&(dyn Error + 'static)> {
68 match self {
69 HashIndexError::LayoutError(e) => Some(e as &dyn Error),
70 HashIndexError::InvalidDisplacement { .. } => None,
71 HashIndexError::ContextError(e) => Some(e as &dyn Error),
72 }
73 }
74 }
75};
76
77impl<C: ArchiveContext + ?Sized> CheckBytes<C> for ArchivedHashIndex
78where
79 C::Error: Error,
80{
81 type Error = HashIndexError<C::Error>;
82
83 unsafe fn check_bytes<'a>(
84 value: *const Self,
85 context: &mut C,
86 ) -> Result<&'a Self, Self::Error> {
87 let len = from_archived!(*Archived::<usize>::check_bytes(
88 ptr::addr_of!((*value).len),
89 context,
90 )?) as usize;
91 Layout::array::<Archived<u32>>(len)?;
92
93 let displace_rel_ptr =
94 RelPtr::manual_check_bytes(ptr::addr_of!((*value).displace), context)?;
95 let displace_ptr = context
96 .check_subtree_ptr::<[Archived<u32>]>(
97 displace_rel_ptr.base(),
98 displace_rel_ptr.offset(),
99 len,
100 )
101 .map_err(HashIndexError::ContextError)?;
102
103 let range = context
104 .push_prefix_subtree(displace_ptr)
105 .map_err(HashIndexError::ContextError)?;
106 let displace = <[Archived<u32>]>::check_bytes(displace_ptr, context)?;
107 context
108 .pop_prefix_range(range)
109 .map_err(HashIndexError::ContextError)?;
110
111 for (i, &d) in displace.iter().enumerate() {
112 let d = from_archived!(d);
113 if d as usize >= len && d < 0x80_00_00_00 {
114 return Err(HashIndexError::InvalidDisplacement { index: i, value: d });
115 }
116 }
117
118 Ok(&*value)
119 }
120}