Branch data Line data Source code
1 : : #include <string.h>
2 : : #include <assert.h>
3 : :
4 : : #include "semantics.h"
5 : : #include "parser.h"
6 : : #include "coerce.h"
7 : :
8 : : /* Same order as enum! */
9 : : static const char *fb_known_attribute_names[] = {
10 : : "",
11 : : "id",
12 : : "deprecated",
13 : : "original_order",
14 : : "force_align",
15 : : "bit_flags",
16 : : "nested_flatbuffer",
17 : : "key",
18 : : "required",
19 : : "hash"
20 : : };
21 : :
22 : : static const int fb_known_attribute_types[] = {
23 : : vt_invalid, /* Uknowns have arbitrary types. */
24 : : vt_uint,
25 : : vt_missing,
26 : : vt_missing,
27 : : vt_uint,
28 : : vt_missing,
29 : : vt_string,
30 : : vt_missing,
31 : : vt_missing,
32 : : vt_string
33 : : };
34 : :
35 : : static fb_scalar_type_t map_scalar_token_type(fb_token_t *t)
36 : : {
37 [ + - ][ + - ]: 305 : switch (t->id) {
[ + - ]
38 : : case tok_kw_ulong:
39 : : return fb_ulong;
40 : : case tok_kw_uint:
41 : : return fb_uint;
42 : : case tok_kw_ushort:
43 : : return fb_ushort;
44 : : case tok_kw_ubyte:
45 : : return fb_ubyte;
46 : : case tok_kw_bool:
47 : : return fb_bool;
48 : : case tok_kw_long:
49 : : return fb_long;
50 : : case tok_kw_int:
51 : : return fb_int;
52 : : case tok_kw_short:
53 : : return fb_short;
54 : : case tok_kw_byte:
55 : : return fb_byte;
56 : : case tok_kw_double:
57 : : return fb_double;
58 : : case tok_kw_float:
59 : : return fb_float;
60 : : default:
61 : : return fb_missing_type;
62 : : }
63 : : }
64 : :
65 : : /*
66 : : * The flatc compiler currently has a 256 limit.
67 : : *
68 : : * Some target C compilers might respect anything above
69 : : * 16 and may reguire that PAD option of the C code generator.
70 : : */
71 : : static inline int is_valid_align(uint64_t align)
72 : : {
73 : : uint64_t n = 1;
74 [ + - ]: 10 : if (align == 0 || align > FLATCC_FORCE_ALIGN_MAX) {
75 : : return 0;
76 : : }
77 [ + - ]: 45 : while (n <= align) {
78 [ + + ]: 45 : if (n == align) {
79 : : return 1;
80 : : }
81 : 35 : n *= 2;
82 : : }
83 : : return 0;
84 : : }
85 : :
86 : : static inline uint64_t fb_align(uint64_t size, uint64_t align)
87 : : {
88 : : assert(is_valid_align(align));
89 : :
90 : 137 : return (size + align - 1) & ~(align - 1);
91 : : }
92 : :
93 : : /*
94 : : * The FNV-1a 32-bit little endian hash is a FlatBuffers standard for
95 : : * transmission of type identifiers in a compact form, in particular as
96 : : * alternative file identifiers. Note that if hash becomes 0, we map it
97 : : * to hash("").
98 : : */
99 : 171 : static inline void set_type_hash(fb_compound_type_t *ct)
100 : : {
101 : : fb_ref_t *name;
102 : : fb_symbol_t *sym;
103 : : uint32_t hash;
104 : :
105 : : hash = fb_hash_fnv1a_32_init();
106 [ + - ]: 171 : if (ct->scope)
107 [ + + ]: 479 : for (name = ct->scope->name; name; name = name->link) {
108 : 308 : hash = fb_hash_fnv1a_32_append(hash, name->ident->text, name->ident->len);
109 : : hash = fb_hash_fnv1a_32_append(hash, ".", 1);
110 : : }
111 : : sym = &ct->symbol;
112 : 171 : hash = fb_hash_fnv1a_32_append(hash, sym->ident->text, sym->ident->len);
113 [ - + ]: 171 : if (hash == 0) {
114 : : hash = fb_hash_fnv1a_32_init();
115 : : }
116 : 171 : ct->type_hash = hash;
117 : 171 : }
118 : :
119 : : static inline fb_scope_t *fb_find_scope_by_string(fb_schema_t *S, const char *name, int len)
120 : : {
121 [ + - ][ + - ]: 1 : if (!S || !S->root_schema) {
122 : : return 0;
123 : : }
124 [ - + ]: 1 : if (len == 0) {
125 : : /* Global scope. */
126 : : name = 0;
127 : : }
128 : 1 : return fb_scope_table_find(&S->root_schema->scope_index, name, (size_t)len);
129 : : }
130 : :
131 : : /* count = 0 indicates zero-terminated ref list, name = 0 indicates global scope. */
132 : : static inline fb_scope_t *fb_find_scope_by_ref(fb_schema_t *S, const fb_ref_t *name, int count)
133 : : {
134 [ + - ][ + - ]: 88 : if (!S || !S->root_schema) {
135 : : return 0;
136 : : }
137 : 88 : return fb_scope_table_find(&S->root_schema->scope_index, name, (size_t)(-count));
138 : : }
139 : :
140 : : static inline fb_symbol_t *define_fb_symbol(fb_symbol_table_t *si, fb_symbol_t *sym)
141 : : {
142 : 771 : return fb_symbol_table_insert_item(si, sym, ht_keep);
143 : : }
144 : :
145 : : static inline fb_symbol_t *find_fb_symbol_by_token(fb_symbol_table_t *si, fb_token_t *token)
146 : : {
147 : 329 : return fb_symbol_table_find(si, token->text, token->len);
148 : : }
149 : :
150 : : static inline fb_name_t *define_fb_name(fb_name_table_t *ni, fb_name_t *name)
151 : : {
152 : 361 : return fb_name_table_insert_item(ni, name, ht_keep);
153 : : }
154 : :
155 : : static inline fb_name_t * find_fb_name_by_token(fb_name_table_t *ni, fb_token_t *token)
156 : : {
157 : 353 : return fb_name_table_find(ni, token->text, token->len);
158 : : }
159 : :
160 : : /* Returns 1 if value exists, 0 otherwise, */
161 : : static inline int add_to_value_set(fb_value_set_t *vs, fb_value_t *value)
162 : : {
163 : 115 : return fb_value_set_insert_item(vs, value, ht_keep) != 0;
164 : : }
165 : :
166 : : static inline int is_in_value_set(fb_value_set_t *vs, fb_value_t *value)
167 : : {
168 : 9 : return 0 != fb_value_set_find_item(vs, value);
169 : : }
170 : :
171 : 10 : static inline fb_symbol_t *lookup_string_reference(fb_parser_t *P, fb_scope_t *local, const char *s, int len)
172 : : {
173 : : fb_symbol_t *sym;
174 : : fb_scope_t *scope;
175 : : const char *name, *basename;
176 : : int k;
177 : :
178 : : name = s;
179 : : basename = s;
180 : : k = len;
181 [ + + ]: 71 : while (k > 0) {
182 [ + + ]: 62 : if (s[--k] == '.') {
183 : 1 : basename = s + k + 1;
184 : 1 : --len;
185 : 62 : break;
186 : : }
187 : : }
188 : 10 : len -= k;
189 [ + + ]: 10 : if (local && k == 0) {
190 [ - + ]: 9 : if ((sym = fb_symbol_table_find(&local->symbol_index, basename, len))) {
191 : : return sym;
192 : : }
193 : : }
194 [ + - ]: 1 : if (!(scope = fb_find_scope_by_string(&P->schema, name, k))) {
195 : : return 0;
196 : : }
197 : 1 : return fb_symbol_table_find(&scope->symbol_index, basename, len);
198 : : }
199 : :
200 : : /*
201 : : * First search the optional local scope, then the scope of the namespace prefix if any.
202 : : * If `enumval` is non-zero, the last namepart is stored in that
203 : : * pointer and the lookup stops before that part.
204 : : */
205 : 278 : static inline fb_symbol_t *lookup_reference(fb_parser_t *P, fb_scope_t *local, fb_ref_t *name, fb_ref_t **enumval)
206 : : {
207 : : fb_ref_t *basename, *last, *p;
208 : : fb_scope_t *scope;
209 : : fb_symbol_t *sym;
210 : : int count;
211 : :
212 : : count = 0;
213 : : scope = 0;
214 : : p = name;
215 : : last = 0;
216 : : basename = 0;
217 [ + + ]: 743 : while (p) {
218 : : basename = last;
219 : : last = p;
220 : 465 : p = p->link;
221 : 465 : ++count;
222 : : }
223 [ + + ]: 278 : if (enumval) {
224 : 71 : --count;
225 : 71 : *enumval = last;
226 : : } else {
227 : : basename = last;
228 : : }
229 [ + + ]: 278 : if (!basename) {
230 : : return 0;
231 : : }
232 [ + + ]: 249 : if (local && count == 1) {
233 [ + + ]: 170 : if ((sym = find_fb_symbol_by_token(&local->symbol_index, basename->ident))) {
234 [ - + ]: 161 : if (get_compound_if_visible(&P->schema, sym)) {
235 : : return sym;
236 : : }
237 : : }
238 : : }
239 : : /* Null name is valid in scope lookup, indicating global scope. */
240 [ + + ]: 88 : if (count == 1) {
241 : : name = 0;
242 : : }
243 [ + - ]: 88 : if (!(scope = fb_find_scope_by_ref(&P->schema, name, count - 1))) {
244 : : return 0;
245 : : }
246 : 88 : sym = find_fb_symbol_by_token(&scope->symbol_index, basename->ident);
247 [ + - ][ - + ]: 176 : if (sym && get_compound_if_visible(&P->schema, sym)) {
248 : : return sym;
249 : : }
250 : : return 0;
251 : : }
252 : :
253 : : static inline fb_symbol_t *lookup_type_reference(fb_parser_t *P, fb_scope_t *local, fb_ref_t *name)
254 : : {
255 : 207 : return lookup_reference(P, local, name, 0);
256 : : }
257 : :
258 : : /*
259 : : * `ct` is null when looking up names for scalar types and otherwise it is
260 : : * the enum type being assigned. The provided reference may reference
261 : : * an enum value in the `ct` type, or another enum if a scope/type is
262 : : * given.
263 : : */
264 : 71 : static inline int lookup_enum_name(fb_parser_t *P, fb_scope_t *local, fb_compound_type_t *ct, fb_ref_t *ref, fb_value_t *value)
265 : : {
266 : : fb_symbol_t *sym;
267 : : fb_ref_t *enumval;
268 : : fb_member_t *member;
269 : :
270 : 71 : enumval = 0;
271 : : assert(ref);
272 : : assert(ct == 0 || ct->symbol.kind == fb_is_enum);
273 : 71 : sym = lookup_reference(P, local, ref, &enumval);
274 [ + + ][ - + ]: 71 : if (sym && sym->kind == fb_is_enum) {
275 : : ct = (fb_compound_type_t *)sym;
276 [ + - ]: 29 : } else if (ref->link) {
277 : : /* If there was a scope / type prefix, it was not found, or it was not an enum type. */
278 : : return -1;
279 : : }
280 [ + - ]: 71 : if (!ct) {
281 : : return -1;
282 : : }
283 : 71 : sym = find_fb_symbol_by_token(&ct->index, enumval->ident);
284 [ + - ]: 71 : if (!sym) {
285 : : return -1;
286 : : }
287 : : member = (fb_member_t *)sym;
288 : 71 : *value = member->value;
289 : 71 : return 0;
290 : : }
291 : :
292 : : /* This is repeated for every include file, but this pose no problem. */
293 : 34 : static void install_known_attributes(fb_parser_t *P)
294 : : {
295 : : int i;
296 : : fb_attribute_t *a;
297 : :
298 [ + + ]: 374 : for (i = 0; i < KNOWN_ATTR_COUNT; ++i) {
299 : : /* Don't put it in the parsed list, just the index. */
300 : 340 : a = new_elem(P, sizeof(*a));
301 : 340 : a->known = i;
302 : 340 : a->name.name.s.s = (char *)fb_known_attribute_names[i];
303 : 340 : a->name.name.s.len = (long)strlen(fb_known_attribute_names[i]);
304 : 340 : a->name.name.type = vt_string;
305 : 340 : a->name.link = 0;
306 [ + + ]: 340 : if ((a = (fb_attribute_t *)define_fb_name(&P->schema.root_schema->attribute_index, &a->name))) {
307 : : /*
308 : : * If the user alredy defined the attribute, keep that instead.
309 : : * (Memory leak is ok here.)
310 : : */
311 : 180 : a->known = i;
312 : : }
313 : : }
314 : 34 : }
315 : :
316 : : static void revert_order(fb_compound_type_t **list) {
317 : 34 : fb_compound_type_t *next, *prev = 0, *link = *list;
318 : :
319 [ + + ]: 86 : while (link) {
320 : 52 : next = link->order;
321 : 52 : link->order = prev;
322 : : prev = link;
323 : : link = next;
324 : : }
325 : 34 : *list = prev;
326 : : }
327 : :
328 : 655 : static inline unsigned short process_metadata(fb_parser_t *P, fb_metadata_t *m,
329 : : unsigned short expect, fb_metadata_t *out[KNOWN_ATTR_COUNT])
330 : : {
331 : : unsigned short flags;
332 : : int n = FLATCC_ATTR_MAX;
333 : : int i;
334 : : int type;
335 : : fb_attribute_t *a;
336 : :
337 : 655 : memset(out, 0, sizeof(out[0]) * KNOWN_ATTR_COUNT);
338 [ + + ]: 1008 : for (flags = 0; m && n; --n, m = m->link) {
339 : 353 : a = (fb_attribute_t *)find_fb_name_by_token(&P->schema.root_schema->attribute_index, m->ident);
340 [ - + ]: 353 : if (!a) {
341 : 0 : error_tok(P, m->ident, "unknown attribute not declared");
342 : 0 : continue;
343 : : }
344 [ + + ]: 353 : if (!(i = a->known)) {
345 : 19 : continue;
346 : : }
347 [ - + ]: 334 : if (!((1 << i) & expect)) {
348 : 0 : error_tok(P, m->ident, "known attribute not expected in this context");
349 : 0 : continue;
350 : : }
351 : 334 : flags |= 1 << i;
352 [ - + ]: 334 : if (out[i]) {
353 : 0 : error_tok(P, m->ident, "known attribute listed multiple times");
354 : 0 : continue;
355 : : }
356 : 334 : out[i] = m;
357 : 334 : type = fb_known_attribute_types[i];
358 [ + + ][ - + ]: 334 : if (type == vt_missing && m->value.type != vt_missing) {
359 : 0 : error_tok(P, m->ident, "known attribute does not expect a value");
360 : 0 : continue;
361 : : }
362 [ + + ][ - + ]: 334 : if (type == vt_string && m->value.type != vt_string) {
363 : 0 : error_tok(P, m->ident, "known attribute expects a string");
364 : 0 : continue;
365 : : }
366 [ + + ][ - + ]: 334 : if (type == vt_uint && m->value.type != vt_uint) {
367 : 0 : error_tok(P, m->ident, "known attribute expects an unsigned integer");
368 : 0 : continue;
369 : : }
370 [ - + ][ # # ]: 334 : if (type == vt_int && m->value.type != vt_uint && m->value.type != vt_int) {
[ # # ]
371 : 0 : error_tok(P, m->ident, "known attribute expects an integer");
372 : 0 : continue;
373 : : }
374 [ - + ][ # # ]: 334 : if (type == vt_bool && m->value.type != vt_bool) {
375 : 0 : error_tok(P, m->ident, "known attribute expects 'true' or 'false'");
376 : 0 : continue;
377 : : }
378 : : }
379 [ - + ]: 655 : if (m) {
380 : 0 : error_tok(P, m->ident, "too many attributes");
381 : : }
382 : 655 : return flags;
383 : : }
384 : :
385 : : /*
386 : : * Recursive types are allowed, according to FlatBuffers Internals doc.,
387 : : * but this cannot be possible for structs because they have no default
388 : : * value or null option, and can only hold scalars and other structs, so
389 : : * recursion would never terminate. Enums are simple types and cannot be
390 : : * recursive either. Unions reference tables which may reference unions,
391 : : * and recursion works well here. Tables allow any other table, union,
392 : : * or scalar value to be optional or default, so recursion is possible.
393 : : * In conclusion, Unions and Table members may reference all other
394 : : * types, and self. Enums are trivially checked because the only allow
395 : : * scalars, which leaves structs that can build illegal forms.
396 : : *
397 : : * Object instances cannot be recursive meaning the object graph is
398 : : * always a tree, but this isn't really a concern for the schema
399 : : * compiler, and for the builder it happens naturally as it only adds to
400 : : * the buffer (though a compressor might reuse old data without
401 : : * violating the tree?).
402 : : *
403 : : * Conclusion: check structs for circular references and allow
404 : : * everything else to unfold, provided they otherwise pass type checks.
405 : : *
406 : : * Algorithm:
407 : : *
408 : : * Depth first search of the struct reference tree. We maintain flags to
409 : : * find back-links. We prune sub-trees already fully analyzed by using
410 : : * the closed flag. This operation is O(N) since each struct member is
411 : : * visited once.
412 : : *
413 : : * Recursion is limited to prevent blowing the stack and to protect
414 : : * against abuse.
415 : : */
416 : 54 : static int analyze_struct(fb_parser_t *P, fb_compound_type_t *ct)
417 : : {
418 : : fb_symbol_t *sym;
419 : : fb_compound_type_t *type;
420 : : fb_member_t *member;
421 : : int ret = 0;
422 : : uint64_t size;
423 : : uint16_t align;
424 : : fb_token_t *t;
425 : :
426 : : assert(ct->symbol.kind == fb_is_struct);
427 : :
428 : : assert(!(ct->symbol.flags & fb_circular_open));
429 [ + + ]: 54 : if (ct->symbol.flags & fb_circular_closed) {
430 : : return 0;
431 : : }
432 : : assert(!ct->order);
433 : 52 : ct->symbol.flags |= fb_circular_open;
434 : : align = 1;
435 [ + + ]: 137 : for (sym = ct->members; sym; sym = sym->link) {
436 : : type = 0;
437 [ - + ]: 85 : if (P->nesting_level >= FLATCC_NESTING_MAX) {
438 : : error(P, "maximum allowed nesting level exceeded while processing struct hierarchy");
439 : 0 : return -1;
440 : : }
441 : : member = (fb_member_t *)sym;
442 [ + + - - ]: 85 : switch (member->type.type) {
443 : : case vt_scalar_type:
444 : 62 : t = member->type.t;
445 : 62 : member->type.st = map_scalar_token_type(t);
446 : : size = sizeof_scalar_type(member->type.st);
447 [ - + ]: 62 : if (size < 1) {
448 : : error_sym_tok(P, sym, "unexpected type", t);
449 : 0 : return -1;
450 : : }
451 : 62 : member->align = (uint16_t)size;
452 : 62 : member->size = size;
453 : 62 : break;
454 : : case vt_compound_type_ref:
455 : : /* Enums might not be valid, but then it would be detected earlier. */
456 [ + + ]: 23 : if (member->type.ct->symbol.kind == fb_is_enum) {
457 : : type = member->type.ct;
458 : 11 : size = type->size;
459 : 11 : member->align = (uint16_t)size;
460 : 11 : member->size = size;
461 : 11 : break;
462 [ + - ]: 12 : } else if (member->type.ct->symbol.kind == fb_is_struct) {
463 : : type = member->type.ct;
464 [ - + ]: 12 : if (type->symbol.flags & fb_circular_open) {
465 : : error_sym_2(P, sym, "circular reference to struct at", &type->symbol);
466 : 0 : return -1;
467 : : }
468 [ + + ]: 12 : if (!(type->symbol.flags & fb_circular_closed)) {
469 [ - + ]: 2 : if (P->opts.hide_later_struct) {
470 : : error_sym_2(P, sym, "dependency on later defined struct not permitted with current settings", &type->symbol);
471 : : }
472 : 2 : ++P->nesting_level;
473 : 2 : ret = analyze_struct(P, type);
474 : 2 : --P->nesting_level;
475 [ + - ]: 2 : if (ret) {
476 : : return ret;
477 : : }
478 : : }
479 : 12 : member->align = type->align;
480 : 12 : member->size = type->size;
481 : 12 : break;
482 : : } else {
483 : : error_sym(P, sym, "unexpected compound type for field");
484 : 0 : return -1;
485 : : }
486 : : break;
487 : : case vt_invalid:
488 : : /* Old error. */
489 : : return -1;
490 : : default:
491 : : error_sym(P, sym, "unexpected type");
492 : 0 : return -1;
493 : : }
494 : 170 : member->offset = fb_align(ct->size, member->align);
495 [ + - ][ - + ]: 85 : if (member->offset < ct->size || member->offset + member->size < member->offset) {
496 : : error_sym(P, sym, "struct size overflow");
497 : 0 : return -1;
498 : : }
499 : : size = member->offset + member->size;
500 [ + - ][ - + ]: 85 : if (size < ct->size || size > FLATCC_STRUCT_MAX_SIZE) {
501 : : error_sym(P, sym, "struct field overflows maximum allowed struct size");
502 : : };
503 : 85 : ct->size = size;
504 : : /*
505 : : * FB spec is not very clear on this - but experimentally a
506 : : * force aligned member struct will force that alignment upon a
507 : : * containing struct if the alignment would otherwise be
508 : : * smaller. In otherwise, a struct is aligned to the alignment
509 : : * of the largest member, not just the largest scalar member
510 : : * (directly or indirectly).
511 : : */
512 [ + + ]: 85 : if (align < member->align) {
513 : : align = member->align;
514 : : }
515 : : }
516 [ + + ]: 52 : if (ct->align > 0) {
517 [ - + ]: 10 : if (align > ct->align) {
518 : : error_sym(P, &ct->symbol, "'force_align' cannot be smaller than natural alignment for");
519 : 0 : ct->align = align;
520 : : }
521 : : } else {
522 : 42 : ct->align = align;
523 : : }
524 : : /* Add trailing padding if necessary. */
525 : 104 : ct->size = fb_align(ct->size, ct->align);
526 : :
527 : 52 : ct->symbol.flags |= fb_circular_closed;
528 : 52 : ct->symbol.flags &= ~fb_circular_open;
529 : 52 : ct->order = P->schema.ordered_structs;
530 : 52 : P->schema.ordered_structs = ct;
531 : 52 : return ret;
532 : : }
533 : :
534 : 20 : static int define_nested_table(fb_parser_t *P, fb_scope_t *local, fb_member_t *member, fb_metadata_t *m)
535 : : {
536 : : fb_symbol_t *type_sym;
537 : :
538 [ + - ][ - + ]: 10 : if (member->type.type != vt_vector_type || member->type.st != fb_ubyte) {
539 : 0 : error_tok(P, m->ident, "'nested_flatbuffer' attribute requires a [ubyte] vector type");
540 : : return -1;
541 : : }
542 [ + - ]: 10 : if (m->value.type != vt_string) {
543 : : /* All known attributes get automatically type checked, so just ignore. */
544 : : return -1;
545 : : }
546 : 10 : type_sym = lookup_string_reference(P, local, m->value.s.s, m->value.s.len);
547 [ - + ]: 10 : if (!type_sym) {
548 : 0 : error_tok_as_string(P, m->ident, "nested reference not found", m->value.s.s, m->value.s.len);
549 : : return -1;
550 : : }
551 [ + + ]: 10 : if (type_sym->kind != fb_is_table) {
552 [ - + ]: 1 : if (!P->opts.allow_struct_root) {
553 : 0 : error_tok_2(P, m->ident, "nested reference does not refer to a table", type_sym->ident);
554 : : return -1;
555 : : }
556 [ - + ]: 1 : if (type_sym->kind != fb_is_struct) {
557 : 0 : error_tok_2(P, m->ident, "nested reference does not refer to a table or a struct", type_sym->ident);
558 : : return -1;
559 : : }
560 : : }
561 : 10 : member->nest = (fb_compound_type_t *)type_sym;
562 : : return 0;
563 : : }
564 : :
565 : 52 : static int process_struct(fb_parser_t *P, fb_compound_type_t *ct)
566 : : {
567 : : fb_symbol_t *sym, *old, *type_sym;
568 : : fb_member_t *member;
569 : : fb_metadata_t *knowns[KNOWN_ATTR_COUNT], *m;
570 : : uint16_t allow_flags;
571 : : int key_count = 0;
572 : :
573 [ - + ]: 52 : if (ct->type.type) {
574 : : error_sym(P, &ct->symbol, "internal error: struct cannot have a type");
575 : 0 : return -1;
576 : : }
577 : 52 : ct->metadata_flags = process_metadata(P, ct->metadata, fb_f_force_align, knowns);
578 [ + + ]: 52 : if ((m = knowns[fb_attr_force_align])) {
579 [ - + ]: 10 : if (!is_valid_align(m->value.u)) {
580 : : error_sym(P, &ct->symbol, "'force_align' exceeds maximum permitted alignment or is not a power of 2");
581 : : } else {
582 : : /* This may still fail on natural alignment size. */
583 : 10 : ct->align = (uint16_t)m->value.u;
584 : : }
585 : : }
586 [ + + ]: 137 : for (sym = ct->members; sym; sym = sym->link) {
587 [ - + ]: 85 : if ((old = define_fb_symbol(&ct->index, sym))) {
588 : : error_sym_2(P, sym, "struct field already defined here", old);
589 : 0 : continue;
590 : : }
591 [ - + ]: 85 : if (sym->kind != fb_is_member) {
592 : : error_sym(P, sym, "internal error: field type expected");
593 : 0 : return -1;
594 : : }
595 : : member = (fb_member_t *)sym;
596 : : allow_flags = 0;
597 : : /* Notice the difference between fb_f_ and fb_attr_ (flag vs index). */
598 [ + - ]: 85 : if (P->opts.allow_struct_field_key) {
599 : : allow_flags |= fb_f_key;
600 : : }
601 [ + - ]: 85 : if (P->opts.allow_struct_field_deprecate) {
602 : 85 : allow_flags |= fb_f_deprecated;
603 : : }
604 : 85 : member->metadata_flags = process_metadata(P, member->metadata, allow_flags, knowns);
605 [ + + - ]: 85 : switch (member->type.type) {
606 : : case vt_type_ref:
607 : 23 : type_sym = lookup_type_reference(P, ct->scope, member->type.ref);
608 [ - + ]: 23 : if (!type_sym) {
609 : 0 : error_ref_sym(P, member->type.ref, "unknown type reference used with struct field", sym);
610 : 0 : member->type.type = vt_invalid;
611 : 0 : continue;
612 : : }
613 : 23 : member->type.ct = (fb_compound_type_t*)type_sym;
614 : 23 : member->type.type = vt_compound_type_ref;
615 [ + + ]: 23 : if (type_sym->kind != fb_is_struct) {
616 [ + - ]: 11 : if (P->opts.allow_enum_struct_field) {
617 [ - + ]: 11 : if (type_sym->kind != fb_is_enum) {
618 : : error_sym_2(P, sym, "struct fields can only be scalars, structs, and enums, but has type", type_sym);
619 : 0 : member->type.type = vt_invalid;
620 : 0 : return -1;
621 : : }
622 [ + + ]: 11 : if (member->metadata_flags & fb_f_key) {
623 [ - + ]: 1 : if (!P->opts.allow_enum_key) {
624 : : error_sym(P, sym, "key attribute now allowed for this kind of field");
625 : 0 : member->type.type = vt_invalid;
626 : 0 : return -1;
627 : : }
628 : 1 : key_count++;
629 : : }
630 : : } else {
631 : : error_sym_2(P, sym, "struct fields can only be scalars and structs, but has type", type_sym);
632 : 0 : member->type.type = vt_invalid;
633 : 0 : return -1;
634 : : }
635 : : } else {
636 [ - + ]: 12 : if (member->metadata_flags & fb_f_key) {
637 : : error_sym(P, sym, "key attribute now allowed for this kind of field");
638 : 0 : member->type.type = vt_invalid;
639 : 0 : return -1;
640 : : }
641 : : }
642 : : break;
643 : : case vt_scalar_type:
644 [ + + ]: 62 : if (member->metadata_flags & fb_f_key) {
645 : 2 : key_count++;
646 : : }
647 : : break;
648 : : default:
649 : : error_sym(P, sym, "struct member member can only be of struct or scalar type");
650 : 0 : return -1;
651 : : }
652 [ - + ]: 85 : if (member->value.type) {
653 : : error_sym(P, sym, "struct member member cannot have a default value");
654 : 0 : continue;
655 : : }
656 : : }
657 [ + + ]: 52 : if (key_count) {
658 : 3 : ct->symbol.flags |= fb_indexed;
659 : : }
660 [ - + ][ # # ]: 52 : if (key_count > 1 && !P->opts.allow_multiple_key_fields) {
661 : : error_sym(P, &ct->symbol, "table has multiple key fields, but at most one is permitted");
662 : 0 : return -1;
663 : : }
664 : : return 0;
665 : : }
666 : :
667 : : /* Temporary markers only used during assignment of field identifiers. */
668 : : enum { unused_field = 0, normal_field, type_field };
669 : :
670 : 72 : static int process_table(fb_parser_t *P, fb_compound_type_t *ct)
671 : : {
672 : : fb_symbol_t *sym, *old, *type_sym;
673 : : fb_member_t *member;
674 : : fb_metadata_t *knowns[KNOWN_ATTR_COUNT], *m;
675 : : int ret = 0;
676 : : uint64_t count = 0;
677 : : int need_id = 0, id_failed = 0;
678 : : uint64_t max_id = 0;
679 : : int key_ok, key_count = 0;
680 : :
681 : : /*
682 : : * This just tracks the presence of a `normal_field` or a hidden
683 : : * `type_field`. The size is litmited to 16-bit unsigned offsets.
684 : : * It is only of relevance for ithe optional `id` table field
685 : : * attribute.
686 : : */
687 : : uint8_t *field_marker = 0;
688 : :
689 : : assert(ct->symbol.kind == fb_is_table);
690 : : assert(!ct->type.type);
691 : :
692 : 72 : ct->metadata_flags = process_metadata(P, ct->metadata, fb_f_original_order, knowns);
693 : : /*
694 : : * `original_order` now lives as a flag, we need not consider it
695 : : * further until code generation.
696 : : */
697 [ + + ]: 469 : for (sym = ct->members; sym; sym = sym->link) {
698 : : key_ok = 0;
699 : : type_sym = 0;
700 [ - + ]: 397 : if ((old = define_fb_symbol(&ct->index, sym))) {
701 : : error_sym_2(P, sym, "table member already defined here", old);
702 : 0 : continue;
703 : : }
704 [ - + ]: 397 : if (sym->kind != fb_is_member) {
705 : : error_sym(P, sym, "internal error: member type expected");
706 : 0 : return -1;
707 : : }
708 : : member = (fb_member_t *)sym;
709 [ - + ]: 397 : if (member->type.type == vt_invalid) {
710 : 0 : continue;
711 : : }
712 [ + + ]: 397 : if (member->type.type == vt_scalar_type || member->type.type == vt_vector_type) {
713 : 208 : member->type.st = map_scalar_token_type(member->type.t);
714 : : }
715 : 397 : member->metadata_flags = process_metadata(P, member->metadata, fb_f_id |
716 : : fb_f_nested_flatbuffer | fb_f_deprecated | fb_f_key | fb_f_required | fb_f_hash, knowns);
717 [ + + ]: 397 : if ((m = knowns[fb_attr_nested_flatbuffer])) {
718 : 10 : define_nested_table(P, ct->scope, member, m);
719 : : }
720 [ + + ][ - + ]: 397 : if ((member->metadata_flags & fb_f_required) && member->type.type == vt_scalar_type) {
721 : : error_sym(P, sym, "'required' attribute is redundant on scalar table field");
722 : : }
723 : 397 : m = knowns[fb_attr_id];
724 [ + + ]: 397 : if (m && count == 0) {
725 : : need_id = 1;
726 : 8 : field_marker = P->tmp_field_marker;
727 : 8 : memset(field_marker, 0, (size_t)P->opts.vt_max_count);
728 : : }
729 [ + - ]: 397 : if (!id_failed) {
730 [ - + ]: 397 : if (count >= P->opts.vt_max_count) {
731 : : error_sym(P, sym, "too many fields for vtable size");
732 : : id_failed = 1;
733 [ + + ]: 397 : } else if (!need_id) {
734 : 197 : member->id = (unsigned short)count;
735 : : }
736 : 397 : ++count;
737 : : }
738 [ + + + + : 397 : switch (member->type.type) {
+ + - ]
739 : : case vt_scalar_type:
740 : : key_ok = 1;
741 [ + + ]: 179 : if (member->value.type == vt_name_ref) {
742 [ - + ]: 25 : if (lookup_enum_name(P, ct->scope, 0, member->value.ref, &member->value)) {
743 : 0 : error_ref_sym(P, member->value.ref, "unknown name used as initializer for scalar field", sym);
744 : 0 : member->type.type = vt_invalid;
745 : 0 : continue;
746 : : }
747 : : }
748 [ + + ]: 179 : if (!member->value.type) {
749 : : /*
750 : : * Simplifying by ensuring we always have a default
751 : : * value where an initializer is possible (also goes for enum
752 : : * above).
753 : : */
754 : 112 : member->value.type = vt_uint;
755 : 112 : member->value.u = 0;
756 : : }
757 [ - + ]: 179 : if (fb_coerce_scalar_type(P, sym, member->type.st, &member->value)) {
758 : 0 : member->type.type = vt_invalid;
759 : 0 : continue;
760 : : }
761 : 358 : member->size = sizeof_scalar_type(member->type.st);
762 : 179 : member->align = (uint16_t)member->size;
763 : 179 : break;
764 : : case vt_vector_type:
765 : 58 : member->size = sizeof_scalar_type(member->type.st);
766 : 29 : member->align =(uint16_t) member->size;
767 [ - + ]: 29 : if (member->value.type) {
768 : : error_sym(P, sym, "scalar vectors cannot have an initializer");
769 : 0 : member->type.type = vt_invalid;
770 : 0 : continue;
771 : : }
772 : : break;
773 : : case vt_string_type:
774 : : /* `size` or `align` not defined - these are implicit uoffset types. */
775 : 32 : key_ok = P->opts.allow_string_key;
776 [ - + ]: 32 : if (member->value.type) {
777 : : error_sym(P, sym, "strings cannot have an initializer");
778 : 0 : member->type.type = vt_invalid;
779 : 0 : continue;
780 : : }
781 : : break;
782 : : case vt_vector_string_type:
783 : : /* `size` or `align` not defined - these are implicit uoffset types. */
784 [ - + ]: 11 : if (member->value.type) {
785 : : error_sym(P, sym, "string vectors cannot have an initializer");
786 : 0 : member->type.type = vt_invalid;
787 : 0 : continue;
788 : : }
789 : : break;
790 : : case vt_type_ref:
791 : 125 : type_sym = lookup_type_reference(P, ct->scope, member->type.ref);
792 [ - + ]: 125 : if (!type_sym) {
793 : 0 : error_ref_sym(P, member->type.ref, "unknown type reference used with table field", sym);
794 : 0 : member->type.type = vt_invalid;
795 : : /* We cannot count id's without knowing if it is a union. */
796 : : id_failed = 1;
797 : 0 : continue;
798 : : }
799 [ + - - + ]: 125 : switch (type_sym->kind) {
800 : : case fb_is_enum:
801 [ - + ]: 55 : if (member->metadata_flags & fb_f_required) {
802 : : error_sym(P, sym, "'required' attribute is redundant on enum table field");
803 : : }
804 : 55 : key_ok = P->opts.allow_enum_key;
805 : 55 : break;
806 : : case fb_is_table:
807 : : case fb_is_struct:
808 : : case fb_is_union:
809 : : break;
810 : : case fb_is_rpc_service:
811 : : error_sym_2(P, sym, "rpc service is not a valid table field type", type_sym);
812 : 0 : member->type.type = vt_invalid;
813 : 0 : continue;
814 : : default:
815 : : error_sym_2(P, sym, "internal error: unexpected field type", type_sym);
816 : 0 : member->type.type = vt_invalid;
817 : 0 : continue;
818 : : }
819 : 125 : member->type.type = vt_compound_type_ref;
820 : 125 : member->type.ct = (fb_compound_type_t*)type_sym;
821 : : /*
822 : : * Note: this information transfer won't always work because
823 : : * structs do not know their full size at this point so
824 : : * codegen must use the member->type.ct values.
825 : : */
826 : 125 : member->size = member->type.ct->size;
827 : 125 : member->align = member->type.ct->align;
828 : :
829 [ + + ][ + - ]: 125 : if (type_sym->kind == fb_is_union && !id_failed) {
830 : : /* Hidden union type field. */
831 [ + + ]: 13 : if (!need_id) {
832 : 5 : member->id = (unsigned short)count;
833 : : }
834 : 13 : ++count;
835 : : }
836 [ + + ]: 125 : if (member->value.type) {
837 [ - + ]: 46 : if (type_sym->kind != fb_is_enum) {
838 : : error_sym(P, sym, "non-scalar field cannot have an initializer");
839 : 0 : member->type.type = vt_invalid;
840 : 0 : continue;
841 : : }
842 [ + - ]: 46 : if (member->value.type == vt_name_ref) {
843 [ - + ]: 46 : if (lookup_enum_name(P, ct->scope, member->type.ct, member->value.ref, &member->value)) {
844 : 0 : error_ref_sym(P, member->value.ref, "unknown name used as initializer for enum field", sym);
845 : 0 : member->type.type = vt_invalid;
846 : 0 : continue;
847 : : }
848 : : } else {
849 [ # # ]: 0 : if (fb_coerce_scalar_type(P, sym, ((fb_compound_type_t *)type_sym)->type.st, &member->value)) {
850 : 0 : member->type.type = vt_invalid;
851 : 0 : continue;
852 : : }
853 [ # # ]: 0 : if (P->opts.strict_enum_init) {
854 [ # # ]: 0 : if (!is_in_value_set(&member->type.ct->value_set, &member->value)) {
855 : : error_sym(P, sym, "initializer does not match a defined enum value");
856 : 0 : member->type.type = vt_invalid;
857 : 0 : continue;
858 : : }
859 : : }
860 : : }
861 : : } else {
862 : : /* Enum is the only type that cannot always default to 0. */
863 [ + + ]: 79 : if (type_sym->kind == fb_is_enum) {
864 : 9 : member->value.type = vt_uint;
865 : 9 : member->value.u = 0;
866 [ - + ]: 9 : if (fb_coerce_scalar_type(P, type_sym, ((fb_compound_type_t *)type_sym)->type.st, &member->value)) {
867 : 0 : member->type.type = vt_invalid;
868 : 0 : continue;
869 : : }
870 [ + - ]: 9 : if (P->opts.strict_enum_init) {
871 [ - + ]: 9 : if (!is_in_value_set(&member->type.ct->value_set, &member->value)) {
872 : : error_sym_2(P, sym,
873 : : "enum type requires an explicit initializer because it has no 0 value", type_sym);
874 : 0 : member->type.type = vt_invalid;
875 : 0 : continue;
876 : : }
877 : : }
878 : : }
879 : : }
880 : : break;
881 : : case vt_vector_type_ref:
882 : 21 : type_sym = lookup_type_reference(P, ct->scope, member->type.ref);
883 [ - + ]: 21 : if (!type_sym) {
884 : 0 : error_ref_sym(P, member->type.ref, "unknown vector type reference used with table field", sym);
885 : 0 : member->type.type = vt_invalid;
886 : 0 : continue;
887 : : }
888 [ + - ][ - + ]: 21 : switch (type_sym->kind) {
889 : : case fb_is_enum:
890 : : case fb_is_table:
891 : : case fb_is_struct:
892 : : break;
893 : : default:
894 : 0 : error_sym_tok(P, sym, "vectors can only hold scalars, structs, enums, and tables", member->type.t);
895 : 0 : member->type.type = vt_invalid;
896 : 0 : continue;
897 : : }
898 [ - + ]: 21 : if (member->value.type) {
899 : : error_sym(P, sym, "non-scalar field cannot have an initializer");
900 : 0 : member->type.type = vt_invalid;
901 : 0 : continue;
902 : : }
903 : : /* Size of the vector element, not of the vector itself. */
904 : 21 : member->type.type = vt_vector_compound_type_ref;
905 : 21 : member->type.ct = (fb_compound_type_t*)type_sym;
906 : 21 : member->size = member->type.ct->size;
907 : 21 : member->align = member->type.ct->align;
908 : 21 : break;
909 : : default:
910 : : error_sym(P, sym, "unexpected table field type encountered");
911 : 0 : member->type.type = vt_invalid;
912 : 0 : continue;
913 : : }
914 [ + - ]: 397 : if (!id_failed) {
915 [ - + ]: 397 : if (m && !need_id && !id_failed) {
916 : 0 : error_tok(P, m->ident, "unexpected id attribute, must be used on all fields, or none");
917 : 0 : id_failed = 1;
918 [ - + ]: 397 : } else if (!m && need_id && !id_failed) {
919 : : error_sym(P, sym, "id attribute missing, must be used on all fields, or none");
920 : 0 : id_failed = 1;
921 [ + + ]: 397 : } else if (m) {
922 [ + - ]: 200 : if (m->value.type == vt_uint) {
923 [ - + ]: 200 : if (m->value.u >= P->opts.vt_max_count) {
924 : : error_sym(P, sym, "id too large to fit in vtable");
925 : : id_failed = 1;
926 : : } else {
927 : 200 : member->id = (unsigned short)m->value.u;
928 [ + + ]: 200 : if (member->id > max_id) {
929 : : max_id = member->id;
930 : : }
931 : : }
932 [ # # ]: 0 : } else if (m->value.type == vt_int) {
933 : 0 : error_tok(P, m->ident, "id attribute cannot be negative");
934 : : id_failed = 1;
935 : : } else {
936 : 0 : error_tok(P, m->ident, "unexpecte id attribute type");
937 : : id_failed = 1;
938 : : }
939 : : }
940 : : }
941 [ + + ]: 397 : if (need_id && !id_failed) {
942 [ - + ]: 200 : if (field_marker[member->id] == type_field) {
943 : 0 : error_tok(P, m->ident, "id attribute value conflicts with a hidden type field");
944 : : id_failed = normal_field;
945 [ - + ]: 200 : } else if (field_marker[member->id]) {
946 : 0 : error_tok(P, m->ident, "id attribute value conflicts with another field");
947 : : } else {
948 : 200 : field_marker[member->id] = normal_field;
949 : : }
950 [ + + ][ + + ]: 200 : if (!id_failed && type_sym && type_sym->kind == fb_is_union) {
951 [ - + ]: 8 : if (member->id <= 1) {
952 : 0 : error_tok(P, m->ident, "id attribute value should be larger to accomdate hidden union type field");
953 : : id_failed = 1;
954 [ - + ]: 8 : } else if (field_marker[member->id - 1] == type_field) {
955 : 0 : error_tok(P, m->ident, "hidden union field below attribute id value conflicts with another hidden type field");
956 : : id_failed = 1;
957 [ - + ]: 8 : } else if (field_marker[member->id - 1]) {
958 : 0 : error_tok(P, m->ident, "hidden union field below attribute id value conflicts with another field");
959 : : id_failed = 1;
960 : : } else {
961 : 8 : field_marker[member->id - 1] = type_field;
962 : : }
963 : : }
964 : : }
965 [ + + ]: 397 : if (member->metadata_flags & fb_f_key) {
966 : 12 : ++key_count;
967 [ - + ]: 12 : if (!key_ok) {
968 : : error_sym(P, sym, "key attribute not allowed for this kind of field");
969 : : }
970 : : }
971 : : }
972 [ + - ]: 72 : if (!id_failed) {
973 : 72 : ct->count = count;
974 : : }
975 [ + + ]: 72 : if (!id_failed && need_id) {
976 [ - + ]: 8 : if (count && max_id >= count) {
977 : : error_sym(P, &ct->symbol, "id field attribute range exceeds field count");
978 : : id_failed = 1;
979 : : }
980 : : }
981 [ + + ]: 72 : if (key_count) {
982 : 11 : ct->symbol.flags |= fb_indexed;
983 : : }
984 [ + + ][ - + ]: 72 : if (key_count > 1 && !P->opts.allow_multiple_key_fields) {
985 : : error_sym(P, &ct->symbol, "table has multiple key fields, but at most one is permitted");
986 : : ret = -1;
987 : : }
988 [ - + ]: 72 : if (id_failed) {
989 : : ret = -1;
990 : : }
991 : : return ret;
992 : : }
993 : :
994 : : /*
995 : : * The parser already makes sure we have exactly one request type,
996 : : * one response type, and no initializer.
997 : : *
998 : : * We are a bit heavy on flagging attributes because their behavior
999 : : * isn't really specified at this point.
1000 : : */
1001 : 1 : static int process_rpc_service(fb_parser_t *P, fb_compound_type_t *ct)
1002 : : {
1003 : : fb_symbol_t *sym, *old, *type_sym;
1004 : : fb_member_t *member;
1005 : : #if FLATCC_ALLOW_RPC_SERVICE_ATTRIBUTES || FLATCC_ALLOW_RPC_METHOD_ATTRIBUTES
1006 : : fb_metadata_t *knowns[KNOWN_ATTR_COUNT];
1007 : : #endif
1008 : :
1009 : : assert(ct->symbol.kind == fb_is_rpc_service);
1010 : : assert(!ct->type.type);
1011 : :
1012 : : /*
1013 : : * Deprecated is defined for fields - but it is unclear if this also
1014 : : * covers rpc services. Anyway, we accept it since it may be useful,
1015 : : * and does not harm.
1016 : : */
1017 : : #if FLATCC_ALLOW_RPC_SERVICE_ATTRIBUTES
1018 : : /* But we have no known attributes to support. */
1019 : : ct->metadata_flags = process_metadata(P, ct->metadata, 0, knowns);
1020 : : #else
1021 [ - + ]: 1 : if (ct->metadata) {
1022 : : error_sym(P, &ct->symbol, "rpc services cannot have attributes");
1023 : : /* Non-fatal. */
1024 : : }
1025 : : #endif
1026 : :
1027 : : /*
1028 : : * `original_order` now lives as a flag, we need not consider it
1029 : : * further until code generation.
1030 : : */
1031 [ + + ]: 4 : for (sym = ct->members; sym; sym = sym->link) {
1032 : : type_sym = 0;
1033 [ - + ]: 3 : if ((old = define_fb_symbol(&ct->index, sym))) {
1034 : : error_sym_2(P, sym, "rpc method already defined here", old);
1035 : 0 : continue;
1036 : : }
1037 [ - + ]: 3 : if (sym->kind != fb_is_member) {
1038 : : error_sym(P, sym, "internal error: member type expected");
1039 : 0 : return -1;
1040 : : }
1041 : : member = (fb_member_t *)sym;
1042 [ - + ]: 3 : if (member->value.type) {
1043 : : error_sym(P, sym, "internal error: initializer should have been rejected by parser");
1044 : : }
1045 [ - + ]: 3 : if (member->type.type == vt_invalid) {
1046 : 0 : continue;
1047 : : }
1048 [ - + ]: 3 : if (member->type.type != vt_type_ref) {
1049 : : error_sym(P, sym, "internal error: request type expected to be a type reference");
1050 : : }
1051 : 3 : type_sym = lookup_type_reference(P, ct->scope, member->req_type.ref);
1052 [ - + ]: 3 : if (!type_sym) {
1053 : 0 : error_ref_sym(P, member->req_type.ref, "unknown type reference used with rpc request type", sym);
1054 : 0 : member->type.type = vt_invalid;
1055 : 0 : continue;
1056 : : } else {
1057 [ - + ]: 3 : if (type_sym->kind != fb_is_table) {
1058 : : error_sym_2(P, sym, "rpc request type must reference a table, defined here", type_sym);
1059 : 0 : member->type.type = vt_invalid;
1060 : 0 : continue;
1061 : : }
1062 : 3 : member->req_type.type = vt_compound_type_ref;
1063 : 3 : member->req_type.ct = (fb_compound_type_t*)type_sym;
1064 : : }
1065 : 3 : type_sym = lookup_type_reference(P, ct->scope, member->type.ref);
1066 [ - + ]: 3 : if (!type_sym) {
1067 : 0 : error_ref_sym(P, member->type.ref, "unknown type reference used with rpc response type", sym);
1068 : 0 : member->type.type = vt_invalid;
1069 : 0 : continue;
1070 : : } else {
1071 [ - + ]: 3 : if (type_sym->kind != fb_is_table) {
1072 : : error_sym_2(P, sym, "rpc response type must reference a table, defined here", type_sym);
1073 : 0 : member->type.type = vt_invalid;
1074 : 0 : continue;
1075 : : }
1076 : 3 : member->type.type = vt_compound_type_ref;
1077 : 3 : member->type.ct = (fb_compound_type_t*)type_sym;
1078 : : /* Symbols have no size. */
1079 : 3 : member->size = 0;
1080 : : }
1081 : : #if FLATCC_ALLOW_RPC_METHOD_ATTRIBUTES
1082 : : #if FLATCC_ALLOW_DEPRECATED_RPC_METHOD
1083 : 3 : member->metadata_flags = process_metadata(P, member->metadata, fb_f_deprecated, knowns);
1084 : : #else
1085 : : member->metadata_flags = process_metadata(P, member->metadata, 0, knowns);
1086 : : #endif
1087 : : #else
1088 : : if (member->metadata) {
1089 : : error_sym(P, sym, "rpc methods cannot have attributes");
1090 : : /* Non-fatal. */
1091 : : continue;
1092 : : }
1093 : : #endif
1094 : : }
1095 : : return 0;
1096 : : }
1097 : :
1098 : 46 : static int process_enum(fb_parser_t *P, fb_compound_type_t *ct)
1099 : : {
1100 : : fb_symbol_t *sym, *old, *type_sym;
1101 : : fb_member_t *member;
1102 : : fb_metadata_t *knowns[KNOWN_ATTR_COUNT];
1103 : : fb_value_t index;
1104 : : fb_value_t old_index;
1105 : : int first = 1;
1106 : : int bit_flags = 0;
1107 : 46 : int is_union = ct->symbol.kind == fb_is_union;
1108 : :
1109 [ + + ]: 46 : if (!is_union) {
1110 : : assert(ct->symbol.kind == fb_is_enum);
1111 [ - + ]: 35 : if (!ct->type.type) {
1112 : 0 : ct->type.type = vt_invalid;
1113 : : error_sym(P, &ct->symbol, "enum must have a type");
1114 : 0 : return -1;
1115 : : }
1116 : : if (ct->type.type == vt_missing) {
1117 : : /*
1118 : : * Enums normally require a type, but the parser may have an
1119 : : * option to allow missing type, and then we provide a
1120 : : * sensible default.
1121 : : */
1122 : : ct->type.st = fb_int;
1123 : : ct->type.type = vt_scalar_type;
1124 [ + - ]: 35 : } else if (ct->type.type == vt_scalar_type) {
1125 : 70 : ct->type.st = map_scalar_token_type(ct->type.t);
1126 : : } else {
1127 : : /* Spec does not mention boolean type in enum, but we allow it. */
1128 : : error_sym(P, &ct->symbol, "enum type must be a scalar integral type or bool");
1129 : 0 : return -1;
1130 : : }
1131 : 70 : ct->size = sizeof_scalar_type(ct->type.st);
1132 : 35 : ct->align = (uint16_t)ct->size;
1133 : : } else {
1134 [ - + ]: 11 : if (ct->type.type) {
1135 : : error_sym(P, &ct->symbol, "unions cannot have a type, they are always enumerated as ubyte");
1136 : 0 : return -1;
1137 : : }
1138 : : /*
1139 : : * We preprocess unions as enums to get the value assignments.
1140 : : * The type field is not documented, but generated output from
1141 : : * flatc suggests ubyte. We use a an injected token to represent
1142 : : * the ubyte type so we do not have to hardcode elsewhere.
1143 : : */
1144 : 11 : ct->type.type = vt_scalar_type;
1145 : 11 : ct->type.st = fb_ubyte;
1146 : : /*
1147 : : * The union field use the type field and not the offset field
1148 : : * to define its size because type.type is scalar.
1149 : : */
1150 : 11 : ct->size = sizeof_scalar_type(fb_ubyte);
1151 : 11 : ct->align = (uint16_t)ct->size;
1152 : : }
1153 : :
1154 : 46 : ct->metadata_flags = process_metadata(P, ct->metadata, fb_f_bit_flags, knowns);
1155 [ + + ]: 46 : if (ct->metadata_flags & fb_f_bit_flags) {
1156 : : bit_flags = 1;
1157 : 10 : index.type = vt_uint;
1158 : 10 : index.u = 0;
1159 : : }
1160 : :
1161 [ + + ]: 46 : if (ct->type.st == fb_bool) {
1162 : 1 : index.b = 0;
1163 : 1 : index.type = vt_bool;
1164 : : } else {
1165 : 45 : index.i = 0;
1166 : 45 : index.type = vt_int;
1167 [ - + ]: 45 : if (fb_coerce_scalar_type(P, (fb_symbol_t *)ct, ct->type.st, &index)) {
1168 : : error(P, "internal error: unexpected conversion failure on enum 0 index");
1169 : 0 : return -1;
1170 : : }
1171 : : }
1172 : 46 : old_index = index;
1173 : :
1174 [ + + ]: 161 : for (sym = ct->members; sym; sym = sym->link, first = 0) {
1175 : : member = (fb_member_t *)sym;
1176 [ - + ]: 115 : if ((old = define_fb_symbol(&ct->index, sym))) {
1177 [ # # ]: 0 : if (old->ident == &P->t_none) {
1178 : : /*
1179 : : * Parser injects `NONE` as the first union member and
1180 : : * it therefore gets index 0. Additional use of NONE
1181 : : * will fail.
1182 : : */
1183 : : error_sym(P, sym, "'NONE' is a predefined value");
1184 : 0 : member->type.type = vt_invalid;
1185 : 0 : continue;
1186 : : }
1187 : : error_sym_2(P, sym, "value already defined here", old);
1188 : 0 : member->type.type = vt_invalid;
1189 : 0 : continue;
1190 : : }
1191 [ - + ]: 115 : if (sym->kind != fb_is_member) {
1192 : : error_sym(P, sym, "internal error: enum value type expected");
1193 : 0 : return -1;
1194 : : }
1195 : : /* Enum / union values cannot have metadata. */
1196 : : assert(member->metadata == 0);
1197 [ + + ]: 115 : if (is_union) {
1198 [ + + ]: 32 : if (member->symbol.ident == &P->t_none) {
1199 : : /* Handle implicit NONE specially. */
1200 : 11 : member->type.type = vt_missing;
1201 [ - + ]: 21 : } else if (member->type.type != vt_type_ref) {
1202 [ # # ]: 0 : if (member->type.type != vt_invalid) {
1203 : : error_sym_2(P, sym, "union member has unexpected type", &member->symbol);
1204 : : }
1205 : 0 : continue;
1206 : : } else {
1207 : 21 : type_sym = lookup_type_reference(P, ct->scope, member->type.ref);
1208 [ - + ]: 21 : if (!type_sym) {
1209 : 0 : error_ref_sym(P, member->type.ref, "unknown type reference used with union member", sym);
1210 : 0 : member->type.type = vt_invalid;
1211 : 0 : continue;
1212 : : } else {
1213 [ - + ]: 21 : if (type_sym->kind != fb_is_table) {
1214 : : error_sym_2(P, sym, "union member must reference a table, defined here", type_sym);
1215 : 0 : member->type.type = vt_invalid;
1216 : 0 : continue;
1217 : : }
1218 : 21 : member->type.type = vt_compound_type_ref;
1219 : 21 : member->type.ct = (fb_compound_type_t*)type_sym;
1220 : : /* Symbols have no size. */
1221 : 21 : member->size = 0;
1222 : : }
1223 : : }
1224 : : }
1225 [ + + ][ + + ]: 115 : if (!member->value.type && !first) {
1226 [ + + ]: 42 : if (index.type == vt_uint) {
1227 [ - + ][ # # ]: 33 : if (ct->type.st == fb_long && index.u == UINT64_MAX) {
1228 : : /* Not captured by range check. */
1229 : : error_sym(P, sym, "64-bit unsigned int overflow");
1230 : : }
1231 : 33 : index.u = index.u + 1;
1232 [ + + ]: 9 : } else if (index.type == vt_int && !first) {
1233 [ - + ][ # # ]: 8 : if (ct->type.st == fb_long && index.i == INT64_MAX) {
1234 : : /* Not captured by range check. */
1235 : : error_sym(P, sym, "64-bit signed int overflow");
1236 : : }
1237 : 8 : index.i = index.i + 1;
1238 [ + - ]: 1 : } else if (index.type == vt_bool && !first) {
1239 [ - + ]: 1 : if (index.b == 1) {
1240 : : error_sym(P, sym, "boolean overflow: cannot enumerate past true");
1241 : : }
1242 : 1 : index.b = 1;
1243 : : }
1244 : : }
1245 [ + + ]: 115 : if (bit_flags) {
1246 [ + + ]: 34 : if (member->value.type) {
1247 [ - + ]: 18 : if (member->value.type != vt_uint) {
1248 : : error_sym(P, sym, "enum value must be unsigned int when used with 'bit_flags'");
1249 : 0 : return -1;
1250 : : } else {
1251 : 18 : index = member->value;
1252 : : }
1253 : : }
1254 [ - + ]: 34 : if (index.u >= sizeof_scalar_type(ct->type.st) * 8) {
1255 : : error_sym(P, sym, "enum value out of range when used with 'bit_flags'");
1256 : 0 : return -1;
1257 : : }
1258 : 34 : member->value.u = 1LL << index.u;
1259 : 34 : member->value.type = vt_uint;
1260 [ - + ]: 34 : if (fb_coerce_scalar_type(P, sym, ct->type.st, &member->value)) {
1261 : : /* E.g. enumval = 15 causes signed overflow with short. */
1262 : : error_sym(P, sym, "enum value out of range when used with 'bit_flags'");
1263 : 0 : return -1;
1264 : : }
1265 : : } else {
1266 [ + + ]: 81 : if (member->value.type) {
1267 : 21 : index = member->value;
1268 : : /*
1269 : : * Captures errors in user assigned values. Also captures
1270 : : * overflow on auto-increment on all types except maximum
1271 : : * representation size, i.e. long or ulong which we handled
1272 : : * above.
1273 : : */
1274 [ + - ]: 21 : if (fb_coerce_scalar_type(P, sym, ct->type.st, &index)) {
1275 : : return -1;
1276 : : }
1277 : : }
1278 : 81 : member->value = index;
1279 : : }
1280 [ + + ][ + - ]: 115 : if (!first && P->opts.ascending_enum) {
1281 : : /* Without ascending enum we also allow duplicate values (but not names). */
1282 [ + + ][ + - ]: 69 : if ((index.type == vt_uint && index.u <= old_index.u) ||
[ + + ]
1283 [ - + ]: 23 : (index.type == vt_int && index.i <= old_index.i)) {
1284 [ # # ][ # # ]: 0 : if (is_union && old_index.u == 0) {
1285 : : /*
1286 : : * The user explicitly assigned zero, or less, to the first
1287 : : * element (here second element after parser injecting
1288 : : * the NONE element).
1289 : : */
1290 : : error_sym(P, sym, "union values must be positive, 0 is reserved for implicit 'NONE'");
1291 : 0 : member->value.type = vt_invalid;
1292 : 0 : return -1;
1293 : : }
1294 : : error_sym(P, sym, "enum values must be in ascending order");
1295 : 0 : member->value.type = vt_invalid;
1296 : 0 : return -1;
1297 : : }
1298 [ + + ][ - + ]: 69 : if (index.type == vt_bool && index.b <= old_index.b) {
1299 : : error_sym(P, sym, "enum of type bool can only enumerate from false (0) to true (1)");
1300 : 0 : member->value.type = vt_invalid;
1301 : 0 : return -1;
1302 : : }
1303 : : }
1304 : 115 : old_index = index;
1305 [ - + ]: 115 : if (add_to_value_set(&ct->value_set, &member->value)) {
1306 [ # # ]: 0 : if (is_union) {
1307 : : error_sym(P, sym, "union members require unique positive values (0 being reserved for 'NONE'");
1308 : 0 : member->value.type = vt_invalid;
1309 : 0 : return -1;
1310 : : } else {
1311 : : /*
1312 : : * With ascending enums this won't happen, but
1313 : : * otherwise flag secondary values so we can remove them
1314 : : * from inverse name mappings in code gen.
1315 : : */
1316 : 0 : member->symbol.flags |= fb_duplicate;
1317 : : }
1318 : : }
1319 [ - + ]: 115 : if (member->metadata) {
1320 : : error_sym(P, sym, "enum values cannot have attributes");
1321 : : /* Non-fatal. */
1322 : 0 : continue;
1323 : : }
1324 : : }
1325 : : return 0;
1326 : : }
1327 : :
1328 : : static inline int process_union(fb_parser_t *P, fb_compound_type_t *ct)
1329 : : {
1330 : 11 : return process_enum(P, ct);
1331 : : }
1332 : :
1333 : : static fb_member_t *original_order_members(fb_parser_t *P, fb_member_t *next)
1334 : : {
1335 : 1 : fb_member_t *head = 0;
1336 : : fb_member_t **tail = &head;
1337 : :
1338 : : /* Not used for now, but in case we need error messages etc. */
1339 : : (void)P;
1340 : :
1341 [ # # ][ + + ]: 10 : while (next) {
1342 : 9 : *tail = next;
1343 : 9 : tail = &next->order;
1344 : 9 : next = (fb_member_t *)(((fb_symbol_t *)next)->link);
1345 : : }
1346 : 1 : *tail = 0;
1347 : 0 : return head;
1348 : : }
1349 : :
1350 : : /*
1351 : : * Alignment of table offset fields are generally not stored, and
1352 : : * vectors store the element alignment for scalar types, so we
1353 : : * detect alignment based on type also. Unions are tricky since they
1354 : : * use a single byte type followed by an offset, but it is impractical
1355 : : * to store these separately so we sort by the type field.
1356 : : */
1357 : 142 : static fb_member_t *align_order_members(fb_parser_t *P, fb_member_t *members)
1358 : : {
1359 : : uint16_t i, j, k;
1360 : 71 : fb_member_t *heads[9] = {0};
1361 : 71 : fb_member_t **tails[9] = {0};
1362 : : fb_member_t *next = members;
1363 : :
1364 [ + + ]: 459 : while (next) {
1365 : 388 : k = next->align;
1366 [ + - ][ + + ]: 388 : switch (next->type.type) {
[ + - ][ + + ]
1367 : : case vt_compound_type_ref:
1368 [ + + + ]: 123 : switch (next->type.ct->symbol.kind) {
1369 : : case fb_is_struct:
1370 : : case fb_is_enum:
1371 : 388 : k = next->type.ct->align;
1372 : : break;
1373 : : case fb_is_union:
1374 : : /*
1375 : : * Unions align to their offsets because the type can
1376 : : * always be added last in a second pass since it is 1
1377 : : * byte.
1378 : : */
1379 : 12 : k = P->opts.offset_size;
1380 : : break;
1381 : : default:
1382 : 26 : k = P->opts.offset_size;
1383 : : break;
1384 : : }
1385 : : break;
1386 : : case vt_vector_compound_type_ref:
1387 : : case vt_string_type:
1388 : : case vt_vector_type:
1389 : : case vt_vector_string_type:
1390 : 91 : k = P->opts.offset_size;
1391 : : break;
1392 : : case vt_invalid:
1393 : : /* Just to have some sane behavior. */
1394 : : return original_order_members(P, members);
1395 : : default:
1396 : : k = next->align;
1397 : : break;
1398 : : }
1399 : : assert(k > 0);
1400 : : i = 0;
1401 [ + + ]: 1063 : while (k >>= 1) {
1402 : 675 : ++i;
1403 : : }
1404 : : /* Normally the largest alignment is 256, but otherwise we group them together. */
1405 [ - + ]: 388 : if (i > 7) {
1406 : : i = 7;
1407 : : }
1408 [ + + ]: 388 : if (!heads[i]) {
1409 : 139 : heads[i] = next;
1410 : : } else {
1411 : 249 : *tails[i] = next;
1412 : : }
1413 : 388 : tails[i] = &next->order;
1414 : 388 : next = (fb_member_t *)(((fb_symbol_t *)next)->link);
1415 : : }
1416 : : i = j = 8;
1417 : 245 : tails[8] = &heads[8];
1418 [ + + ]: 245 : while (j) {
1419 [ + + ][ + + ]: 603 : while (i && !heads[--i]) {
1420 : : }
1421 : 174 : *tails[j] = heads[i];
1422 : : j = i;
1423 : : }
1424 : 71 : return heads[8];
1425 : : }
1426 : :
1427 : 34 : int fb_build_schema(fb_parser_t *P)
1428 : : {
1429 : 34 : fb_schema_t *S = &P->schema;
1430 : : fb_symbol_t *sym, *old_sym;
1431 : : fb_name_t *old_name;
1432 : : fb_compound_type_t *ct;
1433 : : fb_attribute_t *a;
1434 : :
1435 : : /* Make sure self is visible at this point in time. */
1436 : : assert(ptr_set_exists(&P->schema.visible_schema, &P->schema));
1437 [ + + ]: 205 : for (sym = S->symbols; sym; sym = sym->link) {
1438 [ + - ]: 171 : switch (sym->kind) {
1439 : : case fb_is_table:
1440 : : case fb_is_enum:
1441 : : case fb_is_union:
1442 : : case fb_is_struct:
1443 : : case fb_is_rpc_service:
1444 : : ct = (fb_compound_type_t *)sym;
1445 : 171 : set_type_hash(ct);
1446 : 171 : ct->schema = &P->schema;
1447 [ + - - + ]: 342 : if (ct->scope && (old_sym = define_fb_symbol(&ct->scope->symbol_index, sym))) {
1448 : : error_sym_2(P, sym, "symbol already defined here", old_sym);
1449 : : }
1450 : : }
1451 : : }
1452 : :
1453 : : /*
1454 : : * Known attributes will be pre-defined if not provided by the
1455 : : * user. After that point, all attribute references must be
1456 : : * defined.
1457 : : */
1458 [ + + ]: 55 : for (a = (fb_attribute_t *)S->attributes; a; a = (fb_attribute_t *)a->name.link) {
1459 [ - + ]: 21 : if ((old_name = define_fb_name(&S->root_schema->attribute_index, &a->name))) {
1460 : 0 : error_name(P, &a->name, "attribute already defined");
1461 : : }
1462 : : }
1463 : 34 : install_known_attributes(P);
1464 : :
1465 [ + - ]: 34 : if (!P->opts.hide_later_enum) {
1466 [ + + ]: 205 : for (sym = S->symbols; sym; sym = sym->link) {
1467 [ + + ]: 171 : switch (sym->kind) {
1468 : : case fb_is_enum:
1469 : : ct = (fb_compound_type_t *)sym;
1470 [ - + ]: 35 : if (process_enum(P, ct)) {
1471 : 0 : ct->type.type = vt_invalid;
1472 : 0 : continue;
1473 : : }
1474 : : break;
1475 : : default:
1476 : 136 : continue;
1477 : : }
1478 : : }
1479 : : }
1480 : :
1481 : : /*
1482 : : * Resolve type references both earlier and later than point of
1483 : : * reference. This also supports recursion for tables and unions.
1484 : : */
1485 [ + + ]: 205 : for (sym = S->symbols; sym; sym = sym->link) {
1486 [ + + + + : 171 : switch (sym->kind) {
+ - ]
1487 : : case fb_is_struct:
1488 : : ct = (fb_compound_type_t *)sym;
1489 [ - + ]: 52 : if (process_struct(P, ct)) {
1490 : 0 : ct->type.type = vt_invalid;
1491 : 0 : continue;
1492 : : }
1493 : : break;
1494 : : case fb_is_table:
1495 : : /* Handle after structs and enums. */
1496 : 72 : continue;
1497 : : case fb_is_rpc_service:
1498 : : /*
1499 : : * Also handle rpc_service later like tables, just in case
1500 : : * we allow non-table types in request/response type.
1501 : : */
1502 : 1 : continue;
1503 : : case fb_is_enum:
1504 [ - + ]: 35 : if (P->opts.hide_later_enum) {
1505 : : ct = (fb_compound_type_t *)sym;
1506 [ # # ]: 0 : if (process_enum(P, ct)) {
1507 : 0 : ct->type.type = vt_invalid;
1508 : 0 : continue;
1509 : : }
1510 : : }
1511 : : break;
1512 : : case fb_is_union:
1513 : : ct = (fb_compound_type_t *)sym;
1514 [ - + ]: 11 : if (process_union(P, ct)) {
1515 : 0 : ct->type.type = vt_invalid;
1516 : 0 : continue;
1517 : : }
1518 : : break;
1519 : : default:
1520 : : error_sym(P, sym, "internal error: unexpected symbol at schema level");
1521 : 0 : return -1;
1522 : : }
1523 : : }
1524 [ + + ]: 205 : for (sym = P->schema.symbols; sym; sym = sym->link) {
1525 [ + + ]: 171 : switch (sym->kind) {
1526 : : case fb_is_struct:
1527 : : /*
1528 : : * Structs need two stages, first process symbols, then
1529 : : * analyze for size, alignment, and circular references.
1530 : : */
1531 : : ct = (fb_compound_type_t *)sym;
1532 [ + - ][ - + ]: 52 : if (ct->type.type != vt_invalid && analyze_struct(P, ct)) {
1533 : 0 : ct->type.type = vt_invalid;
1534 : 0 : continue;
1535 : : }
1536 : : break;
1537 : : default:
1538 : 119 : continue;
1539 : : }
1540 : : }
1541 [ + + ]: 205 : for (sym = P->schema.symbols; sym; sym = sym->link) {
1542 [ + + + ]: 171 : switch (sym->kind) {
1543 : : case fb_is_table:
1544 : : ct = (fb_compound_type_t *)sym;
1545 : : /* Only now is the full struct size available. */
1546 [ + - ][ - + ]: 72 : if (ct->type.type != vt_invalid && process_table(P, ct)) {
1547 : 0 : ct->type.type = vt_invalid;
1548 : 0 : continue;
1549 : : }
1550 : : break;
1551 : : case fb_is_rpc_service:
1552 : : ct = (fb_compound_type_t *)sym;
1553 : : /* Only now is the full struct size available. */
1554 [ + - ][ - + ]: 1 : if (ct->type.type != vt_invalid && process_rpc_service(P, ct)) {
1555 : 0 : ct->type.type = vt_invalid;
1556 : 0 : continue;
1557 : : }
1558 : : }
1559 : : }
1560 : : revert_order(&P->schema.ordered_structs);
1561 [ + + ]: 205 : for (sym = P->schema.symbols; sym; sym = sym->link) {
1562 [ + + ]: 171 : switch (sym->kind) {
1563 : : case fb_is_table:
1564 : : ct = (fb_compound_type_t *)sym;
1565 [ + + ]: 72 : if (ct->metadata_flags & fb_f_original_order) {
1566 : 1 : ct->ordered_members = original_order_members(P, (fb_member_t *)ct->members);
1567 : : } else {
1568 : 71 : ct->ordered_members = align_order_members(P, (fb_member_t *)ct->members);
1569 : : }
1570 : : }
1571 : : }
1572 [ + + ]: 34 : if (!S->root_type.name) {
1573 [ - + ]: 23 : if (P->opts.require_root_type) {
1574 : : error(P, "root type not declared");
1575 : : }
1576 : : } else {
1577 : 22 : sym = S->root_type.type = lookup_type_reference(P,
1578 : : S->root_type.scope, S->root_type.name);
1579 [ - + ]: 11 : if (!sym) {
1580 : 0 : error_ref(P, S->root_type.name, "root type not found");
1581 [ + - ]: 11 : } else if (P->opts.allow_struct_root) {
1582 [ - + ]: 11 : if (sym->kind != fb_is_struct && sym->kind != fb_is_table) {
1583 : 0 : error_ref(P, S->root_type.name, "root type must be a struct or a table");
1584 : : } else {
1585 : : S->root_type.type = sym;
1586 : : }
1587 : : } else {
1588 [ # # ]: 0 : if (sym->kind != fb_is_table) {
1589 : 0 : error_ref(P, S->root_type.name, "root type must be a table");
1590 : : } else {
1591 : : S->root_type.type = sym;
1592 : : }
1593 : : }
1594 : 11 : S->root_type.name = 0;
1595 : : }
1596 : 34 : P->has_schema = !P->failed;
1597 : 34 : return P->failed;
1598 : : }
|