• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::follow::Follow;
2 use crate::{ForwardsUOffset, SOffsetT, SkipSizePrefix, UOffsetT, VOffsetT, Vector, SIZE_UOFFSET};
3 #[cfg(not(feature = "std"))]
4 use alloc::vec::Vec;
5 use core::ops::Range;
6 use core::option::Option;
7 
8 #[cfg(not(feature = "std"))]
9 use alloc::borrow::Cow;
10 #[cfg(feature = "std")]
11 use std::borrow::Cow;
12 
13 #[cfg(all(nightly, not(feature = "std")))]
14 use core::error::Error;
15 #[cfg(feature = "std")]
16 use std::error::Error;
17 
18 /// Traces the location of data errors. Not populated for Dos detecting errors.
19 /// Useful for MissingRequiredField and Utf8Error in particular, though
20 /// the other errors should not be producible by correct flatbuffers implementations.
21 #[derive(Clone, Debug, PartialEq, Eq)]
22 pub enum ErrorTraceDetail {
23     VectorElement {
24         index: usize,
25         position: usize,
26     },
27     TableField {
28         field_name: Cow<'static, str>,
29         position: usize,
30     },
31     UnionVariant {
32         variant: Cow<'static, str>,
33         position: usize,
34     },
35 }
36 
37 #[derive(PartialEq, Eq, Default, Debug, Clone)]
38 pub struct ErrorTrace(Vec<ErrorTraceDetail>);
39 
40 impl core::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace {
41     #[inline]
as_ref(&self) -> &[ErrorTraceDetail]42     fn as_ref(&self) -> &[ErrorTraceDetail] {
43         &self.0
44     }
45 }
46 
47 /// Describes how a flatuffer is invalid and, for data errors, roughly where. No extra tracing
48 /// information is given for DoS detecting errors since it will probably be a lot.
49 #[derive(Clone, Debug, PartialEq, Eq)]
50 pub enum InvalidFlatbuffer {
51     MissingRequiredField {
52         required: Cow<'static, str>,
53         error_trace: ErrorTrace,
54     },
55     InconsistentUnion {
56         field: Cow<'static, str>,
57         field_type: Cow<'static, str>,
58         error_trace: ErrorTrace,
59     },
60     Utf8Error {
61         error: core::str::Utf8Error,
62         range: Range<usize>,
63         error_trace: ErrorTrace,
64     },
65     MissingNullTerminator {
66         range: Range<usize>,
67         error_trace: ErrorTrace,
68     },
69     Unaligned {
70         position: usize,
71         unaligned_type: Cow<'static, str>,
72         error_trace: ErrorTrace,
73     },
74     RangeOutOfBounds {
75         range: Range<usize>,
76         error_trace: ErrorTrace,
77     },
78     SignedOffsetOutOfBounds {
79         soffset: SOffsetT,
80         position: usize,
81         error_trace: ErrorTrace,
82     },
83     // Dos detecting errors. These do not get error traces since it will probably be very large.
84     TooManyTables,
85     ApparentSizeTooLarge,
86     DepthLimitReached,
87 }
88 
89 #[cfg(any(nightly, feature = "std"))]
90 impl Error for InvalidFlatbuffer {
source(&self) -> Option<&(dyn Error + 'static)>91     fn source(&self) -> Option<&(dyn Error + 'static)> {
92         if let InvalidFlatbuffer::Utf8Error { error: source, .. } = self {
93             Some(source)
94         } else {
95             None
96         }
97     }
98 }
99 
100 impl core::fmt::Display for InvalidFlatbuffer {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result101     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
102         match self {
103             InvalidFlatbuffer::MissingRequiredField {
104                 required,
105                 error_trace,
106             } => {
107                 writeln!(f, "Missing required field `{}`.\n{}", required, error_trace)?;
108             }
109             InvalidFlatbuffer::InconsistentUnion {
110                 field,
111                 field_type,
112                 error_trace,
113             } => {
114                 writeln!(
115                     f,
116                     "Exactly one of union discriminant (`{}`) and value (`{}`) are present.\n{}",
117                     field_type, field, error_trace
118                 )?;
119             }
120             InvalidFlatbuffer::Utf8Error {
121                 error,
122                 range,
123                 error_trace,
124             } => {
125                 writeln!(
126                     f,
127                     "Utf8 error for string in {:?}: {}\n{}",
128                     range, error, error_trace
129                 )?;
130             }
131             InvalidFlatbuffer::MissingNullTerminator { range, error_trace } => {
132                 writeln!(
133                     f,
134                     "String in range [{}, {}) is missing its null terminator.\n{}",
135                     range.start, range.end, error_trace
136                 )?;
137             }
138             InvalidFlatbuffer::Unaligned {
139                 position,
140                 unaligned_type,
141                 error_trace,
142             } => {
143                 writeln!(
144                     f,
145                     "Type `{}` at position {} is unaligned.\n{}",
146                     unaligned_type, position, error_trace
147                 )?;
148             }
149             InvalidFlatbuffer::RangeOutOfBounds { range, error_trace } => {
150                 writeln!(
151                     f,
152                     "Range [{}, {}) is out of bounds.\n{}",
153                     range.start, range.end, error_trace
154                 )?;
155             }
156             InvalidFlatbuffer::SignedOffsetOutOfBounds {
157                 soffset,
158                 position,
159                 error_trace,
160             } => {
161                 writeln!(
162                     f,
163                     "Signed offset at position {} has value {} which points out of bounds.\n{}",
164                     position, soffset, error_trace
165                 )?;
166             }
167             InvalidFlatbuffer::TooManyTables {} => {
168                 writeln!(f, "Too many tables.")?;
169             }
170             InvalidFlatbuffer::ApparentSizeTooLarge {} => {
171                 writeln!(f, "Apparent size too large.")?;
172             }
173             InvalidFlatbuffer::DepthLimitReached {} => {
174                 writeln!(f, "Nested table depth limit reached.")?;
175             }
176         }
177         Ok(())
178     }
179 }
180 
181 impl core::fmt::Display for ErrorTrace {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result182     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
183         use ErrorTraceDetail::*;
184         for e in self.0.iter() {
185             match e {
186                 VectorElement { index, position } => {
187                     writeln!(
188                         f,
189                         "\twhile verifying vector element {:?} at position {:?}",
190                         index, position
191                     )?;
192                 }
193                 TableField {
194                     field_name,
195                     position,
196                 } => {
197                     writeln!(
198                         f,
199                         "\twhile verifying table field `{}` at position {:?}",
200                         field_name, position
201                     )?;
202                 }
203                 UnionVariant { variant, position } => {
204                     writeln!(
205                         f,
206                         "\t while verifying union variant `{}` at position {:?}",
207                         variant, position
208                     )?;
209                 }
210             }
211         }
212         Ok(())
213     }
214 }
215 
216 pub type Result<T> = core::result::Result<T, InvalidFlatbuffer>;
217 
218 impl InvalidFlatbuffer {
new_range_oob<T>(start: usize, end: usize) -> Result<T>219     fn new_range_oob<T>(start: usize, end: usize) -> Result<T> {
220         Err(Self::RangeOutOfBounds {
221             range: Range { start, end },
222             error_trace: Default::default(),
223         })
224     }
new_inconsistent_union<T>( field: impl Into<Cow<'static, str>>, field_type: impl Into<Cow<'static, str>>, ) -> Result<T>225     pub fn new_inconsistent_union<T>(
226         field: impl Into<Cow<'static, str>>,
227         field_type: impl Into<Cow<'static, str>>,
228     ) -> Result<T> {
229         Err(Self::InconsistentUnion {
230             field: field.into(),
231             field_type: field_type.into(),
232             error_trace: Default::default(),
233         })
234     }
new_missing_required<T>(required: impl Into<Cow<'static, str>>) -> Result<T>235     pub fn new_missing_required<T>(required: impl Into<Cow<'static, str>>) -> Result<T> {
236         Err(Self::MissingRequiredField {
237             required: required.into(),
238             error_trace: Default::default(),
239         })
240     }
241 }
242 
243 /// Records the path to the verifier detail if the error is a data error and not a DoS error.
append_trace<T>(mut res: Result<T>, d: ErrorTraceDetail) -> Result<T>244 fn append_trace<T>(mut res: Result<T>, d: ErrorTraceDetail) -> Result<T> {
245     if let Err(e) = res.as_mut() {
246         use InvalidFlatbuffer::*;
247         if let MissingRequiredField { error_trace, .. }
248         | Unaligned { error_trace, .. }
249         | RangeOutOfBounds { error_trace, .. }
250         | InconsistentUnion { error_trace, .. }
251         | Utf8Error { error_trace, .. }
252         | MissingNullTerminator { error_trace, .. }
253         | SignedOffsetOutOfBounds { error_trace, .. } = e
254         {
255             error_trace.0.push(d)
256         }
257     }
258     res
259 }
260 
261 /// Adds a TableField trace detail if `res` is a data error.
trace_field<T>(res: Result<T>, field_name: Cow<'static, str>, position: usize) -> Result<T>262 fn trace_field<T>(res: Result<T>, field_name: Cow<'static, str>, position: usize) -> Result<T> {
263     append_trace(
264         res,
265         ErrorTraceDetail::TableField {
266             field_name,
267             position,
268         },
269     )
270 }
271 
272 /// Adds a TableField trace detail if `res` is a data error.
trace_elem<T>(res: Result<T>, index: usize, position: usize) -> Result<T>273 fn trace_elem<T>(res: Result<T>, index: usize, position: usize) -> Result<T> {
274     append_trace(res, ErrorTraceDetail::VectorElement { index, position })
275 }
276 
277 #[derive(Debug, Clone, PartialEq, Eq)]
278 pub struct VerifierOptions {
279     /// Maximum depth of nested tables allowed in a valid flatbuffer.
280     pub max_depth: usize,
281     /// Maximum number of tables allowed in a valid flatbuffer.
282     pub max_tables: usize,
283     /// Maximum "apparent" size of the message if the Flatbuffer object DAG is expanded into a
284     /// tree.
285     pub max_apparent_size: usize,
286     /// Ignore errors where a string is missing its null terminator.
287     /// This is mostly a problem if the message will be sent to a client using old c-strings.
288     pub ignore_missing_null_terminator: bool,
289     // probably want an option to ignore utf8 errors since strings come from c++
290     // options to error un-recognized enums and unions? possible footgun.
291     // Ignore nested flatbuffers, etc?
292 }
293 
294 impl Default for VerifierOptions {
default() -> Self295     fn default() -> Self {
296         Self {
297             max_depth: 64,
298             max_tables: 1_000_000,
299             // size_ might do something different.
300             max_apparent_size: 1 << 31,
301             ignore_missing_null_terminator: false,
302         }
303     }
304 }
305 
306 /// Carries the verification state. Should not be reused between tables.
307 #[derive(Debug)]
308 pub struct Verifier<'opts, 'buf> {
309     buffer: &'buf [u8],
310     opts: &'opts VerifierOptions,
311     depth: usize,
312     num_tables: usize,
313     apparent_size: usize,
314 }
315 
316 impl<'opts, 'buf> Verifier<'opts, 'buf> {
new(opts: &'opts VerifierOptions, buffer: &'buf [u8]) -> Self317     pub fn new(opts: &'opts VerifierOptions, buffer: &'buf [u8]) -> Self {
318         Self {
319             opts,
320             buffer,
321             depth: 0,
322             num_tables: 0,
323             apparent_size: 0,
324         }
325     }
326     /// Resets verifier internal state.
327     #[inline]
reset(&mut self)328     pub fn reset(&mut self) {
329         self.depth = 0;
330         self.num_tables = 0;
331         self.num_tables = 0;
332     }
333     /// Checks `pos` is aligned to T's alignment. This does not mean `buffer[pos]` is aligned w.r.t
334     /// memory since `buffer: &[u8]` has alignment 1.
335     ///
336     /// ### WARNING
337     ///
338     /// This does not work for flatbuffers-structs as they have alignment 1 according to
339     /// `core::mem::align_of` but are meant to have higher alignment within a Flatbuffer w.r.t.
340     /// `buffer[0]`. TODO(caspern).
341     ///
342     /// Note this does not impact soundness as this crate does not assume alignment of structs
343     #[inline]
is_aligned<T>(&self, pos: usize) -> Result<()>344     pub fn is_aligned<T>(&self, pos: usize) -> Result<()> {
345         if pos % core::mem::align_of::<T>() == 0 {
346             Ok(())
347         } else {
348             Err(InvalidFlatbuffer::Unaligned {
349                 unaligned_type: Cow::Borrowed(core::any::type_name::<T>()),
350                 position: pos,
351                 error_trace: Default::default(),
352             })
353         }
354     }
355     #[inline]
range_in_buffer(&mut self, pos: usize, size: usize) -> Result<()>356     pub fn range_in_buffer(&mut self, pos: usize, size: usize) -> Result<()> {
357         let end = pos.saturating_add(size);
358         if end > self.buffer.len() {
359             return InvalidFlatbuffer::new_range_oob(pos, end);
360         }
361         self.apparent_size += size;
362         if self.apparent_size > self.opts.max_apparent_size {
363             return Err(InvalidFlatbuffer::ApparentSizeTooLarge);
364         }
365         Ok(())
366     }
367     /// Check that there really is a T in there.
368     #[inline]
in_buffer<T>(&mut self, pos: usize) -> Result<()>369     pub fn in_buffer<T>(&mut self, pos: usize) -> Result<()> {
370         self.is_aligned::<T>(pos)?;
371         self.range_in_buffer(pos, core::mem::size_of::<T>())
372     }
373     #[inline]
get_u8(&mut self, pos: usize) -> Result<u8>374     pub fn get_u8(&mut self, pos: usize) -> Result<u8> {
375         self.in_buffer::<u8>(pos)?;
376         Ok(u8::from_le_bytes([self.buffer[pos]]))
377     }
378     #[inline]
get_u16(&mut self, pos: usize) -> Result<u16>379     fn get_u16(&mut self, pos: usize) -> Result<u16> {
380         self.in_buffer::<u16>(pos)?;
381         Ok(u16::from_le_bytes([self.buffer[pos], self.buffer[pos + 1]]))
382     }
383     #[inline]
get_uoffset(&mut self, pos: usize) -> Result<UOffsetT>384     pub fn get_uoffset(&mut self, pos: usize) -> Result<UOffsetT> {
385         self.in_buffer::<u32>(pos)?;
386         Ok(u32::from_le_bytes([
387             self.buffer[pos],
388             self.buffer[pos + 1],
389             self.buffer[pos + 2],
390             self.buffer[pos + 3],
391         ]))
392     }
393     #[inline]
deref_soffset(&mut self, pos: usize) -> Result<usize>394     fn deref_soffset(&mut self, pos: usize) -> Result<usize> {
395         self.in_buffer::<SOffsetT>(pos)?;
396         let offset = SOffsetT::from_le_bytes([
397             self.buffer[pos],
398             self.buffer[pos + 1],
399             self.buffer[pos + 2],
400             self.buffer[pos + 3],
401         ]);
402 
403         // signed offsets are subtracted.
404         let derefed = if offset > 0 {
405             pos.checked_sub(offset.unsigned_abs() as usize)
406         } else {
407             pos.checked_add(offset.unsigned_abs() as usize)
408         };
409         if let Some(x) = derefed {
410             if x < self.buffer.len() {
411                 return Ok(x);
412             }
413         }
414         Err(InvalidFlatbuffer::SignedOffsetOutOfBounds {
415             soffset: offset,
416             position: pos,
417             error_trace: Default::default(),
418         })
419     }
420     #[inline]
visit_table<'ver>( &'ver mut self, table_pos: usize, ) -> Result<TableVerifier<'ver, 'opts, 'buf>>421     pub fn visit_table<'ver>(
422         &'ver mut self,
423         table_pos: usize,
424     ) -> Result<TableVerifier<'ver, 'opts, 'buf>> {
425         let vtable_pos = self.deref_soffset(table_pos)?;
426         let vtable_len = self.get_u16(vtable_pos)? as usize;
427         self.is_aligned::<VOffsetT>(vtable_pos.saturating_add(vtable_len))?; // i.e. vtable_len is even.
428         self.range_in_buffer(vtable_pos, vtable_len)?;
429         // Check bounds.
430         self.num_tables += 1;
431         if self.num_tables > self.opts.max_tables {
432             return Err(InvalidFlatbuffer::TooManyTables);
433         }
434         self.depth += 1;
435         if self.depth > self.opts.max_depth {
436             return Err(InvalidFlatbuffer::DepthLimitReached);
437         }
438         Ok(TableVerifier {
439             pos: table_pos,
440             vtable: vtable_pos,
441             vtable_len,
442             verifier: self,
443         })
444     }
445 
446     /// Runs the union variant's type's verifier assuming the variant is at the given position,
447     /// tracing the error.
verify_union_variant<T: Verifiable>( &mut self, variant: impl Into<Cow<'static, str>>, position: usize, ) -> Result<()>448     pub fn verify_union_variant<T: Verifiable>(
449         &mut self,
450         variant: impl Into<Cow<'static, str>>,
451         position: usize,
452     ) -> Result<()> {
453         let res = T::run_verifier(self, position);
454         append_trace(
455             res,
456             ErrorTraceDetail::UnionVariant {
457                 variant: variant.into(),
458                 position,
459             },
460         )
461     }
462 }
463 
464 // Cache table metadata in usize so we don't have to cast types or jump around so much.
465 // We will visit every field anyway.
466 pub struct TableVerifier<'ver, 'opts, 'buf> {
467     // Absolute position of table in buffer
468     pos: usize,
469     // Absolute position of vtable in buffer.
470     vtable: usize,
471     // Length of vtable.
472     vtable_len: usize,
473     // Verifier struct which holds the surrounding state and options.
474     verifier: &'ver mut Verifier<'opts, 'buf>,
475 }
476 
477 impl<'ver, 'opts, 'buf> TableVerifier<'ver, 'opts, 'buf> {
deref(&mut self, field: VOffsetT) -> Result<Option<usize>>478     pub fn deref(&mut self, field: VOffsetT) -> Result<Option<usize>> {
479         let field = field as usize;
480         if field < self.vtable_len {
481             let field_offset = self.verifier.get_u16(self.vtable.saturating_add(field))?;
482             if field_offset > 0 {
483                 // Field is present.
484                 let field_pos = self.pos.saturating_add(field_offset as usize);
485                 return Ok(Some(field_pos));
486             }
487         }
488         Ok(None)
489     }
490 
491     #[inline]
verifier(&mut self) -> &mut Verifier<'opts, 'buf>492     pub fn verifier(&mut self) -> &mut Verifier<'opts, 'buf> {
493         self.verifier
494     }
495 
496     #[inline]
visit_field<T: Verifiable>( mut self, field_name: impl Into<Cow<'static, str>>, field: VOffsetT, required: bool, ) -> Result<Self>497     pub fn visit_field<T: Verifiable>(
498         mut self,
499         field_name: impl Into<Cow<'static, str>>,
500         field: VOffsetT,
501         required: bool,
502     ) -> Result<Self> {
503         if let Some(field_pos) = self.deref(field)? {
504             trace_field(
505                 T::run_verifier(self.verifier, field_pos),
506                 field_name.into(),
507                 field_pos,
508             )?;
509             return Ok(self);
510         }
511         if required {
512             InvalidFlatbuffer::new_missing_required(field_name.into())
513         } else {
514             Ok(self)
515         }
516     }
517     #[inline]
518     /// Union verification is complicated. The schemas passes this function the metadata of the
519     /// union's key (discriminant) and value fields, and a callback. The function verifies and
520     /// reads the key, then invokes the callback to perform data-dependent verification.
visit_union<Key, UnionVerifier>( mut self, key_field_name: impl Into<Cow<'static, str>>, key_field_voff: VOffsetT, val_field_name: impl Into<Cow<'static, str>>, val_field_voff: VOffsetT, required: bool, verify_union: UnionVerifier, ) -> Result<Self> where Key: Follow<'buf> + Verifiable, UnionVerifier: (core::ops::FnOnce(<Key as Follow<'buf>>::Inner, &mut Verifier, usize) -> Result<()>),521     pub fn visit_union<Key, UnionVerifier>(
522         mut self,
523         key_field_name: impl Into<Cow<'static, str>>,
524         key_field_voff: VOffsetT,
525         val_field_name: impl Into<Cow<'static, str>>,
526         val_field_voff: VOffsetT,
527         required: bool,
528         verify_union: UnionVerifier,
529     ) -> Result<Self>
530     where
531         Key: Follow<'buf> + Verifiable,
532         UnionVerifier:
533             (core::ops::FnOnce(<Key as Follow<'buf>>::Inner, &mut Verifier, usize) -> Result<()>),
534         // NOTE: <Key as Follow<'buf>>::Inner == Key
535     {
536         // TODO(caspern): how to trace vtable errors?
537         let val_pos = self.deref(val_field_voff)?;
538         let key_pos = self.deref(key_field_voff)?;
539         match (key_pos, val_pos) {
540             (None, None) => {
541                 if required {
542                     InvalidFlatbuffer::new_missing_required(val_field_name.into())
543                 } else {
544                     Ok(self)
545                 }
546             }
547             (Some(k), Some(v)) => {
548                 trace_field(
549                     Key::run_verifier(self.verifier, k),
550                     key_field_name.into(),
551                     k,
552                 )?;
553                 // Safety:
554                 // Run verifier on `k` above
555                 let discriminant = unsafe { Key::follow(self.verifier.buffer, k) };
556                 trace_field(
557                     verify_union(discriminant, self.verifier, v),
558                     val_field_name.into(),
559                     v,
560                 )?;
561                 Ok(self)
562             }
563             _ => InvalidFlatbuffer::new_inconsistent_union(key_field_name.into(), val_field_name.into()),
564         }
565     }
finish(self) -> &'ver mut Verifier<'opts, 'buf>566     pub fn finish(self) -> &'ver mut Verifier<'opts, 'buf> {
567         self.verifier.depth -= 1;
568         self.verifier
569     }
570 }
571 
572 // Needs to be implemented for Tables and maybe structs.
573 // Unions need some special treatment.
574 pub trait Verifiable {
575     /// Runs the verifier for this type, assuming its at position `pos` in the verifier's buffer.
576     /// Should not need to be called directly.
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>577     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()>;
578 }
579 
580 // Verify the uoffset and then pass verifier to the type being pointed to.
581 impl<T: Verifiable> Verifiable for ForwardsUOffset<T> {
582     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>583     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
584         let offset = v.get_uoffset(pos)? as usize;
585         let next_pos = offset.saturating_add(pos);
586         T::run_verifier(v, next_pos)
587     }
588 }
589 
590 /// Checks and returns the range containing the flatbuffers vector.
verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<core::ops::Range<usize>>591 fn verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<core::ops::Range<usize>> {
592     let len = v.get_uoffset(pos)? as usize;
593     let start = pos.saturating_add(SIZE_UOFFSET);
594     v.is_aligned::<T>(start)?;
595     let size = len.saturating_mul(core::mem::size_of::<T>());
596     let end = start.saturating_add(size);
597     v.range_in_buffer(start, size)?;
598     Ok(core::ops::Range { start, end })
599 }
600 
601 pub trait SimpleToVerifyInSlice {}
602 
603 impl SimpleToVerifyInSlice for bool {}
604 
605 impl SimpleToVerifyInSlice for i8 {}
606 
607 impl SimpleToVerifyInSlice for u8 {}
608 
609 impl SimpleToVerifyInSlice for i16 {}
610 
611 impl SimpleToVerifyInSlice for u16 {}
612 
613 impl SimpleToVerifyInSlice for i32 {}
614 
615 impl SimpleToVerifyInSlice for u32 {}
616 
617 impl SimpleToVerifyInSlice for f32 {}
618 
619 impl SimpleToVerifyInSlice for i64 {}
620 
621 impl SimpleToVerifyInSlice for u64 {}
622 
623 impl SimpleToVerifyInSlice for f64 {}
624 
625 impl<T: SimpleToVerifyInSlice> Verifiable for Vector<'_, T> {
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>626     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
627         verify_vector_range::<T>(v, pos)?;
628         Ok(())
629     }
630 }
631 
632 impl<T: Verifiable> Verifiable for SkipSizePrefix<T> {
633     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>634     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
635         T::run_verifier(v, pos.saturating_add(crate::SIZE_SIZEPREFIX))
636     }
637 }
638 
639 impl<T: Verifiable> Verifiable for Vector<'_, ForwardsUOffset<T>> {
640     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>641     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
642         let range = verify_vector_range::<ForwardsUOffset<T>>(v, pos)?;
643         let size = core::mem::size_of::<ForwardsUOffset<T>>();
644         for (i, element_pos) in range.step_by(size).enumerate() {
645             trace_elem(
646                 <ForwardsUOffset<T>>::run_verifier(v, element_pos),
647                 i,
648                 element_pos,
649             )?;
650         }
651         Ok(())
652     }
653 }
654 
655 impl<'a> Verifiable for &'a str {
656     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>657     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
658         let range = verify_vector_range::<u8>(v, pos)?;
659         let has_null_terminator = v.buffer.get(range.end).map(|&b| b == 0).unwrap_or(false);
660         let s = core::str::from_utf8(&v.buffer[range.clone()]);
661         if let Err(error) = s {
662             return Err(InvalidFlatbuffer::Utf8Error {
663                 error,
664                 range,
665                 error_trace: Default::default(),
666             });
667         }
668         if !v.opts.ignore_missing_null_terminator && !has_null_terminator {
669             return Err(InvalidFlatbuffer::MissingNullTerminator {
670                 range,
671                 error_trace: Default::default(),
672             });
673         }
674         Ok(())
675     }
676 }
677 
678 // Verify VectorOfTables, Unions, Arrays, Structs...
679 macro_rules! impl_verifiable_for {
680     ($T: ty) => {
681         impl Verifiable for $T {
682             #[inline]
683             fn run_verifier<'opts, 'buf>(v: &mut Verifier<'opts, 'buf>, pos: usize) -> Result<()> {
684                 v.in_buffer::<$T>(pos)
685             }
686         }
687     };
688 }
689 impl_verifiable_for!(bool);
690 impl_verifiable_for!(u8);
691 impl_verifiable_for!(i8);
692 impl_verifiable_for!(u16);
693 impl_verifiable_for!(i16);
694 impl_verifiable_for!(u32);
695 impl_verifiable_for!(i32);
696 impl_verifiable_for!(f32);
697 impl_verifiable_for!(u64);
698 impl_verifiable_for!(i64);
699 impl_verifiable_for!(f64);
700