1use crate::follow::Follow;
2use crate::{ForwardsUOffset, SOffsetT, SkipSizePrefix, UOffsetT, VOffsetT, Vector, SIZE_UOFFSET};
3#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5use core::ops::Range;
6use core::option::Option;
7
8#[cfg(all(nightly, not(feature = "std")))]
9use core::error::Error;
10#[cfg(feature = "std")]
11use std::error::Error;
12
13#[derive(Clone, Debug, PartialEq, Eq)]
17pub enum ErrorTraceDetail {
18 VectorElement {
19 index: usize,
20 position: usize,
21 },
22 TableField {
23 field_name: &'static str,
24 position: usize,
25 },
26 UnionVariant {
27 variant: &'static str,
28 position: usize,
29 },
30}
31
32#[derive(PartialEq, Eq, Default, Debug, Clone)]
33pub struct ErrorTrace(Vec<ErrorTraceDetail>);
34
35impl core::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace {
36 #[inline]
37 fn as_ref(&self) -> &[ErrorTraceDetail] {
38 &self.0
39 }
40}
41
42#[derive(Clone, Debug, PartialEq, Eq)]
45pub enum InvalidFlatbuffer {
46 MissingRequiredField {
47 required: &'static str,
48 error_trace: ErrorTrace,
49 },
50 InconsistentUnion {
51 field: &'static str,
52 field_type: &'static str,
53 error_trace: ErrorTrace,
54 },
55 Utf8Error {
56 error: core::str::Utf8Error,
57 range: Range<usize>,
58 error_trace: ErrorTrace,
59 },
60 MissingNullTerminator {
61 range: Range<usize>,
62 error_trace: ErrorTrace,
63 },
64 Unaligned {
65 position: usize,
66 unaligned_type: &'static str,
67 error_trace: ErrorTrace,
68 },
69 RangeOutOfBounds {
70 range: Range<usize>,
71 error_trace: ErrorTrace,
72 },
73 SignedOffsetOutOfBounds {
74 soffset: SOffsetT,
75 position: usize,
76 error_trace: ErrorTrace,
77 },
78 TooManyTables,
80 ApparentSizeTooLarge,
81 DepthLimitReached,
82}
83
84#[cfg(any(nightly, feature = "std"))]
85impl Error for InvalidFlatbuffer {
86 fn source(&self) -> Option<&(dyn Error + 'static)> {
87 if let InvalidFlatbuffer::Utf8Error { error: source, .. } = self {
88 Some(source)
89 } else {
90 None
91 }
92 }
93}
94
95impl core::fmt::Display for InvalidFlatbuffer {
96 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
97 match self {
98 InvalidFlatbuffer::MissingRequiredField {
99 required,
100 error_trace,
101 } => {
102 writeln!(f, "Missing required field `{}`.\n{}", required, error_trace)?;
103 }
104 InvalidFlatbuffer::InconsistentUnion {
105 field,
106 field_type,
107 error_trace,
108 } => {
109 writeln!(
110 f,
111 "Exactly one of union discriminant (`{}`) and value (`{}`) are present.\n{}",
112 field_type, field, error_trace
113 )?;
114 }
115 InvalidFlatbuffer::Utf8Error {
116 error,
117 range,
118 error_trace,
119 } => {
120 writeln!(
121 f,
122 "Utf8 error for string in {:?}: {}\n{}",
123 range, error, error_trace
124 )?;
125 }
126 InvalidFlatbuffer::MissingNullTerminator { range, error_trace } => {
127 writeln!(
128 f,
129 "String in range [{}, {}) is missing its null terminator.\n{}",
130 range.start, range.end, error_trace
131 )?;
132 }
133 InvalidFlatbuffer::Unaligned {
134 position,
135 unaligned_type,
136 error_trace,
137 } => {
138 writeln!(
139 f,
140 "Type `{}` at position {} is unaligned.\n{}",
141 unaligned_type, position, error_trace
142 )?;
143 }
144 InvalidFlatbuffer::RangeOutOfBounds { range, error_trace } => {
145 writeln!(
146 f,
147 "Range [{}, {}) is out of bounds.\n{}",
148 range.start, range.end, error_trace
149 )?;
150 }
151 InvalidFlatbuffer::SignedOffsetOutOfBounds {
152 soffset,
153 position,
154 error_trace,
155 } => {
156 writeln!(
157 f,
158 "Signed offset at position {} has value {} which points out of bounds.\n{}",
159 position, soffset, error_trace
160 )?;
161 }
162 InvalidFlatbuffer::TooManyTables {} => {
163 writeln!(f, "Too many tables.")?;
164 }
165 InvalidFlatbuffer::ApparentSizeTooLarge {} => {
166 writeln!(f, "Apparent size too large.")?;
167 }
168 InvalidFlatbuffer::DepthLimitReached {} => {
169 writeln!(f, "Nested table depth limit reached.")?;
170 }
171 }
172 Ok(())
173 }
174}
175
176impl core::fmt::Display for ErrorTrace {
177 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
178 use ErrorTraceDetail::*;
179 for e in self.0.iter() {
180 match e {
181 VectorElement { index, position } => {
182 writeln!(
183 f,
184 "\twhile verifying vector element {:?} at position {:?}",
185 index, position
186 )?;
187 }
188 TableField {
189 field_name,
190 position,
191 } => {
192 writeln!(
193 f,
194 "\twhile verifying table field `{}` at position {:?}",
195 field_name, position
196 )?;
197 }
198 UnionVariant { variant, position } => {
199 writeln!(
200 f,
201 "\t while verifying union variant `{}` at position {:?}",
202 variant, position
203 )?;
204 }
205 }
206 }
207 Ok(())
208 }
209}
210
211pub type Result<T> = core::result::Result<T, InvalidFlatbuffer>;
212
213impl InvalidFlatbuffer {
214 fn new_range_oob<T>(start: usize, end: usize) -> Result<T> {
215 Err(Self::RangeOutOfBounds {
216 range: Range { start, end },
217 error_trace: Default::default(),
218 })
219 }
220 fn new_inconsistent_union<T>(field: &'static str, field_type: &'static str) -> Result<T> {
221 Err(Self::InconsistentUnion {
222 field,
223 field_type,
224 error_trace: Default::default(),
225 })
226 }
227 fn new_missing_required<T>(required: &'static str) -> Result<T> {
228 Err(Self::MissingRequiredField {
229 required,
230 error_trace: Default::default(),
231 })
232 }
233}
234
235fn append_trace<T>(mut res: Result<T>, d: ErrorTraceDetail) -> Result<T> {
237 if let Err(e) = res.as_mut() {
238 use InvalidFlatbuffer::*;
239 if let MissingRequiredField { error_trace, .. }
240 | Unaligned { error_trace, .. }
241 | RangeOutOfBounds { error_trace, .. }
242 | InconsistentUnion { error_trace, .. }
243 | Utf8Error { error_trace, .. }
244 | MissingNullTerminator { error_trace, .. }
245 | SignedOffsetOutOfBounds { error_trace, .. } = e
246 {
247 error_trace.0.push(d)
248 }
249 }
250 res
251}
252
253fn trace_field<T>(res: Result<T>, field_name: &'static str, position: usize) -> Result<T> {
255 append_trace(
256 res,
257 ErrorTraceDetail::TableField {
258 field_name,
259 position,
260 },
261 )
262}
263
264fn trace_elem<T>(res: Result<T>, index: usize, position: usize) -> Result<T> {
266 append_trace(res, ErrorTraceDetail::VectorElement { index, position })
267}
268
269#[derive(Debug, Clone, PartialEq, Eq)]
270pub struct VerifierOptions {
271 pub max_depth: usize,
273 pub max_tables: usize,
275 pub max_apparent_size: usize,
278 pub ignore_missing_null_terminator: bool,
281 }
285
286impl Default for VerifierOptions {
287 fn default() -> Self {
288 Self {
289 max_depth: 64,
290 max_tables: 1_000_000,
291 max_apparent_size: 1 << 31,
293 ignore_missing_null_terminator: false,
294 }
295 }
296}
297
298#[derive(Debug)]
300pub struct Verifier<'opts, 'buf> {
301 buffer: &'buf [u8],
302 opts: &'opts VerifierOptions,
303 depth: usize,
304 num_tables: usize,
305 apparent_size: usize,
306}
307
308impl<'opts, 'buf> Verifier<'opts, 'buf> {
309 pub fn new(opts: &'opts VerifierOptions, buffer: &'buf [u8]) -> Self {
310 Self {
311 opts,
312 buffer,
313 depth: 0,
314 num_tables: 0,
315 apparent_size: 0,
316 }
317 }
318 #[inline]
320 pub fn reset(&mut self) {
321 self.depth = 0;
322 self.num_tables = 0;
323 self.num_tables = 0;
324 }
325 #[inline]
336 fn is_aligned<T>(&self, pos: usize) -> Result<()> {
337 if pos % core::mem::align_of::<T>() == 0 {
338 Ok(())
339 } else {
340 Err(InvalidFlatbuffer::Unaligned {
341 unaligned_type: core::any::type_name::<T>(),
342 position: pos,
343 error_trace: Default::default(),
344 })
345 }
346 }
347 #[inline]
348 fn range_in_buffer(&mut self, pos: usize, size: usize) -> Result<()> {
349 let end = pos.saturating_add(size);
350 if end > self.buffer.len() {
351 return InvalidFlatbuffer::new_range_oob(pos, end);
352 }
353 self.apparent_size += size;
354 if self.apparent_size > self.opts.max_apparent_size {
355 return Err(InvalidFlatbuffer::ApparentSizeTooLarge);
356 }
357 Ok(())
358 }
359 #[inline]
361 pub fn in_buffer<T>(&mut self, pos: usize) -> Result<()> {
362 self.is_aligned::<T>(pos)?;
363 self.range_in_buffer(pos, core::mem::size_of::<T>())
364 }
365 #[inline]
366 fn get_u16(&mut self, pos: usize) -> Result<u16> {
367 self.in_buffer::<u16>(pos)?;
368 Ok(u16::from_le_bytes([self.buffer[pos], self.buffer[pos + 1]]))
369 }
370 #[inline]
371 fn get_uoffset(&mut self, pos: usize) -> Result<UOffsetT> {
372 self.in_buffer::<u32>(pos)?;
373 Ok(u32::from_le_bytes([
374 self.buffer[pos],
375 self.buffer[pos + 1],
376 self.buffer[pos + 2],
377 self.buffer[pos + 3],
378 ]))
379 }
380 #[inline]
381 fn deref_soffset(&mut self, pos: usize) -> Result<usize> {
382 self.in_buffer::<SOffsetT>(pos)?;
383 let offset = SOffsetT::from_le_bytes([
384 self.buffer[pos],
385 self.buffer[pos + 1],
386 self.buffer[pos + 2],
387 self.buffer[pos + 3],
388 ]);
389
390 let derefed = if offset > 0 {
392 pos.checked_sub(offset.unsigned_abs() as usize)
393 } else {
394 pos.checked_add(offset.unsigned_abs() as usize)
395 };
396 if let Some(x) = derefed {
397 if x < self.buffer.len() {
398 return Ok(x);
399 }
400 }
401 Err(InvalidFlatbuffer::SignedOffsetOutOfBounds {
402 soffset: offset,
403 position: pos,
404 error_trace: Default::default(),
405 })
406 }
407 #[inline]
408 pub fn visit_table<'ver>(
409 &'ver mut self,
410 table_pos: usize,
411 ) -> Result<TableVerifier<'ver, 'opts, 'buf>> {
412 let vtable_pos = self.deref_soffset(table_pos)?;
413 let vtable_len = self.get_u16(vtable_pos)? as usize;
414 self.is_aligned::<VOffsetT>(vtable_pos.saturating_add(vtable_len))?; self.range_in_buffer(vtable_pos, vtable_len)?;
416 self.num_tables += 1;
418 if self.num_tables > self.opts.max_tables {
419 return Err(InvalidFlatbuffer::TooManyTables);
420 }
421 self.depth += 1;
422 if self.depth > self.opts.max_depth {
423 return Err(InvalidFlatbuffer::DepthLimitReached);
424 }
425 Ok(TableVerifier {
426 pos: table_pos,
427 vtable: vtable_pos,
428 vtable_len,
429 verifier: self,
430 })
431 }
432
433 pub fn verify_union_variant<T: Verifiable>(
436 &mut self,
437 variant: &'static str,
438 position: usize,
439 ) -> Result<()> {
440 let res = T::run_verifier(self, position);
441 append_trace(res, ErrorTraceDetail::UnionVariant { variant, position })
442 }
443}
444
445pub struct TableVerifier<'ver, 'opts, 'buf> {
448 pos: usize,
450 vtable: usize,
452 vtable_len: usize,
454 verifier: &'ver mut Verifier<'opts, 'buf>,
456}
457
458impl<'ver, 'opts, 'buf> TableVerifier<'ver, 'opts, 'buf> {
459 fn deref(&mut self, field: VOffsetT) -> Result<Option<usize>> {
460 let field = field as usize;
461 if field < self.vtable_len {
462 let field_offset = self.verifier.get_u16(self.vtable.saturating_add(field))?;
463 if field_offset > 0 {
464 let field_pos = self.pos.saturating_add(field_offset as usize);
466 return Ok(Some(field_pos));
467 }
468 }
469 Ok(None)
470 }
471
472 #[inline]
473 pub fn visit_field<T: Verifiable>(
474 mut self,
475 field_name: &'static str,
476 field: VOffsetT,
477 required: bool,
478 ) -> Result<Self> {
479 if let Some(field_pos) = self.deref(field)? {
480 trace_field(
481 T::run_verifier(self.verifier, field_pos),
482 field_name,
483 field_pos,
484 )?;
485 return Ok(self);
486 }
487 if required {
488 InvalidFlatbuffer::new_missing_required(field_name)
489 } else {
490 Ok(self)
491 }
492 }
493 #[inline]
494 pub fn visit_union<Key, UnionVerifier>(
498 mut self,
499 key_field_name: &'static str,
500 key_field_voff: VOffsetT,
501 val_field_name: &'static str,
502 val_field_voff: VOffsetT,
503 required: bool,
504 verify_union: UnionVerifier,
505 ) -> Result<Self>
506 where
507 Key: Follow<'buf> + Verifiable,
508 UnionVerifier:
509 (core::ops::FnOnce(<Key as Follow<'buf>>::Inner, &mut Verifier, usize) -> Result<()>),
510 {
512 let val_pos = self.deref(val_field_voff)?;
514 let key_pos = self.deref(key_field_voff)?;
515 match (key_pos, val_pos) {
516 (None, None) => {
517 if required {
518 InvalidFlatbuffer::new_missing_required(val_field_name)
519 } else {
520 Ok(self)
521 }
522 }
523 (Some(k), Some(v)) => {
524 trace_field(Key::run_verifier(self.verifier, k), key_field_name, k)?;
525 let discriminant = unsafe { Key::follow(self.verifier.buffer, k) };
528 trace_field(
529 verify_union(discriminant, self.verifier, v),
530 val_field_name,
531 v,
532 )?;
533 Ok(self)
534 }
535 _ => InvalidFlatbuffer::new_inconsistent_union(key_field_name, val_field_name),
536 }
537 }
538 pub fn finish(self) -> &'ver mut Verifier<'opts, 'buf> {
539 self.verifier.depth -= 1;
540 self.verifier
541 }
542}
543
544pub trait Verifiable {
547 fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()>;
550}
551
552impl<T: Verifiable> Verifiable for ForwardsUOffset<T> {
554 #[inline]
555 fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
556 let offset = v.get_uoffset(pos)? as usize;
557 let next_pos = offset.saturating_add(pos);
558 T::run_verifier(v, next_pos)
559 }
560}
561
562fn verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<core::ops::Range<usize>> {
564 let len = v.get_uoffset(pos)? as usize;
565 let start = pos.saturating_add(SIZE_UOFFSET);
566 v.is_aligned::<T>(start)?;
567 let size = len.saturating_mul(core::mem::size_of::<T>());
568 let end = start.saturating_add(size);
569 v.range_in_buffer(start, size)?;
570 Ok(core::ops::Range { start, end })
571}
572
573pub trait SimpleToVerifyInSlice {}
574
575impl SimpleToVerifyInSlice for bool {}
576
577impl SimpleToVerifyInSlice for i8 {}
578
579impl SimpleToVerifyInSlice for u8 {}
580
581impl SimpleToVerifyInSlice for i16 {}
582
583impl SimpleToVerifyInSlice for u16 {}
584
585impl SimpleToVerifyInSlice for i32 {}
586
587impl SimpleToVerifyInSlice for u32 {}
588
589impl SimpleToVerifyInSlice for f32 {}
590
591impl SimpleToVerifyInSlice for i64 {}
592
593impl SimpleToVerifyInSlice for u64 {}
594
595impl SimpleToVerifyInSlice for f64 {}
596
597impl<T: SimpleToVerifyInSlice> Verifiable for Vector<'_, T> {
598 fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
599 verify_vector_range::<T>(v, pos)?;
600 Ok(())
601 }
602}
603
604impl<T: Verifiable> Verifiable for SkipSizePrefix<T> {
605 #[inline]
606 fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
607 T::run_verifier(v, pos.saturating_add(crate::SIZE_SIZEPREFIX))
608 }
609}
610
611impl<T: Verifiable> Verifiable for Vector<'_, ForwardsUOffset<T>> {
612 #[inline]
613 fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
614 let range = verify_vector_range::<ForwardsUOffset<T>>(v, pos)?;
615 let size = core::mem::size_of::<ForwardsUOffset<T>>();
616 for (i, element_pos) in range.step_by(size).enumerate() {
617 trace_elem(
618 <ForwardsUOffset<T>>::run_verifier(v, element_pos),
619 i,
620 element_pos,
621 )?;
622 }
623 Ok(())
624 }
625}
626
627impl<'a> Verifiable for &'a str {
628 #[inline]
629 fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
630 let range = verify_vector_range::<u8>(v, pos)?;
631 let has_null_terminator = v.buffer.get(range.end).map(|&b| b == 0).unwrap_or(false);
632 let s = core::str::from_utf8(&v.buffer[range.clone()]);
633 if let Err(error) = s {
634 return Err(InvalidFlatbuffer::Utf8Error {
635 error,
636 range,
637 error_trace: Default::default(),
638 });
639 }
640 if !v.opts.ignore_missing_null_terminator && !has_null_terminator {
641 return Err(InvalidFlatbuffer::MissingNullTerminator {
642 range,
643 error_trace: Default::default(),
644 });
645 }
646 Ok(())
647 }
648}
649
650macro_rules! impl_verifiable_for {
652 ($T: ty) => {
653 impl Verifiable for $T {
654 #[inline]
655 fn run_verifier<'opts, 'buf>(v: &mut Verifier<'opts, 'buf>, pos: usize) -> Result<()> {
656 v.in_buffer::<$T>(pos)
657 }
658 }
659 };
660}
661impl_verifiable_for!(bool);
662impl_verifiable_for!(u8);
663impl_verifiable_for!(i8);
664impl_verifiable_for!(u16);
665impl_verifiable_for!(i16);
666impl_verifiable_for!(u32);
667impl_verifiable_for!(i32);
668impl_verifiable_for!(f32);
669impl_verifiable_for!(u64);
670impl_verifiable_for!(i64);
671impl_verifiable_for!(f64);