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