verifier.c (22835B)
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 <string.h> 8 9 #include "flatcc/flatcc_rtconfig.h" 10 #include "flatcc/flatcc_flatbuffers.h" 11 #include "flatcc/flatcc_verifier.h" 12 #include "flatcc/flatcc_identifier.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)); FLATCC_ASSERT(0); return reason; } 21 #endif 22 23 #if 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) FLATCC_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 utype_t flatbuffers_utype_t 69 #define thash_t flatbuffers_thash_t 70 71 #define uoffset_size sizeof(uoffset_t) 72 #define soffset_size sizeof(soffset_t) 73 #define voffset_size sizeof(voffset_t) 74 #define utype_size sizeof(utype_t) 75 #define thash_size sizeof(thash_t) 76 #define offset_size uoffset_size 77 78 const char *flatcc_verify_error_string(int err) 79 { 80 switch (err) { 81 #define XX(no, str) \ 82 case flatcc_verify_error_##no: \ 83 return str; 84 FLATCC_VERIFY_ERROR_MAP(XX) 85 #undef XX 86 default: 87 return "unknown"; 88 } 89 } 90 91 /* `cond` may have side effects. */ 92 #define verify(cond, reason) do { int c = (cond); flatcc_verify(c, reason); } while(0) 93 94 /* 95 * Identify checks related to runtime conditions (buffer size and 96 * alignment) as seperate from those related to buffer content. 97 */ 98 #define verify_runtime(cond, reason) verify(cond, reason) 99 100 #define check_result(x) if (x) { return (x); } 101 102 #define check_field(td, id, required, base) do { \ 103 int ret = get_offset_field(td, id, required, &base); \ 104 if (ret || !base) { return ret; }} while (0) 105 106 static inline uoffset_t read_uoffset(const void *p, uoffset_t base) 107 { 108 return __flatbuffers_uoffset_read_from_pe((uint8_t *)p + base); 109 } 110 111 static inline thash_t read_thash_identifier(const char *identifier) 112 { 113 return flatbuffers_type_hash_from_string(identifier); 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 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 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 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 uoffset_t k = base + offset; 141 142 if (uoffset_size <= voffset_size && k + offset_size < k) { 143 return 0; 144 } 145 /* Alignment refers to element 0 and header must also be aligned. */ 146 align = align < uoffset_size ? uoffset_size : align; 147 148 /* Note to self: the builder can also use the mask OR trick to propagate `min_align`. */ 149 return k > base && k + offset_size <= end && !((k + offset_size) & ((offset_size - 1) | (align - 1u))); 150 } 151 152 static inline int verify_struct(uoffset_t end, uoffset_t base, uoffset_t offset, uoffset_t size, uint16_t align) 153 { 154 /* Structs can have zero size so `end` is a valid value. */ 155 if (offset == 0 || base + offset > end) { 156 return flatcc_verify_error_offset_out_of_range; 157 } 158 base += offset; 159 verify(base + size >= base, flatcc_verify_error_struct_size_overflow); 160 verify(base + size <= end, flatcc_verify_error_struct_out_of_range); 161 verify (!(base & (align - 1u)), flatcc_verify_error_struct_unaligned); 162 return flatcc_verify_ok; 163 } 164 165 static inline voffset_t read_vt_entry(flatcc_table_verifier_descriptor_t *td, voffset_t id) 166 { 167 voffset_t vo = (id + 2u) * sizeof(voffset_t); 168 169 /* Assumes tsize has been verified for alignment. */ 170 if (vo >= td->vsize) { 171 return 0; 172 } 173 return read_voffset(td->vtable, vo); 174 } 175 176 static inline const void *get_field_ptr(flatcc_table_verifier_descriptor_t *td, voffset_t id) 177 { 178 voffset_t vte = read_vt_entry(td, id); 179 return vte ? (const uint8_t *)td->buf + td->table + vte : 0; 180 } 181 182 static int verify_field(flatcc_table_verifier_descriptor_t *td, 183 voffset_t id, int required, uoffset_t size, uint16_t align) 184 { 185 uoffset_t k, k2; 186 voffset_t vte; 187 uoffset_t base = (uoffset_t)(size_t)td->buf; 188 189 190 /* 191 * Otherwise range check assumptions break, and normal access code likely also. 192 * We don't require voffset_size < uoffset_size, but some checks are faster if true. 193 */ 194 FLATCC_ASSERT(uoffset_size >= voffset_size); 195 FLATCC_ASSERT(soffset_size == uoffset_size); 196 197 vte = read_vt_entry(td, id); 198 if (!vte) { 199 verify(!required, flatcc_verify_error_required_field_missing); 200 return flatcc_verify_ok; 201 } 202 trace_verify("table buffer", td->buf); 203 trace_verify("table", td->table); 204 trace_verify("id", id); 205 trace_verify("vte", vte); 206 207 /* 208 * Note that we don't add td.table to k and we test against table 209 * size not table end or buffer end. Otherwise it would not be safe 210 * to optimized out the k <= k2 check for normal uoffset and voffset 211 * configurations. 212 */ 213 k = vte; 214 k2 = k + size; 215 verify(k2 <= td->tsize, flatcc_verify_error_table_field_out_of_range); 216 /* This normally optimizes to nop. */ 217 verify(uoffset_size > voffset_size || k <= k2, flatcc_verify_error_table_field_size_overflow); 218 trace_verify("table + vte", vte + td->table); 219 k += td->table + base; 220 trace_verify("entry: buf + table + vte", k); 221 trace_verify("align", align); 222 trace_verify("align masked entry", k & (align - 1u)); 223 verify(!(k & (align - 1u)), flatcc_verify_error_table_field_not_aligned); 224 /* We assume the table size has already been verified. */ 225 return flatcc_verify_ok; 226 } 227 228 static int get_offset_field(flatcc_table_verifier_descriptor_t *td, voffset_t id, int required, uoffset_t *out) 229 { 230 uoffset_t k, k2; 231 voffset_t vte; 232 233 vte = read_vt_entry(td, id); 234 if (!vte) { 235 *out = 0; 236 if (required) { 237 return flatcc_verify_error_required_field_missing; 238 } 239 /* Missing, but not invalid. */ 240 return flatcc_verify_ok; 241 } 242 /* 243 * Note that we don't add td.table to k and we test against table 244 * size not table end or buffer end. Otherwise it would not be safe 245 * to optimized out the k <= k2 check for normal uoffset and voffset 246 * configurations. 247 */ 248 k = vte; 249 k2 = k + offset_size; 250 verify(k2 <= td->tsize, flatcc_verify_error_table_field_out_of_range); 251 /* This normally optimizes to nop. */ 252 verify(uoffset_size > voffset_size || k <= k2, flatcc_verify_error_table_field_size_overflow); 253 k += td->table; 254 verify(!(k & (offset_size - 1u)), flatcc_verify_error_table_field_not_aligned); 255 /* We assume the table size has already been verified. */ 256 *out = k; 257 return flatcc_verify_ok; 258 } 259 260 static inline int verify_string(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset) 261 { 262 uoffset_t n; 263 264 verify(check_header(end, base, offset), flatcc_verify_error_string_header_out_of_range_or_unaligned); 265 base += offset; 266 n = read_uoffset(buf, base); 267 base += offset_size; 268 verify(end - base > n, flatcc_verify_error_string_out_of_range); 269 verify(((uint8_t *)buf + base)[n] == 0, flatcc_verify_error_string_not_zero_terminated); 270 return flatcc_verify_ok; 271 } 272 273 /* 274 * Keep interface somwewhat similar ot flatcc_builder_start_vector. 275 * `max_count` is a precomputed division to manage overflow check on vector length. 276 */ 277 static inline int verify_vector(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset, uoffset_t elem_size, uint16_t align, uoffset_t max_count) 278 { 279 uoffset_t n; 280 281 verify(check_aligned_header(end, base, offset, align), flatcc_verify_error_vector_header_out_of_range_or_unaligned); 282 base += offset; 283 n = read_uoffset(buf, base); 284 base += offset_size; 285 /* `n * elem_size` can overflow uncontrollably otherwise. */ 286 verify(n <= max_count, flatcc_verify_error_vector_count_exceeds_representable_vector_size); 287 verify(end - base >= n * elem_size, flatcc_verify_error_vector_out_of_range); 288 return flatcc_verify_ok; 289 } 290 291 static inline int verify_string_vector(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset) 292 { 293 uoffset_t i, n; 294 295 check_result(verify_vector(buf, end, base, offset, offset_size, offset_size, FLATBUFFERS_COUNT_MAX(offset_size))); 296 base += offset; 297 n = read_uoffset(buf, base); 298 base += offset_size; 299 for (i = 0; i < n; ++i, base += offset_size) { 300 check_result(verify_string(buf, end, base, read_uoffset(buf, base))); 301 } 302 return flatcc_verify_ok; 303 } 304 305 static inline int verify_table(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset, 306 int ttl, flatcc_table_verifier_f tvf) 307 { 308 uoffset_t vbase, vend; 309 flatcc_table_verifier_descriptor_t td; 310 311 verify((td.ttl = ttl - 1), flatcc_verify_error_max_nesting_level_reached); 312 verify(check_header(end, base, offset), flatcc_verify_error_table_header_out_of_range_or_unaligned); 313 td.table = base + offset; 314 /* Read vtable offset - it is signed, but we want it unsigned, assuming 2's complement works. */ 315 vbase = td.table - read_uoffset(buf, td.table); 316 verify((soffset_t)vbase >= 0 && !(vbase & (voffset_size - 1)), flatcc_verify_error_vtable_offset_out_of_range_or_unaligned); 317 verify(vbase + voffset_size <= end, flatcc_verify_error_vtable_header_out_of_range); 318 /* Read vtable size. */ 319 td.vsize = read_voffset(buf, vbase); 320 vend = vbase + td.vsize; 321 verify(vend <= end && !(td.vsize & (voffset_size - 1)), flatcc_verify_error_vtable_size_out_of_range_or_unaligned); 322 /* Optimizes away overflow check if uoffset_t is large enough. */ 323 verify(uoffset_size > voffset_size || vend >= vbase, flatcc_verify_error_vtable_size_overflow); 324 325 verify(td.vsize >= 2 * voffset_size, flatcc_verify_error_vtable_header_too_small); 326 /* Read table size. */ 327 td.tsize = read_voffset(buf, vbase + voffset_size); 328 verify(end - td.table >= td.tsize, flatcc_verify_error_table_size_out_of_range); 329 td.vtable = (uint8_t *)buf + vbase; 330 td.buf = buf; 331 td.end = end; 332 return tvf(&td); 333 } 334 335 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) 336 { 337 uoffset_t i, n; 338 339 verify(ttl-- > 0, flatcc_verify_error_max_nesting_level_reached); 340 check_result(verify_vector(buf, end, base, offset, offset_size, offset_size, FLATBUFFERS_COUNT_MAX(offset_size))); 341 base += offset; 342 n = read_uoffset(buf, base); 343 base += offset_size; 344 for (i = 0; i < n; ++i, base += offset_size) { 345 check_result(verify_table(buf, end, base, read_uoffset(buf, base), ttl, tvf)); 346 } 347 return flatcc_verify_ok; 348 } 349 350 static inline int verify_union_vector(const void *buf, uoffset_t end, uoffset_t base, uoffset_t offset, 351 uoffset_t count, const utype_t *types, int ttl, flatcc_union_verifier_f uvf) 352 { 353 uoffset_t i, n, elem; 354 flatcc_union_verifier_descriptor_t ud; 355 356 verify(ttl-- > 0, flatcc_verify_error_max_nesting_level_reached); 357 check_result(verify_vector(buf, end, base, offset, offset_size, offset_size, FLATBUFFERS_COUNT_MAX(offset_size))); 358 base += offset; 359 n = read_uoffset(buf, base); 360 verify(n == count, flatcc_verify_error_union_vector_length_mismatch); 361 base += offset_size; 362 363 ud.buf = buf; 364 ud.end = end; 365 ud.ttl = ttl; 366 367 for (i = 0; i < n; ++i, base += offset_size) { 368 /* Table vectors can never be null, but unions can when the type is NONE. */ 369 elem = read_uoffset(buf, base); 370 if (elem == 0) { 371 verify(types[i] == 0, flatcc_verify_error_union_element_absent_without_type_NONE); 372 } else { 373 verify(types[i] != 0, flatcc_verify_error_union_element_present_with_type_NONE); 374 ud.type = types[i]; 375 ud.base = base; 376 ud.offset = elem; 377 check_result(uvf(&ud)); 378 } 379 } 380 return flatcc_verify_ok; 381 } 382 383 int flatcc_verify_field(flatcc_table_verifier_descriptor_t *td, 384 voffset_t id, size_t size, uint16_t align) 385 { 386 check_result(verify_field(td, id, 0, (uoffset_t)size, align)); 387 return flatcc_verify_ok; 388 } 389 390 int flatcc_verify_string_field(flatcc_table_verifier_descriptor_t *td, 391 voffset_t id, int required) 392 { 393 uoffset_t base; 394 395 check_field(td, id, required, base); 396 return verify_string(td->buf, td->end, base, read_uoffset(td->buf, base)); 397 } 398 399 int flatcc_verify_vector_field(flatcc_table_verifier_descriptor_t *td, 400 voffset_t id, int required, size_t elem_size, uint16_t align, size_t max_count) 401 { 402 uoffset_t base; 403 404 check_field(td, id, required, base); 405 return verify_vector(td->buf, td->end, base, read_uoffset(td->buf, base), 406 (uoffset_t)elem_size, align, (uoffset_t)max_count); 407 } 408 409 int flatcc_verify_string_vector_field(flatcc_table_verifier_descriptor_t *td, 410 voffset_t id, int required) 411 { 412 uoffset_t base; 413 414 check_field(td, id, required, base); 415 return verify_string_vector(td->buf, td->end, base, read_uoffset(td->buf, base)); 416 } 417 418 int flatcc_verify_table_field(flatcc_table_verifier_descriptor_t *td, 419 voffset_t id, int required, flatcc_table_verifier_f tvf) 420 { 421 uoffset_t base; 422 423 check_field(td, id, required, base); 424 return verify_table(td->buf, td->end, base, read_uoffset(td->buf, base), td->ttl, tvf); 425 } 426 427 int flatcc_verify_table_vector_field(flatcc_table_verifier_descriptor_t *td, 428 voffset_t id, int required, flatcc_table_verifier_f tvf) 429 { 430 uoffset_t base; 431 432 check_field(td, id, required, base); 433 return verify_table_vector(td->buf, td->end, base, read_uoffset(td->buf, base), td->ttl, tvf); 434 } 435 436 int flatcc_verify_union_table(flatcc_union_verifier_descriptor_t *ud, flatcc_table_verifier_f *tvf) 437 { 438 return verify_table(ud->buf, ud->end, ud->base, ud->offset, ud->ttl, tvf); 439 } 440 441 int flatcc_verify_union_struct(flatcc_union_verifier_descriptor_t *ud, size_t size, uint16_t align) 442 { 443 return verify_struct(ud->end, ud->base, ud->offset, (uoffset_t)size, align); 444 } 445 446 int flatcc_verify_union_string(flatcc_union_verifier_descriptor_t *ud) 447 { 448 return verify_string(ud->buf, ud->end, ud->base, ud->offset); 449 } 450 451 int flatcc_verify_buffer_header(const void *buf, size_t bufsiz, const char *fid) 452 { 453 thash_t id, id2; 454 455 verify_runtime(!(((size_t)buf) & (offset_size - 1)), flatcc_verify_error_runtime_buffer_header_not_aligned); 456 /* -8 ensures no scalar or offset field size can overflow. */ 457 verify_runtime(bufsiz <= FLATBUFFERS_UOFFSET_MAX - 8, flatcc_verify_error_runtime_buffer_size_too_large); 458 /* 459 * Even if we specify no fid, the user might later. Therefore 460 * require space for it. Not all buffer generators will take this 461 * into account, so it is possible to fail an otherwise valid buffer 462 * - but such buffers aren't safe. 463 */ 464 verify(bufsiz >= offset_size + FLATBUFFERS_IDENTIFIER_SIZE, flatcc_verify_error_buffer_header_too_small); 465 if (fid != 0) { 466 id2 = read_thash_identifier(fid); 467 id = read_thash(buf, offset_size); 468 verify(id2 == 0 || id == id2, flatcc_verify_error_identifier_mismatch); 469 } 470 return flatcc_verify_ok; 471 } 472 473 int flatcc_verify_typed_buffer_header(const void *buf, size_t bufsiz, flatbuffers_thash_t thash) 474 { 475 thash_t id, id2; 476 477 verify_runtime(!(((size_t)buf) & (offset_size - 1)), flatcc_verify_error_runtime_buffer_header_not_aligned); 478 /* -8 ensures no scalar or offset field size can overflow. */ 479 verify_runtime(bufsiz <= FLATBUFFERS_UOFFSET_MAX - 8, flatcc_verify_error_runtime_buffer_size_too_large); 480 /* 481 * Even if we specify no fid, the user might later. Therefore 482 * require space for it. Not all buffer generators will take this 483 * into account, so it is possible to fail an otherwise valid buffer 484 * - but such buffers aren't safe. 485 */ 486 verify(bufsiz >= offset_size + FLATBUFFERS_IDENTIFIER_SIZE, flatcc_verify_error_buffer_header_too_small); 487 if (thash != 0) { 488 id2 = thash; 489 id = read_thash(buf, offset_size); 490 verify(id2 == 0 || id == id2, flatcc_verify_error_identifier_mismatch); 491 } 492 return flatcc_verify_ok; 493 } 494 495 int flatcc_verify_struct_as_root(const void *buf, size_t bufsiz, const char *fid, size_t size, uint16_t align) 496 { 497 check_result(flatcc_verify_buffer_header(buf, bufsiz, fid)); 498 return verify_struct((uoffset_t)bufsiz, 0, read_uoffset(buf, 0), (uoffset_t)size, align); 499 } 500 501 int flatcc_verify_struct_as_typed_root(const void *buf, size_t bufsiz, flatbuffers_thash_t thash, size_t size, uint16_t align) 502 { 503 check_result(flatcc_verify_typed_buffer_header(buf, bufsiz, thash)); 504 return verify_struct((uoffset_t)bufsiz, 0, read_uoffset(buf, 0), (uoffset_t)size, align); 505 } 506 507 int flatcc_verify_table_as_root(const void *buf, size_t bufsiz, const char *fid, flatcc_table_verifier_f *tvf) 508 { 509 check_result(flatcc_verify_buffer_header(buf, (uoffset_t)bufsiz, fid)); 510 return verify_table(buf, (uoffset_t)bufsiz, 0, read_uoffset(buf, 0), FLATCC_VERIFIER_MAX_LEVELS, tvf); 511 } 512 513 int flatcc_verify_table_as_typed_root(const void *buf, size_t bufsiz, flatbuffers_thash_t thash, flatcc_table_verifier_f *tvf) 514 { 515 check_result(flatcc_verify_typed_buffer_header(buf, (uoffset_t)bufsiz, thash)); 516 return verify_table(buf, (uoffset_t)bufsiz, 0, read_uoffset(buf, 0), FLATCC_VERIFIER_MAX_LEVELS, tvf); 517 } 518 519 int flatcc_verify_struct_as_nested_root(flatcc_table_verifier_descriptor_t *td, 520 voffset_t id, int required, const char *fid, size_t size, uint16_t align) 521 { 522 const uoffset_t *buf; 523 uoffset_t bufsiz; 524 525 check_result(flatcc_verify_vector_field(td, id, required, align, 1, FLATBUFFERS_COUNT_MAX(1))); 526 if (0 == (buf = get_field_ptr(td, id))) { 527 return flatcc_verify_ok; 528 } 529 buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0)); 530 bufsiz = read_uoffset(buf, 0); 531 ++buf; 532 return flatcc_verify_struct_as_root(buf, bufsiz, fid, size, align); 533 } 534 535 int flatcc_verify_table_as_nested_root(flatcc_table_verifier_descriptor_t *td, 536 voffset_t id, int required, const char *fid, 537 uint16_t align, flatcc_table_verifier_f tvf) 538 { 539 const uoffset_t *buf; 540 uoffset_t bufsiz; 541 542 check_result(flatcc_verify_vector_field(td, id, required, align, 1, FLATBUFFERS_COUNT_MAX(1))); 543 if (0 == (buf = get_field_ptr(td, id))) { 544 return flatcc_verify_ok; 545 } 546 buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0)); 547 bufsiz = read_uoffset(buf, 0); 548 ++buf; 549 /* 550 * Don't verify nested buffers identifier - information is difficult to get and 551 * might not be what is desired anyway. User can do it later. 552 */ 553 check_result(flatcc_verify_buffer_header(buf, bufsiz, fid)); 554 return verify_table(buf, bufsiz, 0, read_uoffset(buf, 0), td->ttl, tvf); 555 } 556 557 int flatcc_verify_union_field(flatcc_table_verifier_descriptor_t *td, 558 voffset_t id, int required, flatcc_union_verifier_f uvf) 559 { 560 voffset_t vte_type, vte_table; 561 const uint8_t *type; 562 uoffset_t base; 563 flatcc_union_verifier_descriptor_t ud; 564 565 if (0 == (vte_type = read_vt_entry(td, id - 1))) { 566 vte_table = read_vt_entry(td, id); 567 verify(vte_table == 0, flatcc_verify_error_union_cannot_have_a_table_without_a_type); 568 verify(!required, flatcc_verify_error_type_field_absent_from_required_union_field); 569 return flatcc_verify_ok; 570 } 571 /* No need to check required here. */ 572 check_result(verify_field(td, id - 1, 0, 1, 1)); 573 /* Only now is it safe to read the type. */ 574 vte_table = read_vt_entry(td, id); 575 type = (const uint8_t *)td->buf + td->table + vte_type; 576 verify(*type || vte_table == 0, flatcc_verify_error_union_type_NONE_cannot_have_a_value); 577 578 if (*type == 0) { 579 return flatcc_verify_ok; 580 } 581 check_field(td, id, required, base); 582 ud.buf = td->buf; 583 ud.end = td->end; 584 ud.ttl = td->ttl; 585 ud.base = base; 586 ud.offset = read_uoffset(td->buf, base); 587 ud.type = *type; 588 return uvf(&ud); 589 } 590 591 int flatcc_verify_union_vector_field(flatcc_table_verifier_descriptor_t *td, 592 flatbuffers_voffset_t id, int required, flatcc_union_verifier_f uvf) 593 { 594 voffset_t vte_type, vte_table; 595 const uoffset_t *buf; 596 const utype_t *types; 597 uoffset_t count, base; 598 599 if (0 == (vte_type = read_vt_entry(td, id - 1))) { 600 if (0 == (vte_table = read_vt_entry(td, id))) { 601 verify(!required, flatcc_verify_error_type_field_absent_from_required_union_vector_field); 602 } 603 } 604 check_result(flatcc_verify_vector_field(td, id - 1, required, 605 utype_size, utype_size, FLATBUFFERS_COUNT_MAX(utype_size))); 606 if (0 == (buf = get_field_ptr(td, id - 1))) { 607 return flatcc_verify_ok; 608 } 609 buf = (const uoffset_t *)((size_t)buf + read_uoffset(buf, 0)); 610 count = read_uoffset(buf, 0); 611 ++buf; 612 types = (utype_t *)buf; 613 614 check_field(td, id, required, base); 615 return verify_union_vector(td->buf, td->end, base, read_uoffset(td->buf, base), 616 count, types, td->ttl, uvf); 617 }