• 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(all(nightly, not(feature = "std")))]
9 use core::error::Error;
10 #[cfg(feature = "std")]
11 use std::error::Error;
12 
13 /// Traces the location of data errors. Not populated for Dos detecting errors.
14 /// Useful for MissingRequiredField and Utf8Error in particular, though
15 /// the other errors should not be producible by correct flatbuffers implementations.
16 #[derive(Clone, Debug, PartialEq, Eq)]
17 pub 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)]
33 pub struct ErrorTrace(Vec<ErrorTraceDetail>);
34 
35 impl core::convert::AsRef<[ErrorTraceDetail]> for ErrorTrace {
36     #[inline]
as_ref(&self) -> &[ErrorTraceDetail]37     fn as_ref(&self) -> &[ErrorTraceDetail] {
38         &self.0
39     }
40 }
41 
42 /// Describes how a flatuffer is invalid and, for data errors, roughly where. No extra tracing
43 /// information is given for DoS detecting errors since it will probably be a lot.
44 #[derive(Clone, Debug, PartialEq, Eq)]
45 pub 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     // Dos detecting errors. These do not get error traces since it will probably be very large.
79     TooManyTables,
80     ApparentSizeTooLarge,
81     DepthLimitReached,
82 }
83 
84 #[cfg(any(nightly, feature = "std"))]
85 impl Error for InvalidFlatbuffer {
source(&self) -> Option<&(dyn Error + 'static)>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 
95 impl core::fmt::Display for InvalidFlatbuffer {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result96     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 
176 impl core::fmt::Display for ErrorTrace {
fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result177     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 
211 pub type Result<T> = core::result::Result<T, InvalidFlatbuffer>;
212 
213 impl InvalidFlatbuffer {
new_range_oob<T>(start: usize, end: usize) -> Result<T>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     }
new_inconsistent_union<T>(field: &'static str, field_type: &'static str) -> Result<T>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     }
new_missing_required<T>(required: &'static str) -> Result<T>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 
235 /// 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>236 fn 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 
253 /// Adds a TableField trace detail if `res` is a data error.
trace_field<T>(res: Result<T>, field_name: &'static str, position: usize) -> Result<T>254 fn 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 
264 /// Adds a TableField trace detail if `res` is a data error.
trace_elem<T>(res: Result<T>, index: usize, position: usize) -> Result<T>265 fn 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)]
270 pub struct VerifierOptions {
271     /// Maximum depth of nested tables allowed in a valid flatbuffer.
272     pub max_depth: usize,
273     /// Maximum number of tables allowed in a valid flatbuffer.
274     pub max_tables: usize,
275     /// Maximum "apparent" size of the message if the Flatbuffer object DAG is expanded into a
276     /// tree.
277     pub max_apparent_size: usize,
278     /// Ignore errors where a string is missing its null terminator.
279     /// This is mostly a problem if the message will be sent to a client using old c-strings.
280     pub ignore_missing_null_terminator: bool,
281     // probably want an option to ignore utf8 errors since strings come from c++
282     // options to error un-recognized enums and unions? possible footgun.
283     // Ignore nested flatbuffers, etc?
284 }
285 
286 impl Default for VerifierOptions {
default() -> Self287     fn default() -> Self {
288         Self {
289             max_depth: 64,
290             max_tables: 1_000_000,
291             // size_ might do something different.
292             max_apparent_size: 1 << 31,
293             ignore_missing_null_terminator: false,
294         }
295     }
296 }
297 
298 /// Carries the verification state. Should not be reused between tables.
299 #[derive(Debug)]
300 pub 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 
308 impl<'opts, 'buf> Verifier<'opts, 'buf> {
new(opts: &'opts VerifierOptions, buffer: &'buf [u8]) -> Self309     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     /// Resets verifier internal state.
319     #[inline]
reset(&mut self)320     pub fn reset(&mut self) {
321         self.depth = 0;
322         self.num_tables = 0;
323         self.num_tables = 0;
324     }
325     /// Checks `pos` is aligned to T's alignment. This does not mean `buffer[pos]` is aligned w.r.t
326     /// memory since `buffer: &[u8]` has alignment 1.
327     ///
328     /// ### WARNING
329     ///
330     /// This does not work for flatbuffers-structs as they have alignment 1 according to
331     /// `core::mem::align_of` but are meant to have higher alignment within a Flatbuffer w.r.t.
332     /// `buffer[0]`. TODO(caspern).
333     ///
334     /// Note this does not impact soundness as this crate does not assume alignment of structs
335     #[inline]
is_aligned<T>(&self, pos: usize) -> Result<()>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]
range_in_buffer(&mut self, pos: usize, size: usize) -> Result<()>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     /// Check that there really is a T in there.
360     #[inline]
in_buffer<T>(&mut self, pos: usize) -> Result<()>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]
get_u16(&mut self, pos: usize) -> Result<u16>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]
get_uoffset(&mut self, pos: usize) -> Result<UOffsetT>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]
deref_soffset(&mut self, pos: usize) -> Result<usize>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         // signed offsets are subtracted.
391         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]
visit_table<'ver>( &'ver mut self, table_pos: usize, ) -> Result<TableVerifier<'ver, 'opts, 'buf>>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))?; // i.e. vtable_len is even.
415         self.range_in_buffer(vtable_pos, vtable_len)?;
416         // Check bounds.
417         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     /// Runs the union variant's type's verifier assuming the variant is at the given position,
434     /// tracing the error.
verify_union_variant<T: Verifiable>( &mut self, variant: &'static str, position: usize, ) -> Result<()>435     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 
445 // Cache table metadata in usize so we don't have to cast types or jump around so much.
446 // We will visit every field anyway.
447 pub struct TableVerifier<'ver, 'opts, 'buf> {
448     // Absolute position of table in buffer
449     pos: usize,
450     // Absolute position of vtable in buffer.
451     vtable: usize,
452     // Length of vtable.
453     vtable_len: usize,
454     // Verifier struct which holds the surrounding state and options.
455     verifier: &'ver mut Verifier<'opts, 'buf>,
456 }
457 
458 impl<'ver, 'opts, 'buf> TableVerifier<'ver, 'opts, 'buf> {
deref(&mut self, field: VOffsetT) -> Result<Option<usize>>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                 // Field is present.
465                 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]
visit_field<T: Verifiable>( mut self, field_name: &'static str, field: VOffsetT, required: bool, ) -> Result<Self>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     /// Union verification is complicated. The schemas passes this function the metadata of the
495     /// union's key (discriminant) and value fields, and a callback. The function verifies and
496     /// reads the key, then invokes the callback to perform data-dependent verification.
visit_union<Key, UnionVerifier>( mut self, key_field_name: &'static str, key_field_voff: VOffsetT, val_field_name: &'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<()>),497     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         // NOTE: <Key as Follow<'buf>>::Inner == Key
511     {
512         // TODO(caspern): how to trace vtable errors?
513         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                 // Safety:
526                 // Run verifier on `k` above
527                 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     }
finish(self) -> &'ver mut Verifier<'opts, 'buf>538     pub fn finish(self) -> &'ver mut Verifier<'opts, 'buf> {
539         self.verifier.depth -= 1;
540         self.verifier
541     }
542 }
543 
544 // Needs to be implemented for Tables and maybe structs.
545 // Unions need some special treatment.
546 pub trait Verifiable {
547     /// Runs the verifier for this type, assuming its at position `pos` in the verifier's buffer.
548     /// Should not need to be called directly.
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>549     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()>;
550 }
551 
552 // Verify the uoffset and then pass verifier to the type being pointed to.
553 impl<T: Verifiable> Verifiable for ForwardsUOffset<T> {
554     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>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 
562 /// Checks and returns the range containing the flatbuffers vector.
verify_vector_range<T>(v: &mut Verifier, pos: usize) -> Result<core::ops::Range<usize>>563 fn 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 
573 pub trait SimpleToVerifyInSlice {}
574 
575 impl SimpleToVerifyInSlice for bool {}
576 
577 impl SimpleToVerifyInSlice for i8 {}
578 
579 impl SimpleToVerifyInSlice for u8 {}
580 
581 impl SimpleToVerifyInSlice for i16 {}
582 
583 impl SimpleToVerifyInSlice for u16 {}
584 
585 impl SimpleToVerifyInSlice for i32 {}
586 
587 impl SimpleToVerifyInSlice for u32 {}
588 
589 impl SimpleToVerifyInSlice for f32 {}
590 
591 impl SimpleToVerifyInSlice for i64 {}
592 
593 impl SimpleToVerifyInSlice for u64 {}
594 
595 impl SimpleToVerifyInSlice for f64 {}
596 
597 impl<T: SimpleToVerifyInSlice> Verifiable for Vector<'_, T> {
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>598     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
599         verify_vector_range::<T>(v, pos)?;
600         Ok(())
601     }
602 }
603 
604 impl<T: Verifiable> Verifiable for SkipSizePrefix<T> {
605     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>606     fn run_verifier(v: &mut Verifier, pos: usize) -> Result<()> {
607         T::run_verifier(v, pos.saturating_add(crate::SIZE_SIZEPREFIX))
608     }
609 }
610 
611 impl<T: Verifiable> Verifiable for Vector<'_, ForwardsUOffset<T>> {
612     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>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 
627 impl<'a> Verifiable for &'a str {
628     #[inline]
run_verifier(v: &mut Verifier, pos: usize) -> Result<()>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 
650 // Verify VectorOfTables, Unions, Arrays, Structs...
651 macro_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 }
661 impl_verifiable_for!(bool);
662 impl_verifiable_for!(u8);
663 impl_verifiable_for!(i8);
664 impl_verifiable_for!(u16);
665 impl_verifiable_for!(i16);
666 impl_verifiable_for!(u32);
667 impl_verifiable_for!(i32);
668 impl_verifiable_for!(f32);
669 impl_verifiable_for!(u64);
670 impl_verifiable_for!(i64);
671 impl_verifiable_for!(f64);
672