Branch data Line data Source code
1 : : /*
2 : : * Runtime support for verifying flatbuffers.
3 : : *
4 : : * Depends mutually on generated verifier functions for table types that
5 : : * call into this library.
6 : : */
7 : : #include <assert.h>
8 : : #include <string.h>
9 : :
10 : : #include "flatcc/flatcc_rtconfig.h"
11 : : #include "flatcc/flatcc_flatbuffers.h"
12 : : #include "flatcc/flatcc_verifier.h"
13 : :
14 : : /* Customization for testing. */
15 : : #if FLATCC_DEBUG_VERIFY
16 : : #define FLATCC_VERIFIER_ASSERT_ON_ERROR 1
17 : : #include <stdio.h>
18 : : #define FLATCC_VERIFIER_ASSERT(cond, reason) \
19 : : if (!(cond)) { fprintf(stderr, "verifier assert: %s\n", \
20 : : flatcc_verify_error_string(reason)); assert(0); return reason; }
21 : : #endif
22 : :
23 : : #ifdef FLATCC_TRACE_VERIFY
24 : : #include <stdio.h>
25 : : #define trace_verify(s, p) \
26 : : fprintf(stderr, "trace verify: %s: 0x%02x\n", (s), (unsigned)(size_t)(p));
27 : : #else
28 : : #define trace_verify(s, p) ((void)0)
29 : : #endif
30 : :
31 : : /* The runtime library does not use the global config file. */
32 : :
33 : : /* This is a guideline, not an exact measure. */
34 : : #ifndef FLATCC_VERIFIER_MAX_LEVELS
35 : : #define FLATCC_VERIFIER_MAX_LEVELS 100
36 : : #endif
37 : :
38 : : #ifndef FLATCC_VERIFIER_ASSERT_ON_ERROR
39 : : #define FLATCC_VERIFIER_ASSERT_ON_ERROR 0
40 : : #endif
41 : :
42 : : /*
43 : : * Generally a check should tell if a buffer is valid or not such
44 : : * that runtime can take appropriate actions rather than crash,
45 : : * also in debug, but assertions are helpful in debugging a problem.
46 : : *
47 : : * This must be compiled into the debug runtime library to take effect.
48 : : */
49 : : #ifndef FLATCC_VERIFIER_ASSERT_ON_ERROR
50 : : #define FLATCC_VERIFIER_ASSERT_ON_ERROR 1
51 : : #endif
52 : :
53 : : /* May be redefined for logging purposes. */
54 : : #ifndef FLATCC_VERIFIER_ASSERT
55 : : #define FLATCC_VERIFIER_ASSERT(cond, reason) assert(cond)
56 : : #endif
57 : :
58 : : #if FLATCC_VERIFIER_ASSERT_ON_ERROR
59 : : #define flatcc_verify(cond, reason) if (!(cond)) { FLATCC_VERIFIER_ASSERT(cond, reason); return reason; }
60 : : #else
61 : : #define flatcc_verify(cond, reason) if (!(cond)) { return reason; }
62 : : #endif
63 : :
64 : :
65 : : #define uoffset_t flatbuffers_uoffset_t
66 : : #define soffset_t flatbuffers_soffset_t
67 : : #define voffset_t flatbuffers_voffset_t
68 : : #define thash_t flatbuffers_thash_t
69 : :
70 : : #define uoffset_size sizeof(uoffset_t)
71 : : #define soffset_size sizeof(soffset_t)
72 : : #define voffset_size sizeof(voffset_t)
73 : : #define thash_size sizeof(thash_t)
74 : : #define offset_size uoffset_size
75 : :
76 [ # # ]: 0 : const char *flatcc_verify_error_string(int err)
77 : : {
78 : : switch (err) {
79 : : #define XX(no, str) \
80 : : case flatcc_verify_error_##no: \
81 : : return str;
82 : : FLATCC_VERIFY_ERROR_MAP(XX)
83 : : #undef XX
84 : : default:
85 : : return "unknown";
86 : : }
87 : : }
88 : :
89 : : /* `cond` may have side effects. */
90 : : #define verify(cond, reason) do { int c = (cond); flatcc_verify(c, reason); } while(0)
91 : :
92 : : /*
93 : : * Identify checks related to runtime conditions (buffer size and
94 : : * alignment) as seperate from those related to buffer content.
95 : : */
96 : : #define verify_runtime(cond, reason) verify(cond, reason)
97 : :
98 : : #define check_result(x) if (x) { return (x); }
99 : :
100 : : #define check_field(td, id, required, base) do { \
101 : : int ret = get_offset_field(td, id, required, &base); \
102 : : if (ret || !base) { return ret; }} while (0)
103 : :
104 : : static inline uoffset_t read_uoffset(const void *p, uoffset_t base)
105 : : {
106 : 408 : return __flatbuffers_uoffset_read_from_pe((uint8_t *)p + base);
107 : : }
108 : :
109 : : static inline thash_t read_thash_identifier(const char *identifier)
110 : : {
111 : 58 : flatbuffers_thash_t id = 0;
112 : 58 : strncpy((char *)&id, identifier, sizeof(id));
113 : 58 : return __flatbuffers_thash_cast_from_le(id);
114 : : }
115 : :
116 : : static inline thash_t read_thash(const void *p, uoffset_t base)
117 : : {
118 : : return __flatbuffers_thash_read_from_pe((uint8_t *)p + base);
119 : : }
120 : :
121 : : static inline voffset_t read_voffset(const void *p, uoffset_t base)
122 : : {
123 : 886 : return __flatbuffers_voffset_read_from_pe((uint8_t *)p + base);
124 : : }
125 : :
126 : : static inline int check_header(uoffset_t end, uoffset_t base, uoffset_t offset)
127 : : {
128 : 209 : uoffset_t k = base + offset;
129 : :
130 : : if (uoffset_size <= voffset_size && k + offset_size < k) {
131 : : return 0;
132 : : }
133 : :
134 : : /* The `k > base` rather than `k >= base` is to avoid null offsets. */
135 [ + - ][ + - ]: 209 : return k > base && k + offset_size <= end && !(k & (offset_size - 1));
[ - + ][ + - ]
[ + - ][ - + ]
136 : : }
137 : :
138 : : static inline int check_aligned_header(uoffset_t end, uoffset_t base, uoffset_t offset, uint16_t align)
139 : : {
140 : 21 : uoffset_t k = base + offset;
141 : :
142 : : if (uoffset_size <= voffset_size && k + offset_size < k) {
143 : : return 0;
144 : : }
145 : :
146 : : /* Note to self: the builder can also use the mask OR trick to propagate `min_align`. */
147 [ + - ][ + - ]: 21 : return k > base && k + offset_size <= end && !(k & ((offset_size - 1) | (align - 1)));
[ - + ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
[ # # ]
148 : : }
149 : :
150 : : static inline int verify_struct(uoffset_t end, uoffset_t base, uint16_t align, uoffset_t size)
151 : : {
152 : : verify(uoffset_size <= voffset_size && base + size < base, flatcc_verify_error_struct_size_overflow);
153 : : verify(base > 0 && base + size <= end, flatcc_verify_error_struct_out_of_range);
154 : : verify (!(base & (align - 1)), flatcc_verify_error_struct_unaligned);
155 : : return flatcc_verify_ok;
156 : : }
157 : :
158 : : static inline uoffset_t read_vt_entry(flatcc_table_verifier_descriptor_t *td, voffset_t id)
159 : : {
160 : 2498 : voffset_t vo = (id + 2) * sizeof(voffset_t);
161 : :
162 : : /* Assumes tsize has been verified for alignment. */
163 [ + + ][ + + ]: 2498 : if (vo >= td->vsize) {
[ + - ][ + + ]
[ # # ][ + + ]
[ + + ]
164 : : return 0;
165 : : }
166 : 681 : return read_voffset(td->vtable, vo);
167 : : }
168 : :
169 : : static inline const void *get_field_ptr(flatcc_table_verifier_descriptor_t *td, voffset_t id)
170 : : {
171 : 95 : voffset_t vte = read_vt_entry(td, id);
172 [ + + ][ # # ]: 95 : return vte ? (const uint8_t *)td->buf + td->table + vte : 0;
173 : : }
174 : :
175 : : static int verify_field(flatcc_table_verifier_descriptor_t *td,
176 : : voffset_t id, int required, uint16_t align, uoffset_t size)
177 : : {
178 : : uoffset_t k, k2;
179 : : voffset_t vte;
180 : 1259 : uoffset_t base = (uoffset_t)(size_t)td->buf;
181 : :
182 : :
183 : : /*
184 : : * Otherwise range check assumptions break, and normal access code likely also.
185 : : * We don't require voffset_size < uoffset_size, but some checks are faster if true.
186 : : */
187 : : assert(uoffset_size >= voffset_size);
188 : : assert(soffset_size == uoffset_size);
189 : :
190 : 1245 : vte = read_vt_entry(td, id);
191 [ + + ][ # # ]: 1245 : if (!vte) {
192 : : verify(!required, flatcc_verify_error_required_field_missing);
193 : : return flatcc_verify_ok;
194 : : }
195 : : trace_verify("table buffer", td->buf);
196 : : trace_verify("table", td->table);
197 : : trace_verify("id", id);
198 : : trace_verify("vte", vte);
199 : :
200 : : /*
201 : : * Note that we don't add td.table to k and we test against table
202 : : * size not table end or buffer end. Otherwise it would not be safe
203 : : * to optimized out the k <= k2 check for normal uoffset and voffset
204 : : * configurations.
205 : : */
206 : : k = vte;
207 : 74 : k2 = k + size;
208 [ + - ][ # # ]: 74 : verify(k2 <= td->tsize, flatcc_verify_error_table_field_out_of_range);
[ + - ][ # # ]
209 : : /* This normally optimizes to nop. */
210 : : verify(uoffset_size > voffset_size || k <= k2, flatcc_verify_error_table_field_size_overflow);
211 : : trace_verify("table + vte", vte + td->table);
212 : 60 : k += td->table + base;
213 : : trace_verify("entry: buf + table + vte", k);
214 : : trace_verify("align", align);
215 : : trace_verify("align masked entry", k & (align - 1));
216 [ + - ][ # # ]: 60 : verify(!(k & (align - 1)), flatcc_verify_error_table_field_not_aligned);
217 : : /* We assume the table size has already been verified. */
218 : : return flatcc_verify_ok;
219 : : }
220 : :
221 : 968 : static int get_offset_field(flatcc_table_verifier_descriptor_t *td, voffset_t id, int required, uoffset_t *out)
222 : : {
223 : : uoffset_t k, k2;
224 : : voffset_t vte;
225 : :
226 : 1936 : vte = read_vt_entry(td, id);
227 [ + + ]: 968 : if (!vte) {
228 : 831 : *out = 0;
229 [ + - ]: 831 : if (required) {
230 : : return flatcc_verify_error_required_field_missing;
231 : : }
232 : : /* Missing, but not invalid. */
233 : 831 : return flatcc_verify_ok;
234 : : }
235 : : /*
236 : : * Note that we don't add td.table to k and we test against table
237 : : * size not table end or buffer end. Otherwise it would not be safe
238 : : * to optimized out the k <= k2 check for normal uoffset and voffset
239 : : * configurations.
240 : : */
241 : : k = vte;
242 : 137 : k2 = k + offset_size;
243 [ + - ]: 137 : verify(k2 <= td->tsize, flatcc_verify_error_table_field_out_of_range);
244 : : /* This normally optimizes to nop. */
245 : : verify(uoffset_size > voffset_size || k <= k2, flatcc_verify_error_table_field_size_overflow);
246 : 137 : k += td->table;
247 [ + - ]: 137 : verify(!(k & (offset_size - 1)), flatcc_verify_error_table_field_not_aligned);
248 : : /* We assume the table size has already been verified. */
249 : 137 : *out = k;
250 : 137 : return flatcc_verify_ok;
251 : : }
252 : :
253 : 106 : static inline int verify_string(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset)
254 : : {
255 : : uoffset_t n;
256 : :
257 [ + - ]: 106 : verify(check_header(end, base, offset), flatcc_verify_error_table_offset_out_of_range_or_unaligned);
258 : : base += offset;
259 : : n = read_uoffset(buf, base);
260 : 106 : base += offset_size;
261 [ + - ]: 106 : verify(end - base >= n + 1, flatcc_verify_error_string_out_of_range);
262 [ + - ]: 106 : verify(((uint8_t *)buf + base)[n] == 0, flatcc_verify_error_string_not_zero_terminated);
263 : 106 : return flatcc_verify_ok;
264 : : }
265 : :
266 : : /*
267 : : * Keep interface somwewhat similar ot flatcc_builder_start_vector.
268 : : * `max_count` is a precomputed division to manage overflow check on vector length.
269 : : */
270 : : static inline int verify_vector(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset, uint16_t align, uoffset_t elem_size, uoffset_t max_count)
271 : : {
272 : : uoffset_t n;
273 : :
274 [ + - ][ + - ]: 21 : verify(check_aligned_header(end, base, offset, align), flatcc_verify_error_table_header_out_of_range_or_unaligned);
[ # # ][ + - ]
[ # # ]
275 : : base += offset;
276 : : n = read_uoffset(buf, base);
277 : 21 : base += offset_size;
278 : : /* `n * elem_size` can overflow uncontrollably otherwise. */
279 [ + - ][ + - ]: 21 : verify(n <= max_count, flatcc_verify_error_vector_count_exceeds_representable_vector_size);
[ # # ][ + - ]
[ # # ]
280 [ + - ][ + - ]: 21 : verify(end - base >= n * elem_size, flatcc_verify_error_vector_out_of_range);
[ # # ][ + - ]
[ # # ]
281 : : return flatcc_verify_ok;
282 : : }
283 : :
284 : 4 : static inline int verify_string_vector(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset)
285 : : {
286 : : uoffset_t i, n;
287 : :
288 [ - + ]: 4 : check_result(verify_vector(buf, end, base, offset, offset_size, offset_size, FLATBUFFERS_COUNT_MAX(offset_size)));
289 : : base += offset;
290 : : n = read_uoffset(buf, base);
291 : 4 : base += offset_size;
292 [ + + ]: 14 : for (i = 0; i < n; ++i, base += offset_size) {
293 [ + - ]: 10 : check_result(verify_string(buf, end, base, read_uoffset(buf, base)));
294 : : }
295 : : return flatcc_verify_ok;
296 : : }
297 : :
298 : 103 : static inline int verify_table(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset, int ttl, flatcc_table_verifier_f tvf)
299 : : {
300 : : uoffset_t vbase, vend;
301 : : flatcc_table_verifier_descriptor_t td;
302 : :
303 [ + - ]: 103 : verify((td.ttl = ttl - 1), flatcc_verify_error_max_nesting_level_reached);
304 [ + - ]: 103 : verify(check_header(end, base, offset), flatcc_verify_error_table_header_out_of_range_or_unaligned);
305 : 103 : td.table = base + offset;
306 : : /* Read vtable offset - it is signed, but we want it unsigned, assuming 2's complement works. */
307 : 103 : vbase = td.table - read_uoffset(buf, td.table);
308 [ + - ][ - + ]: 103 : verify((soffset_t)vbase >= 0 && !(vbase & (voffset_size - 1)), flatcc_verify_error_vtable_offset_out_of_range_or_unaligned);
[ + - ]
309 [ + - ]: 103 : verify(vbase + voffset_size <= end, flatcc_verify_error_vtable_header_out_of_range);
310 : : /* Read vtable size. */
311 : 103 : td.vsize = read_voffset(buf, vbase);
312 : 103 : vend = vbase + td.vsize;
313 [ + + ][ - + ]: 103 : verify(vend <= end && !(td.vsize & (voffset_size - 1)), flatcc_verify_error_vtable_size_out_of_range_or_unaligned);
[ + + ]
314 : : /* Optimizes away overflow check if uoffset_t is large enough. */
315 : : verify(uoffset_size > voffset_size || vend >= vbase, flatcc_verify_error_vtable_size_overflow);
316 : :
317 [ + - ]: 102 : verify(td.vsize >= 2 * voffset_size, flatcc_verify_error_vtable_header_too_small);
318 : : /* Read table size. */
319 : 204 : td.tsize = read_voffset(buf, vbase + voffset_size);
320 [ + - ]: 102 : verify(end - td.table >= td.tsize, flatcc_verify_error_table_size_out_of_range);
321 : 102 : td.vtable = (uint8_t *)buf + vbase;
322 : 102 : td.buf = buf;
323 : 102 : td.end = end;
324 : 102 : return tvf(&td);
325 : : }
326 : :
327 : 5 : static inline int verify_table_vector(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset, int ttl, flatcc_table_verifier_f tvf)
328 : : {
329 : : uoffset_t i, n;
330 : :
331 [ + - ]: 5 : verify(ttl-- > 0, flatcc_verify_error_max_nesting_level_reached);
332 [ - + ]: 5 : check_result(verify_vector(buf, end, base, offset, offset_size, offset_size, FLATBUFFERS_COUNT_MAX(offset_size)));
333 : : base += offset;
334 : : n = read_uoffset(buf, base);
335 : 5 : base += offset_size;
336 [ + + ]: 27 : for (i = 0; i < n; ++i, base += offset_size) {
337 [ - + ]: 22 : check_result(verify_table(buf, end, base, read_uoffset(buf, base), ttl, tvf));
338 : : }
339 : : return flatcc_verify_ok;
340 : : }
341 : :
342 : 1245 : int flatcc_verify_field(flatcc_table_verifier_descriptor_t *td,
343 : : voffset_t id, uint16_t align, size_t size)
344 : : {
345 [ - + ]: 1245 : check_result(verify_field(td, id, 0, align, (uoffset_t)size));
346 : : return flatcc_verify_ok;
347 : : }
348 : :
349 : 99 : int flatcc_verify_string_field(flatcc_table_verifier_descriptor_t *td,
350 : : voffset_t id, int required)
351 : : {
352 : : uoffset_t base;
353 : :
354 [ + - ][ + + ]: 99 : check_field(td, id, required, base);
355 : 96 : return verify_string(td->buf, td->end, base, read_uoffset(td->buf, base));
356 : : }
357 : :
358 : 380 : int flatcc_verify_vector_field(flatcc_table_verifier_descriptor_t *td,
359 : : voffset_t id, int required, uint16_t align, size_t elem_size, size_t max_count)
360 : : {
361 : : uoffset_t base;
362 : :
363 [ + - ][ + + ]: 380 : check_field(td, id, required, base);
364 : 24 : return verify_vector(td->buf, td->end, base, read_uoffset(td->buf, base),
365 : : align, (uoffset_t)elem_size, (uoffset_t)max_count);
366 : : }
367 : :
368 : 95 : int flatcc_verify_string_vector_field(flatcc_table_verifier_descriptor_t *td,
369 : : voffset_t id, int required)
370 : : {
371 : : uoffset_t base;
372 : :
373 [ + - ][ + + ]: 95 : check_field(td, id, required, base);
374 : 4 : return verify_string_vector(td->buf, td->end, base, read_uoffset(td->buf, base));
375 : : }
376 : :
377 : 299 : int flatcc_verify_table_field(flatcc_table_verifier_descriptor_t *td,
378 : : voffset_t id, int required, flatcc_table_verifier_f tvf)
379 : : {
380 : : uoffset_t base;
381 : :
382 [ + - ][ + + ]: 299 : check_field(td, id, required, base);
383 : 20 : return verify_table(td->buf, td->end, base, read_uoffset(td->buf, base), td->ttl, tvf);
384 : : }
385 : :
386 : 95 : int flatcc_verify_table_vector_field(flatcc_table_verifier_descriptor_t *td,
387 : : voffset_t id, int required, flatcc_table_verifier_f tvf)
388 : : {
389 : : uoffset_t base;
390 : :
391 [ + - ][ + + ]: 95 : check_field(td, id, required, base);
392 : 5 : return verify_table_vector(td->buf, td->end, base, read_uoffset(td->buf, base), td->ttl, tvf);
393 : : }
394 : :
395 : 60 : int flatcc_verify_buffer_header(const void *buf, size_t bufsiz, const char *fid)
396 : : {
397 : : thash_t id, id2;
398 : :
399 [ + - ]: 60 : verify_runtime(!(((size_t)buf) & (offset_size - 1)), flatcc_verify_error_runtime_buffer_header_not_aligned);
400 : : /* -8 ensures no scalar or offset field size can overflow. */
401 [ + - ]: 60 : verify_runtime(bufsiz <= FLATBUFFERS_UOFFSET_MAX - 8, flatcc_verify_error_runtime_buffer_size_too_large);
402 : : /*
403 : : * Even if we specify no fid, the user might later. Therefore
404 : : * require space for it. Not all buffer generators will take this
405 : : * into account, so it is possible to fail an otherwise valid buffer
406 : : * - but such buffers aren't safe.
407 : : */
408 [ + - ]: 60 : verify(bufsiz >= offset_size + FLATBUFFERS_IDENTIFIER_SIZE, flatcc_verify_error_buffer_header_too_small);
409 [ + + ]: 60 : if (fid != 0) {
410 : : id2 = read_thash_identifier(fid);
411 : : id = read_thash(buf, offset_size);
412 [ + + ]: 58 : verify(id2 == 0 || id == id2, flatcc_verify_error_identifier_mismatch);
413 : : }
414 : : return flatcc_verify_ok;
415 : : }
416 : :
417 : 0 : int flatcc_verify_typed_buffer_header(const void *buf, size_t bufsiz, flatbuffers_thash_t thash)
418 : : {
419 : : thash_t id, id2;
420 : :
421 [ + - ][ # # ]: 5 : verify_runtime(!(((size_t)buf) & (offset_size - 1)), flatcc_verify_error_runtime_buffer_header_not_aligned);
[ + - ][ # # ]
[ # # ]
422 : : /* -8 ensures no scalar or offset field size can overflow. */
423 [ + - ][ # # ]: 5 : verify_runtime(bufsiz <= FLATBUFFERS_UOFFSET_MAX - 8, flatcc_verify_error_runtime_buffer_size_too_large);
[ + - ][ # # ]
[ # # ]
424 : : /*
425 : : * Even if we specify no fid, the user might later. Therefore
426 : : * require space for it. Not all buffer generators will take this
427 : : * into account, so it is possible to fail an otherwise valid buffer
428 : : * - but such buffers aren't safe.
429 : : */
430 [ + - ][ # # ]: 5 : verify(bufsiz >= offset_size + FLATBUFFERS_IDENTIFIER_SIZE, flatcc_verify_error_buffer_header_too_small);
[ + - ][ # # ]
[ # # ]
431 [ + - ][ # # ]: 5 : if (thash != 0) {
[ + - ][ # # ]
[ # # ]
432 : : id2 = thash;
433 : : id = read_thash(buf, offset_size);
434 [ + - ][ # # ]: 5 : verify(id2 == 0 || id == id2, flatcc_verify_error_identifier_mismatch);
[ + - ][ # # ]
[ # # ]
435 : : }
436 : : return flatcc_verify_ok;
437 : : }
438 : :
439 : 0 : int flatcc_verify_struct_as_root(const void *buf, size_t bufsiz, const char *fid, uint16_t align, size_t size)
440 : : {
441 [ # # ]: 0 : check_result(flatcc_verify_buffer_header(buf, bufsiz, fid));
442 : : return verify_struct((uoffset_t)bufsiz, read_uoffset(buf, 0), align, (uoffset_t)size);
443 : : }
444 : :
445 : 2 : int flatcc_verify_struct_as_typed_root(const void *buf, size_t bufsiz, flatbuffers_thash_t thash, uint16_t align, size_t size)
446 : : {
447 [ - + ]: 2 : check_result(flatcc_verify_typed_buffer_header(buf, bufsiz, thash));
448 : : return verify_struct((uoffset_t)bufsiz, read_uoffset(buf, 0), align, (uoffset_t)size);
449 : : }
450 : :
451 : 57 : int flatcc_verify_table_as_root(const void *buf, size_t bufsiz, const char *fid, flatcc_table_verifier_f *tvf)
452 : : {
453 [ + + ]: 57 : check_result(flatcc_verify_buffer_header(buf, (uoffset_t)bufsiz, fid));
454 : 56 : return verify_table(buf, (uoffset_t)bufsiz, 0, read_uoffset(buf, 0), FLATCC_VERIFIER_MAX_LEVELS, tvf);
455 : : }
456 : :
457 : 3 : int flatcc_verify_table_as_typed_root(const void *buf, size_t bufsiz, flatbuffers_thash_t thash, flatcc_table_verifier_f *tvf)
458 : : {
459 [ - + ]: 3 : check_result(flatcc_verify_typed_buffer_header(buf, (uoffset_t)bufsiz, thash));
460 : 3 : return verify_table(buf, (uoffset_t)bufsiz, 0, read_uoffset(buf, 0), FLATCC_VERIFIER_MAX_LEVELS, tvf);
461 : : }
462 : :
463 : 0 : int flatcc_verify_struct_as_nested_root(flatcc_table_verifier_descriptor_t *td,
464 : : voffset_t id, int required, const char *fid, uint16_t align, size_t size)
465 : : {
466 : : const uoffset_t *buf;
467 : : uoffset_t bufsiz;
468 : :
469 [ # # ]: 0 : check_result(flatcc_verify_vector_field(td, id, required, align, 1, FLATBUFFERS_COUNT_MAX(1)));
470 [ # # ]: 0 : if (0 == (buf = get_field_ptr(td, id))) {
471 : : return flatcc_verify_ok;
472 : : }
473 : 0 : buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0));
474 : : bufsiz = read_uoffset(buf, 0);
475 : 0 : ++buf;
476 : 0 : return flatcc_verify_struct_as_root(buf, bufsiz, fid, align, size);
477 : : }
478 : :
479 : 95 : int flatcc_verify_table_as_nested_root(flatcc_table_verifier_descriptor_t *td,
480 : : voffset_t id, int required, const char *fid,
481 : : uint16_t align, flatcc_table_verifier_f tvf)
482 : : {
483 : : const uoffset_t *buf;
484 : : uoffset_t bufsiz;
485 : :
486 [ - + ]: 95 : check_result(flatcc_verify_vector_field(td, id, required, align, 1, FLATBUFFERS_COUNT_MAX(1)));
487 [ + + ]: 95 : if (0 == (buf = get_field_ptr(td, id))) {
488 : : return flatcc_verify_ok;
489 : : }
490 : 2 : buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0));
491 : : bufsiz = read_uoffset(buf, 0);
492 : 2 : ++buf;
493 : : /*
494 : : * Don't verify nested buffers identifier - information is difficult to get and
495 : : * might not be what is desired anyway. User can do it later.
496 : : */
497 [ - + ]: 2 : check_result(flatcc_verify_buffer_header(buf, bufsiz, fid));
498 : 2 : return verify_table(buf, bufsiz, 0, read_uoffset(buf, 0), td->ttl, tvf);
499 : : }
500 : :
501 : 95 : int flatcc_verify_union_field(flatcc_table_verifier_descriptor_t *td,
502 : : voffset_t id, int required, flatcc_union_verifier_f *uvf)
503 : : {
504 : : voffset_t vte_type, vte_table;
505 : : const uint8_t *type;
506 : :
507 [ + + ]: 95 : if (0 == (vte_type = read_vt_entry(td, id - 1))) {
508 : 162 : vte_table = read_vt_entry(td, id);
509 [ + - ]: 81 : verify(vte_table == 0, flatcc_verify_error_union_cannot_have_a_table_without_a_type);
510 [ + - ]: 81 : verify(!required, flatcc_verify_error_type_field_absent_from_required_union_field);
511 : 81 : return flatcc_verify_ok;
512 : : }
513 : : /* No need to check required here. */
514 [ - + ]: 14 : check_result(verify_field(td, id - 1, 0, 1, 1));
515 : : /* Only now is it safe to read the type. */
516 : 28 : vte_table = read_vt_entry(td, id);
517 : 14 : type = (const uint8_t *)td->buf + td->table + vte_type;
518 [ - + ][ # # ]: 14 : verify(*type || vte_table == 0, flatcc_verify_error_union_type_NONE_cannot_have_a_table);
[ + - ]
519 : 14 : return uvf(td, id, *type);
520 : : }
|