LCOV - code coverage report
Current view: top level - src/runtime - builder.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 500 599 83.5 %
Date: 2016-11-30 13:12:14 Functions: 69 94 73.4 %
Branches: 233 417 55.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Codegenerator for C, building FlatBuffers.
       3                 :            :  *
       4                 :            :  * There are several approaches, some light, some requiring a library,
       5                 :            :  * some with vectored I/O etc.
       6                 :            :  *
       7                 :            :  * Here we focus on a reasonable balance of light code and efficiency.
       8                 :            :  *
       9                 :            :  * Builder code is generated to a separate file that includes the
      10                 :            :  * generated read-only code.
      11                 :            :  *
      12                 :            :  * Mutable buffers are not supported in this version.
      13                 :            :  *
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <stdlib.h>
      17                 :            : #include <memory.h>
      18                 :            : #include <string.h>
      19                 :            : #include <assert.h>
      20                 :            : 
      21                 :            : #include "flatcc/flatcc_builder.h"
      22                 :            : #include "flatcc/flatcc_emitter.h"
      23                 :            : 
      24                 :            : /*
      25                 :            :  * `check` is designed to handle incorrect use errors that can be
      26                 :            :  * ignored in production of a tested product.
      27                 :            :  *
      28                 :            :  * `check_error` fails if condition is false and is designed to return an
      29                 :            :  * error code in production.
      30                 :            :  */
      31                 :            : 
      32                 :            : #if FLATCC_BUILDER_ASSERT_ON_ERROR
      33                 :            : #define check(cond, reason) FLATCC_BUILDER_ASSERT(cond, reason)
      34                 :            : #else
      35                 :            : #define check(cond) ((void)0)
      36                 :            : #endif
      37                 :            : 
      38                 :            : #if FLATCC_BUILDER_SKIP_CHECKS
      39                 :            : #define check_error(cond, err, reason) ((void)0)
      40                 :            : #else
      41                 :            : #define check_error(cond, err, reason) if (!(cond)) { check(cond, reason); return err; }
      42                 :            : #endif
      43                 :            : 
      44                 :            : /* `strnlen` not widely supported. */
      45                 :            : static inline size_t pstrnlen(const char *s, size_t max_len)
      46                 :            : {
      47                 :          5 :     const char *end = memchr(s, 0, max_len);
      48 [ +  + ][ +  - ]:          5 :     return end ? (size_t)(end - s) : max_len;
      49                 :            : }
      50                 :            : #undef strnlen
      51                 :            : #define strnlen pstrnlen
      52                 :            : 
      53                 :            : /* `align` must be a power of 2. */
      54                 :            : #define alignup(x, align) (((x) + (align) - 1) & ~((align) - 1))
      55                 :            : 
      56                 :            : /* Padding can be up to 255 zeroes, and 1 zero string termination byte.
      57                 :            :  * When two paddings are combined at nested buffers, we need twice that.
      58                 :            :  * Visible to emitter so it can test for zero padding in iov. */
      59                 :            : const uint8_t flatcc_builder_padding_base[512] = { 0 };
      60                 :            : #define _pad flatcc_builder_padding_base
      61                 :            : 
      62                 :            : #define uoffset_t flatbuffers_uoffset_t
      63                 :            : #define soffset_t flatbuffers_soffset_t
      64                 :            : #define voffset_t flatbuffers_voffset_t
      65                 :            : 
      66                 :            : #define store_uoffset __flatbuffers_uoffset_cast_to_pe
      67                 :            : #define store_voffset  __flatbuffers_voffset_cast_to_pe
      68                 :            : #define store_identifier __flatbuffers_uoffset_cast_to_pe
      69                 :            : 
      70                 :            : #define field_size sizeof(uoffset_t)
      71                 :            : #define max_offset_count FLATBUFFERS_COUNT_MAX(field_size)
      72                 :            : #define max_string_len FLATBUFFERS_COUNT_MAX(1)
      73                 :            : #define identifier_size FLATBUFFERS_IDENTIFIER_SIZE
      74                 :            : 
      75                 :            : #define iovec_t flatcc_iovec_t
      76                 :            : #define frame_size sizeof(__flatcc_builder_frame_t)
      77                 :            : #define frame(x) (B->frame[0].x)
      78                 :            : 
      79                 :            : typedef struct vtable_descriptor vtable_descriptor_t;
      80                 :            : struct vtable_descriptor {
      81                 :            :     /* Where the vtable is emitted. */
      82                 :            :     flatcc_builder_ref_t vt_ref;
      83                 :            :     /* Which buffer it was emitted to. */
      84                 :            :     flatcc_builder_ref_t buffer_mark;
      85                 :            :     /* Where the vtable is cached. */
      86                 :            :     uoffset_t vb_start;
      87                 :            :     /* Hash table collision chain. */
      88                 :            :     uoffset_t next;
      89                 :            : };
      90                 :            : 
      91                 :            : typedef struct flatcc_iov_state flatcc_iov_state_t;
      92                 :            : struct flatcc_iov_state {
      93                 :            :     size_t len;
      94                 :            :     int count;
      95                 :            :     flatcc_iovec_t iov[FLATCC_IOV_COUNT_MAX];
      96                 :            : };
      97                 :            : 
      98                 :            : #define iov_state_t flatcc_iov_state_t
      99                 :            : 
     100                 :            : /* This assumes `iov_state_t iov;` has been declared in scope */
     101                 :            : #define push_iov_cond(base, size, cond) if ((size) > 0 && (cond)) { iov.len += size;\
     102                 :            :         iov.iov[iov.count].iov_base = (void *)(base); iov.iov[iov.count].iov_len = (size); ++iov.count; }
     103                 :            : #define push_iov(base, size) push_iov_cond(base, size, 1)
     104                 :            : #define init_iov() { iov.len = 0; iov.count = 0; }
     105                 :            : 
     106                 :            : 
     107                 :        920 : int flatcc_builder_default_alloc(void *alloc_context, iovec_t *b, size_t request, int zero_fill, int hint)
     108                 :            : {
     109                 :            :     void *p;
     110                 :            :     size_t n;
     111                 :            : 
     112                 :            :     (void)alloc_context;
     113                 :            : 
     114         [ +  + ]:        920 :     if (request == 0) {
     115         [ +  + ]:        432 :         if (b->iov_base) {
     116                 :        421 :             free(b->iov_base);
     117                 :        421 :             b->iov_base = 0;
     118                 :        421 :             b->iov_len = 0;
     119                 :            :         }
     120                 :            :         return 0;
     121                 :            :     }
     122   [ +  +  +  +  :        488 :     switch (hint) {
                      + ]
     123                 :            :     case flatcc_builder_alloc_ds:
     124                 :            :         n = 256;
     125                 :            :         break;
     126                 :            :     case flatcc_builder_alloc_ht:
     127                 :            :         /* Should be exact size, or space size is just wasted. */
     128                 :            :         n = request;
     129                 :         54 :         break;
     130                 :            :     case flatcc_builder_alloc_fs:
     131                 :            :         n = sizeof(__flatcc_builder_frame_t) * 8;
     132                 :        488 :         break;
     133                 :            :     case flatcc_builder_alloc_us:
     134                 :            :         n = 64;
     135                 :         49 :         break;
     136                 :            :     default:
     137                 :            :         /*
     138                 :            :          * We have many small structures - vs stack for tables with few
     139                 :            :          * elements, and few offset fields in patch log. No need to
     140                 :            :          * overallocate in case of busy small messages.
     141                 :            :          */
     142                 :            :         n = 32;
     143                 :        266 :         break;
     144                 :            :     }
     145         [ +  + ]:        763 :     while (n < request) {
     146                 :        275 :         n *= 2;
     147                 :            :     }
     148 [ +  + ][ +  - ]:        488 :     if (request <= b->iov_len && b->iov_len / 2 >= n) {
     149                 :            :         /* Add hysteresis to shrink. */
     150                 :            :         return 0;
     151                 :            :     }
     152         [ +  - ]:        488 :     if (!(p = realloc(b->iov_base, n))) {
     153                 :            :         return -1;
     154                 :            :     }
     155                 :            :     /* Realloc might also shrink. */
     156 [ +  + ][ +  + ]:        488 :     if (zero_fill && b->iov_len < n) {
     157                 :        181 :         memset((uint8_t *)p + b->iov_len, 0, n - b->iov_len);
     158                 :            :     }
     159                 :        488 :     b->iov_base = p;
     160                 :        488 :     b->iov_len = n;
     161                 :        488 :     return 0;
     162                 :            : }
     163                 :            : 
     164                 :            : #define T_ptr(base, pos) ((void *)((uint8_t *)(base) + (uoffset_t)(pos)))
     165                 :            : #define ds_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_ds].iov_base, (pos)))
     166                 :            : #define vs_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vs].iov_base, (pos)))
     167                 :            : #define pl_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_pl].iov_base, (pos)))
     168                 :            : #define us_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_us].iov_base, (pos)))
     169                 :            : #define vd_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vd].iov_base, (pos)))
     170                 :            : #define vb_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vb].iov_base, (pos)))
     171                 :            : #define vs_offset(ptr) ((uoffset_t)((size_t)(ptr) - (size_t)B->buffers[flatcc_builder_alloc_vs].iov_base))
     172                 :            : #define pl_offset(ptr) ((uoffset_t)((size_t)(ptr) - (size_t)B->buffers[flatcc_builder_alloc_pl].iov_base))
     173                 :            : #define us_offset(ptr) ((uoffset_t)((size_t)(ptr) - (size_t)B->buffers[flatcc_builder_alloc_us].iov_base))
     174                 :            : 
     175                 :            : #define table_limit (FLATBUFFERS_VOFFSET_MAX - field_size + 1)
     176                 :            : #define data_limit (FLATBUFFERS_UOFFSET_MAX - field_size + 1)
     177                 :            : 
     178                 :            : #define set_identifier(id) memcpy(&B->identifier, (id) ? (void *)(id) : (void *)_pad, identifier_size)
     179                 :            : 
     180                 :            : /* This also returns true if no buffer has been started. */
     181                 :            : #define is_top_buffer(B) (B->buffer_mark == 0)
     182                 :            : 
     183                 :            : /*
     184                 :            :  * Tables use a stack represention better suited for quickly adding
     185                 :            :  * fields to tables, but it must occasionally be refreshed following
     186                 :            :  * reallocation or reentry from child frame.
     187                 :            :  */
     188                 :            : static inline void refresh_ds(flatcc_builder_t *B, uoffset_t type_limit)
     189                 :            : {
     190                 :            :     iovec_t *buf = B->buffers + flatcc_builder_alloc_ds;
     191                 :            : 
     192                 :      66851 :     B->ds = ds_ptr(B->ds_first);
     193                 :      66851 :     B->ds_limit = (uoffset_t)buf->iov_len - B->ds_first;
     194                 :            :     /*
     195                 :            :      * So we don't allocate outside tables representation size, nor our
     196                 :            :      * current buffer size.
     197                 :            :      */
     198 [ +  + ][ -  + ]:      66851 :     if (B->ds_limit > type_limit) {
         [ -  + ][ -  + ]
         [ +  + ][ -  + ]
     199                 :      22020 :         B->ds_limit = type_limit;
     200                 :            :     }
     201                 :            :     /* So exit frame can refresh fast. */
     202                 :      66851 :     frame(type_limit) = type_limit;
     203                 :            : }
     204                 :            : 
     205                 :         65 : static int reserve_ds(flatcc_builder_t *B, size_t need, uoffset_t limit)
     206                 :            : {
     207                 :         65 :     iovec_t *buf = B->buffers + flatcc_builder_alloc_ds;
     208                 :            : 
     209         [ +  - ]:         65 :     if (B->alloc(B->alloc_context, buf, B->ds_first + need, 1, flatcc_builder_alloc_ds)) {
     210                 :            :         return -1;
     211                 :            :     }
     212                 :            :     refresh_ds(B, limit);
     213                 :         65 :     return 0;
     214                 :            : }
     215                 :            : 
     216                 :            : /*
     217                 :            :  * Make sure there is always an extra zero termination on stack
     218                 :            :  * even if it isn't emitted such that string updates may count
     219                 :            :  * on zero termination being present always.
     220                 :            :  */
     221                 :    2211221 : static inline void *push_ds(flatcc_builder_t *B, uoffset_t size)
     222                 :            : {
     223                 :            :     size_t offset;
     224                 :            : 
     225                 :    2211221 :     offset = B->ds_offset;
     226         [ +  + ]:    2211221 :     if ((B->ds_offset += size) >= B->ds_limit) {
     227         [ +  - ]:         13 :         if (reserve_ds(B, B->ds_offset + 1, data_limit)) {
     228                 :            :             return 0;
     229                 :            :         }
     230                 :            :     }
     231                 :    2211221 :     return B->ds + offset;
     232                 :            : }
     233                 :            : 
     234                 :            : static inline void unpush_ds(flatcc_builder_t *B, uoffset_t size)
     235                 :            : {
     236                 :          5 :     B->ds_offset -= size;
     237                 :          5 :     memset(B->ds + B->ds_offset, 0, size);
     238                 :            : }
     239                 :            : 
     240                 :    2200043 : static inline void *push_ds_copy(flatcc_builder_t *B, const void *data, uoffset_t size)
     241                 :            : {
     242                 :            :     void *p;
     243                 :            : 
     244         [ +  - ]:    2200043 :     if (!(p = push_ds(B, size))) {
     245                 :            :         return 0;
     246                 :            :     }
     247                 :    2200043 :     memcpy(p, data, size);
     248                 :    2200043 :     return p;
     249                 :            : }
     250                 :            : 
     251                 :        342 : static inline void *push_ds_field(flatcc_builder_t *B, uoffset_t size, uint16_t align, voffset_t id)
     252                 :            : {
     253                 :            :     uoffset_t offset;
     254                 :            : 
     255                 :            :     /*
     256                 :            :      * We calculate table field alignment relative to first entry, not
     257                 :            :      * header field with vtable offset.
     258                 :            :      *
     259                 :            :      * Note: >= comparison handles special case where B->ds is not
     260                 :            :      * allocated yet and size is 0 so the return value would be mistaken
     261                 :            :      * for an error.
     262                 :            :      */
     263                 :        342 :     offset = alignup(B->ds_offset, align);
     264         [ +  + ]:        342 :     if ((B->ds_offset = offset + size) >= B->ds_limit) {
     265         [ +  - ]:          6 :         if (reserve_ds(B, B->ds_offset + 1, table_limit)) {
     266                 :            :             return 0;
     267                 :            :         }
     268                 :            :     }
     269                 :        342 :     B->vs[id] = (voffset_t)(offset + field_size);
     270         [ +  + ]:        342 :     if (id >= B->id_end) {
     271                 :        253 :         B->id_end = id + 1;
     272                 :            :     }
     273                 :        342 :     return B->ds + offset;
     274                 :            : }
     275                 :            : 
     276                 :      22383 : static inline void *push_ds_offset_field(flatcc_builder_t *B, voffset_t id)
     277                 :            : {
     278                 :            :     uoffset_t offset;
     279                 :            : 
     280                 :      22383 :     offset = alignup(B->ds_offset, field_size);
     281         [ +  + ]:      22383 :     if ((B->ds_offset = offset + field_size) > B->ds_limit) {
     282         [ +  - ]:         46 :         if (reserve_ds(B, B->ds_offset, table_limit)) {
     283                 :            :             return 0;
     284                 :            :         }
     285                 :            :     }
     286                 :      22383 :     B->vs[id] = (voffset_t)(offset + field_size);
     287         [ +  + ]:      22383 :     if (id >= B->id_end) {
     288                 :      22359 :         B->id_end = id + 1;
     289                 :            :     }
     290                 :      22383 :     *B->pl++ = (flatbuffers_voffset_t)offset;
     291                 :      22383 :     return B->ds + offset;
     292                 :            : }
     293                 :            : 
     294                 :            : static inline void *reserve_buffer(flatcc_builder_t *B, int alloc_type, size_t used, size_t need, int zero_init)
     295                 :            : {
     296                 :      23067 :     iovec_t *buf = B->buffers + alloc_type;
     297                 :            : 
     298 [ +  + ][ +  + ]:      23067 :     if (used + need > buf->iov_len) {
         [ +  + ][ +  - ]
         [ +  - ][ +  + ]
                 [ +  + ]
     299 [ +  - ][ +  - ]:        369 :         if (B->alloc(B->alloc_context, buf, used + need, zero_init, alloc_type)) {
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     300                 :            :             check(0, "memory allocation failed");
     301                 :            :             return 0;
     302                 :            :         }
     303                 :            :     }
     304                 :      23067 :     return (void *)((size_t)buf->iov_base + used);
     305                 :            : }
     306                 :            : 
     307                 :      11289 : static inline int reserve_fields(flatcc_builder_t *B, int count)
     308                 :            : {
     309                 :            :     uoffset_t used, need;
     310                 :            : 
     311                 :            :     /* Provide faster stack operations for common table operations. */
     312                 :      11289 :     used = frame(table.vs_end) + frame(table.id_end) * sizeof(voffset_t);
     313                 :      11289 :     need = (count + 2) * sizeof(voffset_t);
     314         [ +  - ]:      11289 :     if (!(B->vs = reserve_buffer(B, flatcc_builder_alloc_vs, used, need, 1))) {
     315                 :            :         return -1;
     316                 :            :     }
     317                 :            :     /* Move past header for convenience. */
     318                 :      11289 :     B->vs += 2;
     319                 :      11289 :     used = frame(table.pl_end);
     320                 :            :     /* Add one to handle special case of first table being empty. */
     321                 :      11289 :     need = count * sizeof(*(B->pl)) + 1;
     322         [ +  - ]:      11289 :     if (!(B->pl = reserve_buffer(B, flatcc_builder_alloc_pl, used, need, 0))) {
     323                 :            :         return -1;
     324                 :            :     }
     325                 :      11289 :     return 0;
     326                 :            : }
     327                 :            : 
     328                 :         54 : static int alloc_ht(flatcc_builder_t *B)
     329                 :            : {
     330                 :         54 :     iovec_t *buf = B->buffers + flatcc_builder_alloc_ht;
     331                 :            : 
     332                 :            :     size_t size;
     333                 :            :     /* Allocate null entry so we can check for return errors. */
     334                 :            :     assert(B->vd_end == 0);
     335         [ +  - ]:         54 :     if (!reserve_buffer(B, flatcc_builder_alloc_vd, B->vd_end, sizeof(vtable_descriptor_t), 0)) {
     336                 :            :         return -1;
     337                 :            :     }
     338                 :         54 :     B->vd_end = sizeof(vtable_descriptor_t);
     339                 :            :     size = field_size * FLATCC_BUILDER_MIN_HASH_COUNT;
     340         [ +  - ]:         54 :     if (B->alloc(B->alloc_context, buf, size, 1, flatcc_builder_alloc_ht)) {
     341                 :            :         return -1;
     342                 :            :     }
     343         [ -  + ]:         54 :     while (size * 2 <= buf->iov_len) {
     344                 :            :         size *= 2;
     345                 :            :     }
     346                 :         54 :     B->ht_mask = size / field_size - 1;
     347                 :         54 :     return 0;
     348                 :            : }
     349                 :            : 
     350                 :      11289 : static inline uoffset_t *lookup_ht(flatcc_builder_t *B, uint32_t hash)
     351                 :            : {
     352                 :            :     uoffset_t *T;
     353                 :            : 
     354         [ +  + ]:      11289 :     if (B->ht_mask == 0) {
     355         [ +  - ]:         54 :         if (alloc_ht(B)) {
     356                 :            :             return 0;
     357                 :            :         }
     358                 :            :     }
     359                 :      11289 :     T = B->buffers[flatcc_builder_alloc_ht].iov_base;
     360                 :      11289 :     return &T[hash & B->ht_mask];
     361                 :            : }
     362                 :            : 
     363                 :          0 : void flatcc_builder_flush_vtable_cache(flatcc_builder_t *B)
     364                 :            : {
     365                 :            :     iovec_t *buf = B->buffers + flatcc_builder_alloc_ht;
     366                 :            : 
     367 [ #  # ][ #  # ]:          0 :     if (B->ht_mask == 0) {
     368                 :            :         return;
     369                 :            :     }
     370                 :          0 :     memset(buf->iov_base, 0, buf->iov_len);
     371                 :            :     /* Reserve the null entry. */
     372                 :          0 :     B->vd_end = sizeof(vtable_descriptor_t);
     373                 :          0 :     B->vb_end = 0;
     374                 :            : }
     375                 :            : 
     376                 :          1 : int flatcc_builder_custom_init(flatcc_builder_t *B,
     377                 :            :         flatcc_builder_emit_fun *emit, void *emit_context,
     378                 :            :         flatcc_builder_alloc_fun *alloc, void *alloc_context)
     379                 :            : {
     380                 :            :     /*
     381                 :            :      * Do not allocate anything here. Only the required buffers will be
     382                 :            :      * allocated. For simple struct buffers, no allocation is required
     383                 :            :      * at all.
     384                 :            :      */
     385                 :         54 :     memset(B, 0, sizeof(*B));
     386                 :            : 
     387         [ -  + ]:          1 :     if (emit == 0) {
     388                 :         53 :         B->is_default_emitter = 1;
     389                 :            :         emit = flatcc_emitter;
     390                 :          0 :         emit_context = &B->default_emit_context;
     391                 :            :     }
     392         [ +  - ]:          1 :     if (alloc == 0) {
     393                 :            :         alloc = flatcc_builder_default_alloc;
     394                 :            :     }
     395                 :         54 :     B->alloc_context = alloc_context;
     396                 :         54 :     B->alloc = alloc;
     397                 :         54 :     B->emit_context = emit_context;
     398                 :         54 :     B->emit = emit;
     399                 :          1 :     return 0;
     400                 :            : }
     401                 :            : 
     402                 :         53 : int flatcc_builder_init(flatcc_builder_t *B)
     403                 :            : {
     404                 :         53 :     return flatcc_builder_custom_init(B, 0, 0, 0, 0);
     405                 :            : }
     406                 :            : 
     407                 :         31 : int flatcc_builder_custom_reset(flatcc_builder_t *B, int set_defaults, int reduce_buffers)
     408                 :            : {
     409                 :            :     iovec_t *buf;
     410                 :            :     int i;
     411                 :            : 
     412         [ +  + ]:        279 :     for (i = 0; i < FLATCC_BUILDER_ALLOC_BUFFER_COUNT; ++i) {
     413                 :        248 :         buf = B->buffers + i;
     414         [ +  + ]:        248 :         if (buf->iov_base) {
     415                 :            :             /* Don't try to reduce the hash table. */
     416         [ -  + ]:        204 :             if (i != flatcc_builder_alloc_ht &&
     417         [ #  # ]:          0 :                 reduce_buffers && B->alloc(B->alloc_context, buf, 1, 1, i)) {
     418                 :            :                 return -1;
     419                 :            :             }
     420                 :        204 :             memset(buf->iov_base, 0, buf->iov_len);
     421                 :            :         } else {
     422                 :            :             assert(buf->iov_len == 0);
     423                 :            :         }
     424                 :            :     }
     425                 :         31 :     B->vb_end = 0;
     426         [ +  + ]:         31 :     if (B->vd_end > 0) {
     427                 :            :         /* Reset past null entry. */
     428                 :         29 :         B->vd_end = sizeof(vtable_descriptor_t);
     429                 :            :     }
     430                 :         31 :     B->min_align = 0;
     431                 :         31 :     B->emit_start = 0;
     432                 :         31 :     B->emit_end = 0;
     433                 :         31 :     B->level = 0;
     434                 :         31 :     B->limit_level = 0;
     435                 :         31 :     B->ds_offset = 0;
     436                 :         31 :     B->ds_limit = 0;
     437                 :            :     /* Needed for correct offset calculation. */
     438                 :         31 :     B->ds = B->buffers[flatcc_builder_alloc_ds].iov_base;
     439                 :         31 :     B->pl = B->buffers[flatcc_builder_alloc_pl].iov_base;
     440                 :         31 :     B->vs = B->buffers[flatcc_builder_alloc_vs].iov_base;
     441                 :         31 :     B->frame = 0;
     442         [ -  + ]:         31 :     if (set_defaults) {
     443                 :          0 :         B->vb_flush_limit = 0;
     444                 :          0 :         B->max_level = 0;
     445                 :          0 :         B->disable_vt_clustering = 0;
     446                 :            :     }
     447         [ +  - ]:         31 :     if (B->is_default_emitter) {
     448                 :         31 :         flatcc_emitter_reset(&B->default_emit_context);
     449                 :            :     }
     450                 :            :     return 0;
     451                 :            : }
     452                 :            : 
     453                 :         31 : int flatcc_builder_reset(flatcc_builder_t *B)
     454                 :            : {
     455                 :         31 :     return flatcc_builder_custom_reset(B, 0, 0);
     456                 :            : }
     457                 :            : 
     458                 :         54 : void flatcc_builder_clear(flatcc_builder_t *B)
     459                 :            : {
     460                 :            :     iovec_t *buf;
     461                 :            :     int i;
     462                 :            : 
     463         [ +  + ]:        486 :     for (i = 0; i < FLATCC_BUILDER_ALLOC_BUFFER_COUNT; ++i) {
     464                 :        432 :         buf = B->buffers + i;
     465                 :        432 :         B->alloc(B->alloc_context, buf, 0, 0, i);
     466                 :            :     }
     467         [ +  + ]:         54 :     if (B->is_default_emitter) {
     468                 :         53 :         flatcc_emitter_clear(&B->default_emit_context);
     469                 :            :     }
     470                 :         54 :     memset(B, 0, sizeof(*B));
     471                 :         54 : }
     472                 :            : 
     473                 :            : static inline void set_min_align(flatcc_builder_t *B, uint16_t align)
     474                 :            : {
     475 [ #  # ][ +  + ]:      55962 :     if (B->min_align < align) {
         [ +  + ][ +  + ]
         [ -  + ][ +  - ]
         [ -  + ][ -  + ]
     476                 :         96 :         B->min_align = align;
     477                 :            :     }
     478                 :            : }
     479                 :            : 
     480                 :            : /*
     481                 :            :  * It's a max, but the minimum viable alignment is the largest observed
     482                 :            :  * alignment requirement, but no larger.
     483                 :            :  */
     484                 :            : static inline void get_min_align(uint16_t *align, uint16_t b)
     485                 :            : {
     486 [ +  + ][ -  + ]:      33402 :     if (*align < b) {
         [ +  - ][ -  + ]
                 [ -  + ]
     487                 :          0 :         *align = b;
     488                 :            :     }
     489                 :            : }
     490                 :            : 
     491                 :         49 : void *flatcc_builder_enter_user_frame(flatcc_builder_t *B, size_t size)
     492                 :            : {
     493                 :            :     size_t *frame;
     494                 :            : 
     495                 :         49 :     size = alignup(size, sizeof(size_t)) + sizeof(size_t);
     496                 :            : 
     497         [ +  - ]:         49 :     if (!(frame = reserve_buffer(B, flatcc_builder_alloc_us, B->user_frame_end, size, 0))) {
     498                 :            :         return 0;
     499                 :            :     }
     500                 :         49 :     memset(frame, 0, size);
     501                 :         49 :     *frame++ = B->user_frame_offset;
     502                 :         49 :     B->user_frame_offset = B->user_frame_end;
     503                 :         49 :     B->user_frame_end += size;
     504                 :         49 :     return frame;
     505                 :            : }
     506                 :            : 
     507                 :         49 : void flatcc_builder_exit_user_frame(flatcc_builder_t *B)
     508                 :            : {
     509                 :            :     size_t *hdr;
     510                 :            : 
     511                 :         49 :     hdr = us_ptr(B->user_frame_offset);
     512                 :         49 :     B->user_frame_end = B->user_frame_offset;
     513                 :         49 :     B->user_frame_offset = *hdr;
     514                 :         49 : }
     515                 :            : 
     516                 :         61 : void *flatcc_builder_get_user_frame(flatcc_builder_t *B)
     517                 :            : {
     518                 :         61 :     return us_ptr(B->user_frame_offset + sizeof(size_t));
     519                 :            : }
     520                 :            : 
     521                 :          0 : int flatcc_builder_has_user_frame(flatcc_builder_t *B)
     522                 :            : {
     523                 :          0 :     return B->user_frame_end != 0;
     524                 :            : }
     525                 :            : 
     526                 :      33435 : static int enter_frame(flatcc_builder_t *B, uint16_t align)
     527                 :            : {
     528         [ +  + ]:      33435 :     if (++B->level > B->limit_level) {
     529 [ -  + ][ #  # ]:         82 :         if (B->max_level > 0 && B->level > B->max_level) {
     530                 :            :             return -1;
     531                 :            :         }
     532         [ +  - ]:         82 :         if (!(B->frame = reserve_buffer(B, flatcc_builder_alloc_fs, B->level * frame_size, frame_size, 0))) {
     533                 :            :             return -1;
     534                 :            :         }
     535                 :         82 :         B->limit_level = (int)(B->buffers[flatcc_builder_alloc_fs].iov_len / frame_size);
     536 [ -  + ][ #  # ]:         82 :         if (B->max_level > 0 && B->max_level < B->limit_level) {
     537                 :          0 :             B->limit_level = B->max_level;
     538                 :            :         }
     539                 :            :     } else {
     540                 :      33353 :         ++B->frame;
     541                 :            :     }
     542                 :      33435 :     frame(ds_offset) = B->ds_offset;
     543                 :      33435 :     frame(align) = B->align;
     544                 :      33435 :     B->align = align;
     545                 :            :     /* Note: do not assume padding before first has been allocated! */
     546                 :      33435 :     frame(ds_first) = B->ds_first;
     547                 :      33435 :     frame(type_limit) = data_limit;
     548                 :      33435 :     B->ds_first = alignup(B->ds_first + B->ds_offset, 8);
     549                 :      33435 :     B->ds_offset = 0;
     550                 :      33435 :     return 0;
     551                 :            : }
     552                 :            : 
     553                 :      33435 : static inline void exit_frame(flatcc_builder_t *B)
     554                 :            : {
     555                 :      33435 :     memset(B->ds, 0, B->ds_offset);
     556                 :      33435 :     B->ds_offset = frame(ds_offset);
     557                 :      33435 :     B->ds_first = frame(ds_first);
     558                 :      33435 :     refresh_ds(B, frame(type_limit));
     559                 :            : 
     560                 :            :     /*
     561                 :            :      * Restore local alignment: e.g. a table should not change alignment
     562                 :            :      * because a child table was just created elsewhere in the buffer,
     563                 :            :      * but the overall alignment (min align), should be aware of it.
     564                 :            :      * Each buffer has its own min align that then migrates up without
     565                 :            :      * being affected by sibling or child buffers.
     566                 :            :      */
     567                 :      33435 :     set_min_align(B, B->align);
     568                 :      33435 :     B->align = frame(align);
     569                 :            : 
     570                 :      33435 :     --B->frame;
     571                 :      33435 :     --B->level;
     572                 :      33435 : }
     573                 :            : 
     574                 :            : static inline uoffset_t front_pad(flatcc_builder_t *B, uoffset_t size, uint16_t align)
     575                 :            : {
     576                 :      33667 :     return (B->emit_start - size) & (align - 1);
     577                 :            : }
     578                 :            : 
     579                 :            : static inline uoffset_t back_pad(flatcc_builder_t *B, uint16_t align)
     580                 :            : {
     581                 :         82 :     return (B->emit_end) & (align - 1);
     582                 :            : }
     583                 :            : 
     584                 :      33669 : static inline flatcc_builder_ref_t emit_front(flatcc_builder_t *B, iov_state_t *iov)
     585                 :            : {
     586                 :            :     flatcc_builder_ref_t ref;
     587                 :            : 
     588                 :            :     /*
     589                 :            :      * We might have overflow when including headers, but without
     590                 :            :      * headers we should have checks to prevent overflow in the
     591                 :            :      * uoffset_t range, hence we subtract 16 to be safe. With that
     592                 :            :      * guarantee we can also make a safe check on the soffset_t range.
     593                 :            :      *
     594                 :            :      * We only allow buffers half the theoritical size of
     595                 :            :      * FLATBUFFERS_UOFFSET_MAX so we can safely use signed references.
     596                 :            :      *
     597                 :            :      * NOTE: vtables vt_offset field is signed, and the check in create
     598                 :            :      * table only ensures the signed limit. The check would fail if the
     599                 :            :      * total buffer size could grow beyond UOFFSET_MAX, and we prevent
     600                 :            :      * that by limiting the lower end to SOFFSET_MIN, and the upper end
     601                 :            :      * at emit_back to SOFFSET_MAX.
     602                 :            :      */
     603                 :      33669 :     ref = B->emit_start - (flatcc_builder_ref_t)iov->len;
     604 [ +  - ][ +  - ]:      33669 :     if ((iov->len > 16 && iov->len - 16 > FLATBUFFERS_UOFFSET_MAX) || ref >= B->emit_start) {
     605                 :            :         check(0, "buffer too large to represent");
     606                 :            :         return 0;
     607                 :            :     }
     608         [ +  - ]:      33669 :     if (B->emit(B->emit_context, iov->iov, iov->count, ref, iov->len)) {
     609                 :            :         check(0, "emitter rejected buffer content");
     610                 :            :         return 0;
     611                 :            :     }
     612                 :      33669 :     return B->emit_start = ref;
     613                 :            : }
     614                 :            : 
     615                 :            : static inline flatcc_builder_ref_t emit_back(flatcc_builder_t *B, iov_state_t *iov)
     616                 :            : {
     617                 :            :     flatcc_builder_ref_t ref;
     618                 :            : 
     619                 :        150 :     ref = B->emit_end;
     620                 :        150 :     B->emit_end = ref + (flatcc_builder_ref_t)iov->len;
     621                 :            :     /*
     622                 :            :      * Similar to emit_front check, but since we only emit vtables and
     623                 :            :      * padding at the back, we are not concerned with iov->len overflow,
     624                 :            :      * only total buffer overflow.
     625                 :            :      *
     626                 :            :      * With this check, vtable soffset references at table header can
     627                 :            :      * still overflow in extreme cases, so this must be checked
     628                 :            :      * separately.
     629                 :            :      */
     630 [ +  - ][ #  # ]:        150 :     if (B->emit_end < ref) {
     631                 :            :         check(0, "buffer too large to represent");
     632                 :            :         return 0;
     633                 :            :     }
     634 [ +  - ][ #  # ]:        150 :     if (B->emit(B->emit_context, iov->iov, iov->count, ref, iov->len)) {
     635                 :            :         check(0, "emitter rejected buffer content");
     636                 :            :         return 0;
     637                 :            :     }
     638                 :            :     /*
     639                 :            :      * Back references always return ref + 1 because ref == 0 is valid and
     640                 :            :      * should not be mistaken for error. vtables understand this.
     641                 :            :      */
     642                 :        150 :     return ref + 1;
     643                 :            : }
     644                 :            : 
     645                 :         84 : static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_align, int is_nested)
     646                 :            : {
     647                 :            :     size_t end_pad;
     648                 :            :     iov_state_t iov;
     649                 :            : 
     650 [ +  - ][ -  + ]:         84 :     block_align = block_align ? block_align : B->block_align ? B->block_align : 1;
     651                 :            :     get_min_align(align, field_size);
     652                 :         84 :     get_min_align(align, block_align);
     653                 :            :     /* Pad end of buffer to multiple. */
     654         [ +  + ]:         84 :     if (!is_nested) {
     655                 :         82 :         end_pad = back_pad(B, block_align);
     656         [ -  + ]:         82 :         if (end_pad) {
     657                 :            :             init_iov();
     658                 :          0 :             push_iov(_pad, end_pad);
     659         [ #  # ]:          0 :             if (0 == emit_back(B, &iov)) {
     660                 :            :                 check(0, "emitter rejected buffer content");
     661                 :            :                 return -1;
     662                 :            :             }
     663                 :            :         }
     664                 :            :     }
     665                 :            :     return 0;
     666                 :            : }
     667                 :            : 
     668                 :          0 : flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B,
     669                 :            :         uint16_t block_align,
     670                 :            :         const void *data, size_t size, uint16_t align, int flags)
     671                 :            : {
     672                 :            :     uoffset_t size_field, pad;
     673                 :            :     iov_state_t iov;
     674                 :          0 :     int with_size = flags & flatcc_builder_with_size;
     675                 :            : 
     676         [ #  # ]:          0 :     if (align_to_block(B, &align, block_align, !is_top_buffer(B))) {
     677                 :            :         return 0;
     678                 :            :     }
     679         [ #  # ]:          0 :     pad = front_pad(B, (uoffset_t)size + (with_size ? field_size : 0), align);
     680                 :          0 :     size_field = store_uoffset((uoffset_t)size + pad);
     681                 :          0 :     init_iov();
     682                 :            :     /* Add ubyte vector size header if nested buffer. */
     683         [ #  # ]:          0 :     push_iov_cond(&size_field, field_size, !is_top_buffer(B));
     684         [ #  # ]:          0 :     push_iov(data, size);
     685         [ #  # ]:          0 :     push_iov(_pad, pad);
     686                 :          0 :     return emit_front(B, &iov);
     687                 :            : }
     688                 :            : 
     689                 :         84 : flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B,
     690                 :            :         const char identifier[identifier_size], uint16_t block_align,
     691                 :            :         flatcc_builder_ref_t object_ref, uint16_t align, int flags)
     692                 :            : {
     693                 :            :     flatcc_builder_ref_t buffer_ref;
     694                 :            :     uoffset_t header_pad, id_size = 0;
     695                 :            :     uoffset_t object_offset, buffer_size, buffer_base;
     696                 :            :     iov_state_t iov;
     697                 :         84 :     flatcc_builder_identifier_t id_out = 0;
     698                 :         84 :     int is_nested = (flags & flatcc_builder_is_nested) != 0;
     699                 :         84 :     int with_size = (flags & flatcc_builder_with_size) != 0;
     700                 :            : 
     701         [ +  - ]:         84 :     if (align_to_block(B, &align, block_align, is_nested)) {
     702                 :            :         return 0;
     703                 :            :     }
     704                 :         84 :     set_min_align(B, align);
     705         [ +  - ]:         84 :     if (identifier) {
     706                 :            :         assert(sizeof(flatcc_builder_identifier_t) == identifier_size);
     707                 :            :         assert(sizeof(flatcc_builder_identifier_t) == field_size);
     708                 :         84 :         memcpy(&id_out, identifier, identifier_size);
     709                 :            :         id_out = __flatbuffers_thash_cast_from_le(id_out);
     710                 :            :         id_out = store_identifier(id_out);
     711                 :            :     }
     712         [ +  + ]:         84 :     id_size = id_out ? identifier_size : 0;
     713         [ +  + ]:         84 :     header_pad = front_pad(B, field_size + id_size + (with_size ? field_size : 0), align);
     714                 :         84 :     init_iov();
     715                 :            :     /* ubyte vectors size field wrapping nested buffer. */
     716         [ +  + ]:         84 :     push_iov_cond(&buffer_size, field_size, is_nested || with_size);
     717                 :         84 :     push_iov(&object_offset, field_size);
     718                 :            :     /* Identifiers are not always present in buffer. */
     719         [ +  + ]:         84 :     push_iov(&id_out, id_size);
     720         [ +  + ]:         84 :     push_iov(_pad, header_pad);
     721         [ +  + ]:         84 :     buffer_base = (uoffset_t)B->emit_start - (uoffset_t)iov.len + ((is_nested || with_size) ? field_size : 0);
     722         [ +  + ]:         84 :     if (is_nested) {
     723                 :          2 :         buffer_size = store_uoffset((uoffset_t)B->buffer_mark - buffer_base);
     724                 :            :     } else {
     725                 :         82 :         buffer_size = store_uoffset((uoffset_t)B->emit_end - buffer_base);
     726                 :            :     }
     727                 :         84 :     object_offset = store_uoffset((uoffset_t)object_ref - buffer_base);
     728         [ +  - ]:         84 :     if (0 == (buffer_ref = emit_front(B, &iov))) {
     729                 :            :         check(0, "emitter rejected buffer content");
     730                 :            :         return 0;
     731                 :            :     }
     732                 :         84 :     return buffer_ref;
     733                 :            : }
     734                 :            : 
     735                 :          2 : flatcc_builder_ref_t flatcc_builder_create_struct(flatcc_builder_t *B, const void *data, size_t size, uint16_t align)
     736                 :            : {
     737                 :            :     size_t pad;
     738                 :            :     iov_state_t iov;
     739                 :            : 
     740                 :            :     check(align >= 1, "align cannot be 0");
     741                 :          2 :     set_min_align(B, align);
     742                 :          4 :     pad = front_pad(B, (uoffset_t)size, align);
     743                 :          2 :     init_iov();
     744         [ +  - ]:          2 :     push_iov(data, size);
     745                 :            :     /*
     746                 :            :      * Normally structs will already be a multiple of their alignment,
     747                 :            :      * so this padding will not likely be emitted.
     748                 :            :      */
     749         [ -  + ]:          2 :     push_iov(_pad, pad);
     750                 :          2 :     return emit_front(B, &iov);
     751                 :            : }
     752                 :            : 
     753                 :         82 : int flatcc_builder_start_buffer(flatcc_builder_t *B,
     754                 :            :         const char identifier[identifier_size], uint16_t block_align, int flags)
     755                 :            : {
     756                 :            :     /*
     757                 :            :      * This saves the parent `min_align` in the align field since we
     758                 :            :      * shouldn't use that for the current buffer. `exit_frame`
     759                 :            :      * automatically aggregates align up, so it is updated when the
     760                 :            :      * buffer frame exits.
     761                 :            :      */
     762         [ +  - ]:         82 :     if (enter_frame(B, B->min_align)) {
     763                 :            :         return -1;
     764                 :            :     }
     765                 :            :     /* B->align now has parent min_align, and child frames will save it. */
     766                 :         82 :     B->min_align = 1;
     767                 :            :     /* Save the parent block align, and set proper defaults for this buffer. */
     768                 :         82 :     frame(buffer.block_align) = B->block_align;
     769                 :         82 :     B->block_align = block_align;
     770                 :         82 :     frame(buffer.flags = B->buffer_flags);
     771                 :         82 :     B->buffer_flags = flags;
     772                 :         82 :     frame(buffer.mark) = B->buffer_mark;
     773                 :            :     /* Allow vectors etc. to be constructed before buffer at root level. */
     774         [ +  + ]:         82 :     B->buffer_mark = B->level == 1 ? 0 : B->emit_start;
     775                 :         82 :     frame(buffer.identifier) = B->identifier;
     776         [ +  + ]:         82 :     set_identifier(identifier);
     777                 :         82 :     frame(type) = flatcc_builder_buffer;
     778                 :         82 :     return 0;
     779                 :            : }
     780                 :            : 
     781                 :         82 : flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_builder_ref_t root)
     782                 :            : {
     783                 :            :     flatcc_builder_ref_t buffer_ref;
     784                 :            : 
     785                 :            :     check(frame(type) == flatcc_builder_buffer, "expected buffer frame");
     786                 :         82 :     set_min_align(B, B->block_align);
     787         [ +  - ]:         82 :     if (0 == (buffer_ref = flatcc_builder_create_buffer(B, (void *)&B->identifier,
     788                 :        164 :             B->block_align, root, B->min_align, (B->buffer_flags & flatcc_builder_with_size) | !is_top_buffer(B)))) {
     789                 :            :         return 0;
     790                 :            :     }
     791                 :         82 :     B->buffer_mark = frame(buffer.mark);
     792                 :         82 :     B->identifier = frame(buffer.identifier);
     793                 :         82 :     B->buffer_flags = frame(buffer.flags);
     794                 :         82 :     exit_frame(B);
     795                 :         82 :     return buffer_ref;
     796                 :            : }
     797                 :            : 
     798                 :          2 : void *flatcc_builder_start_struct(flatcc_builder_t *B, size_t size, uint16_t align)
     799                 :            : {
     800                 :            :     /* Allocate space for the struct on the ds stack. */
     801         [ +  - ]:          2 :     if (enter_frame(B, align)) {
     802                 :            :         return 0;
     803                 :            :     }
     804                 :          2 :     frame(type) = flatcc_builder_struct;
     805                 :          2 :     return push_ds(B, (uoffset_t)size);
     806                 :            : }
     807                 :            : 
     808                 :          0 : void *flatcc_builder_struct_edit(flatcc_builder_t *B)
     809                 :            : {
     810                 :          0 :     return B->ds;
     811                 :            : }
     812                 :            : 
     813                 :          2 : flatcc_builder_ref_t flatcc_builder_end_struct(flatcc_builder_t *B)
     814                 :            : {
     815                 :            :     flatcc_builder_ref_t object_ref;
     816                 :            : 
     817                 :            :     check(frame(type) == flatcc_builder_struct, "expected struct frame");
     818         [ +  - ]:          2 :     if (0 == (object_ref = flatcc_builder_create_struct(B, B->ds, B->ds_offset, B->align))) {
     819                 :            :         return 0;
     820                 :            :     }
     821                 :          2 :     exit_frame(B);
     822                 :          2 :     return object_ref;
     823                 :            : }
     824                 :            : 
     825                 :            : static inline int vector_count_add(flatcc_builder_t *B, uoffset_t count, uoffset_t max_count)
     826                 :            : {
     827                 :            :     uoffset_t n, n1;
     828                 :    2200116 :     n = frame(vector.count);
     829                 :    2200116 :     n1 = n + count;
     830                 :            :     /*
     831                 :            :      * This prevents elem_size * count from overflowing iff max_vector
     832                 :            :      * has been set sensible. Without this check we might allocate to
     833                 :            :      * little on the ds stack and return a buffer the user thinks is
     834                 :            :      * much larger which of course is bad even though the buffer eventually
     835                 :            :      * would fail anyway.
     836                 :            :      */
     837 [ +  - ][ +  - ]:    2200116 :     check_error(n <= n1 && n1 <= max_count, -1, "vector too large to represent");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     838                 :    2200116 :     frame(vector.count) = n1;
     839                 :            :     return 0;
     840                 :            : }
     841                 :            : 
     842                 :         60 : void *flatcc_builder_extend_vector(flatcc_builder_t *B, size_t count)
     843                 :            : {
     844         [ +  - ]:         60 :     if (vector_count_add(B, (uoffset_t)count, frame(vector.max_count))) {
     845                 :            :         return 0;
     846                 :            :     }
     847                 :         60 :     return push_ds(B, frame(vector.elem_size) * (uoffset_t)count);
     848                 :            : }
     849                 :            : 
     850                 :          0 : void *flatcc_builder_vector_push(flatcc_builder_t *B, const void *data)
     851                 :            : {
     852                 :            :     check(frame(type) == flatcc_builder_vector, "expected vector frame");
     853         [ #  # ]:          0 :     check_error(frame(vector.count) <= frame(vector.max_count), 0, "vector max count exceeded");
     854                 :          0 :     frame(vector.count) += 1;
     855                 :          0 :     return push_ds_copy(B, data, frame(vector.elem_size));
     856                 :            : }
     857                 :            : 
     858                 :    1100004 : void *flatcc_builder_append_vector(flatcc_builder_t *B, const void *data, size_t count)
     859                 :            : {
     860                 :            :     check(frame(type) == flatcc_builder_vector, "expected vector frame");
     861         [ +  - ]:    1100004 :     if (vector_count_add(B, (uoffset_t)count, frame(vector.max_count))) {
     862                 :            :         return 0;
     863                 :            :     }
     864                 :    1100004 :     return push_ds_copy(B, data, frame(vector.elem_size) * (uoffset_t)count);
     865                 :            : }
     866                 :            : 
     867                 :         12 : flatcc_builder_ref_t *flatcc_builder_extend_offset_vector(flatcc_builder_t *B, size_t count)
     868                 :            : {
     869         [ +  - ]:         12 :     if (vector_count_add(B, (uoffset_t)count, max_offset_count)) {
     870                 :            :         return 0;
     871                 :            :     }
     872                 :         12 :     return push_ds(B, field_size * (uoffset_t)count);
     873                 :            : }
     874                 :            : 
     875                 :      11103 : flatcc_builder_ref_t *flatcc_builder_offset_vector_push(flatcc_builder_t *B, flatcc_builder_ref_t ref)
     876                 :            : {
     877                 :            :     flatcc_builder_ref_t *p;
     878                 :            : 
     879                 :            :     check(frame(type) == flatcc_builder_offset_vector, "expected offset vector frame");
     880         [ +  - ]:      11103 :     if (frame(vector.count) == max_offset_count) {
     881                 :            :         return 0;
     882                 :            :     }
     883                 :      11103 :     frame(vector.count) += 1;
     884         [ +  - ]:      11103 :     if (0 == (p = push_ds(B, field_size))) {
     885                 :            :         return 0;
     886                 :            :     }
     887                 :      11103 :     *p = ref;
     888                 :      11103 :     return p;
     889                 :            : }
     890                 :            : 
     891                 :          2 : flatcc_builder_ref_t *flatcc_builder_append_offset_vector(flatcc_builder_t *B, const flatcc_builder_ref_t *refs, size_t count)
     892                 :            : {
     893                 :            :     check(frame(type) == flatcc_builder_offset_vector, "expected offset vector frame");
     894         [ +  - ]:          2 :     if (vector_count_add(B, (uoffset_t)count, max_offset_count)) {
     895                 :            :         return 0;
     896                 :            :     }
     897                 :          2 :     return push_ds_copy(B, refs, field_size * (uoffset_t)count);
     898                 :            : }
     899                 :            : 
     900                 :          1 : char *flatcc_builder_extend_string(flatcc_builder_t *B, size_t len)
     901                 :            : {
     902                 :            :     check(frame(type) == flatcc_builder_string, "expected string frame");
     903         [ +  - ]:          1 :     if (vector_count_add(B, (uoffset_t)len, max_string_len)) {
     904                 :            :         return 0;
     905                 :            :     }
     906                 :          1 :     return push_ds(B, (uoffset_t)len);
     907                 :            : }
     908                 :            : 
     909                 :    1100037 : char *flatcc_builder_append_string(flatcc_builder_t *B, const char *s, size_t len)
     910                 :            : {
     911                 :            :     check(frame(type) == flatcc_builder_string, "expected string frame");
     912         [ +  - ]:    1100037 :     if (vector_count_add(B, (uoffset_t)len, max_string_len)) {
     913                 :            :         return 0;
     914                 :            :     }
     915                 :    1100037 :     return push_ds_copy(B, s, (uoffset_t)len);
     916                 :            : }
     917                 :            : 
     918                 :          1 : char *flatcc_builder_append_string_str(flatcc_builder_t *B, const char *s)
     919                 :            : {
     920                 :          1 :     return flatcc_builder_append_string(B, s, strlen(s));
     921                 :            : }
     922                 :            : 
     923                 :          1 : char *flatcc_builder_append_string_strn(flatcc_builder_t *B, const char *s, size_t max_len)
     924                 :            : {
     925                 :          1 :     return flatcc_builder_append_string(B, s, strnlen(s, max_len));
     926                 :            : }
     927                 :            : 
     928                 :          2 : int flatcc_builder_truncate_vector(flatcc_builder_t *B, size_t count)
     929                 :            : {
     930                 :            :     check(frame(type) == flatcc_builder_vector, "expected vector frame");
     931         [ +  - ]:          2 :     check_error(frame(vector.count) >= count, -1, "cannot truncate vector past empty");
     932                 :          2 :     frame(vector.count) -= (uoffset_t)count;
     933                 :          2 :     unpush_ds(B, frame(vector.elem_size) * (uoffset_t)count);
     934                 :          2 :     return 0;
     935                 :            : }
     936                 :            : 
     937                 :          2 : int flatcc_builder_truncate_offset_vector(flatcc_builder_t *B, size_t count)
     938                 :            : {
     939                 :            :     check(frame(type) == flatcc_builder_offset_vector, "expected offset vector frame");
     940         [ +  - ]:          2 :     check_error(frame(vector.count) >= (uoffset_t)count, -1, "cannot truncate vector past empty");
     941                 :          2 :     frame(vector.count) -= (uoffset_t)count;
     942                 :          2 :     unpush_ds(B, frame(vector.elem_size) * (uoffset_t)count);
     943                 :          2 :     return 0;
     944                 :            : }
     945                 :            : 
     946                 :          1 : int flatcc_builder_truncate_string(flatcc_builder_t *B, size_t len)
     947                 :            : {
     948                 :            :     check(frame(type) == flatcc_builder_string, "expected string frame");
     949         [ +  - ]:          1 :     check_error(frame(vector.count) >= len, -1, "cannot truncate string past empty");
     950                 :          1 :     frame(vector.count) -= (uoffset_t)len;
     951                 :            :     unpush_ds(B, (uoffset_t)len);
     952                 :          1 :     return 0;
     953                 :            : }
     954                 :            : 
     955                 :      11008 : int flatcc_builder_start_vector(flatcc_builder_t *B, size_t elem_size, uint16_t align, size_t max_count)
     956                 :            : {
     957                 :            :     get_min_align(&align, field_size);
     958         [ +  - ]:      11008 :     if (enter_frame(B, align)) {
     959                 :            :         return -1;
     960                 :            :     }
     961                 :      11008 :     frame(vector.elem_size) = (uoffset_t)elem_size;
     962                 :      11008 :     frame(vector.count) = 0;
     963                 :      11008 :     frame(vector.max_count) = (uoffset_t)max_count;
     964                 :      11008 :     frame(type) = flatcc_builder_vector;
     965                 :            :     refresh_ds(B, data_limit);
     966                 :      11008 :     return 0;
     967                 :            : }
     968                 :            : 
     969                 :         49 : int flatcc_builder_start_offset_vector(flatcc_builder_t *B)
     970                 :            : {
     971         [ +  - ]:         49 :     if (enter_frame(B, field_size)) {
     972                 :            :         return -1;
     973                 :            :     }
     974                 :         49 :     frame(vector.elem_size) = field_size;
     975                 :         49 :     frame(vector.count) = 0;
     976                 :         49 :     frame(type) = flatcc_builder_offset_vector;
     977                 :            :     refresh_ds(B, data_limit);
     978                 :         49 :     return 0;
     979                 :            : }
     980                 :            : 
     981                 :          4 : flatcc_builder_ref_t flatcc_builder_create_offset_vector(flatcc_builder_t *B,
     982                 :            :         const flatcc_builder_ref_t *vec, size_t count)
     983                 :            : {
     984                 :            :     flatcc_builder_ref_t *_vec;
     985                 :            : 
     986         [ +  - ]:          4 :     if (flatcc_builder_start_offset_vector(B)) {
     987                 :            :         return 0;
     988                 :            :     }
     989         [ +  - ]:          4 :     if (!(_vec = flatcc_builder_extend_offset_vector(B, count))) {
     990                 :            :         return 0;
     991                 :            :     }
     992                 :          4 :     memcpy(_vec, vec, count * field_size);
     993                 :          4 :     return flatcc_builder_end_offset_vector(B);
     994                 :            : }
     995                 :            : 
     996                 :      11005 : int flatcc_builder_start_string(flatcc_builder_t *B)
     997                 :            : {
     998         [ +  - ]:      11005 :     if (enter_frame(B, 1)) {
     999                 :            :         return -1;
    1000                 :            :     }
    1001                 :      11005 :     frame(vector.elem_size) = 1;
    1002                 :      11005 :     frame(vector.count) = 0;
    1003                 :      11005 :     frame(type) = flatcc_builder_string;
    1004                 :            :     refresh_ds(B, data_limit);
    1005                 :      11005 :     return 0;
    1006                 :            : }
    1007                 :            : 
    1008                 :          0 : int flatcc_builder_reserve_table(flatcc_builder_t *B, int count)
    1009                 :            : {
    1010                 :            :     check(count >= 0, "cannot reserve negative count");
    1011                 :          0 :     return reserve_fields(B, count);
    1012                 :            : }
    1013                 :            : 
    1014                 :      11289 : int flatcc_builder_start_table(flatcc_builder_t *B, int count)
    1015                 :            : {
    1016         [ +  - ]:      11289 :     if (enter_frame(B, field_size)) {
    1017                 :            :         return -1;
    1018                 :            :     }
    1019                 :      11289 :     frame(table.vs_end) = vs_offset(B->vs);
    1020                 :      11289 :     frame(table.pl_end) = pl_offset(B->pl);
    1021                 :      11289 :     frame(table.vt_hash) = B->vt_hash;
    1022                 :      11289 :     frame(table.id_end) = B->id_end;
    1023                 :            :     B->vt_hash = 0;
    1024                 :      11289 :     FLATCC_BUILDER_INIT_VT_HASH(B->vt_hash);
    1025                 :      11289 :     B->id_end = 0;
    1026                 :      11289 :     frame(type) = flatcc_builder_table;
    1027         [ +  - ]:      11289 :     if (reserve_fields(B, count)) {
    1028                 :            :         return -1;
    1029                 :            :     }
    1030                 :            :     refresh_ds(B, table_limit);
    1031                 :      11289 :     return 0;
    1032                 :            : }
    1033                 :            : 
    1034                 :        152 : flatcc_builder_vt_ref_t flatcc_builder_create_vtable(flatcc_builder_t *B,
    1035                 :            :         const voffset_t *vt, voffset_t vt_size)
    1036                 :            : {
    1037                 :            :     flatcc_builder_vt_ref_t vt_ref;
    1038                 :            :     iov_state_t iov;
    1039                 :            :     voffset_t *vt_;
    1040                 :            :     size_t i;
    1041                 :            : 
    1042                 :            :     /*
    1043                 :            :      * Only top-level buffer can cluster vtables because only it can
    1044                 :            :      * extend beyond the end.
    1045                 :            :      *
    1046                 :            :      * We write the vtable after the referencing table to maintain
    1047                 :            :      * the construction invariant that any offset reference has
    1048                 :            :      * valid emitted data at a higher address, and also that any
    1049                 :            :      * issued negative emit address represents an offset reference
    1050                 :            :      * to some flatbuffer object or vector (or possibly a root
    1051                 :            :      * struct).
    1052                 :            :      *
    1053                 :            :      * The vt_ref is stored as the reference + 1 to avoid having 0 as a
    1054                 :            :      * valid reference (which usally means error). It also idententifies
    1055                 :            :      * vtable references as the only uneven references, and the only
    1056                 :            :      * references that can be used multiple times in the same buffer.
    1057                 :            :      *
    1058                 :            :      * We do the vtable conversion here so cached vtables can be built
    1059                 :            :      * hashed and compared more efficiently, and so end users with
    1060                 :            :      * direct vtable construction don't have to worry about endianness.
    1061                 :            :      * This also ensures the hash function works the same wrt.
    1062                 :            :      * collision frequency.
    1063                 :            :      */
    1064                 :            : 
    1065                 :            :     if (!flatbuffers_is_native_pe()) {
    1066                 :            :         /* Make space in vtable cache for temporary endian conversion. */
    1067                 :            :         if (!(vt_ = reserve_buffer(B, flatcc_builder_alloc_vb, B->vb_end, vt_size, 0))) {
    1068                 :            :             return 0;
    1069                 :            :         }
    1070                 :            :         for (i = 0; i < vt_size / sizeof(voffset_t); ++i) {
    1071                 :            :             vt_[i] = store_voffset(vt[i]);
    1072                 :            :         }
    1073                 :            :         vt = vt_;
    1074                 :            :         /* We don't need to free the reservation since we don't advance any base pointer. */
    1075                 :            :     }
    1076                 :            : 
    1077                 :        152 :     init_iov();
    1078         [ +  - ]:        152 :     push_iov(vt, vt_size);
    1079 [ +  + ][ +  - ]:        152 :     if (is_top_buffer(B) && !B->disable_vt_clustering) {
    1080                 :            :         /* Note that `emit_back` already returns ref + 1 as we require for vtables. */
    1081         [ +  - ]:        150 :         if (0 == (vt_ref = emit_back(B, &iov))) {
    1082                 :            :             return 0;
    1083                 :            :         }
    1084                 :            :     } else {
    1085         [ +  - ]:          2 :         if (0 == (vt_ref = emit_front(B, &iov))) {
    1086                 :            :             return 0;
    1087                 :            :         }
    1088                 :            :         /*
    1089                 :            :          * We don't have a valid 0 ref here, but to be consistent with
    1090                 :            :          * clustered vtables we offset by one. This cannot be zero
    1091                 :            :          * either.
    1092                 :            :          */
    1093                 :          2 :         vt_ref += 1;
    1094                 :            :     }
    1095                 :            :     return vt_ref;
    1096                 :            : }
    1097                 :            : 
    1098                 :      11289 : flatcc_builder_vt_ref_t flatcc_builder_create_cached_vtable(flatcc_builder_t *B,
    1099                 :            :         const voffset_t *vt, voffset_t vt_size, uint32_t vt_hash)
    1100                 :            : {
    1101                 :            :     vtable_descriptor_t *vd, *vd2;
    1102                 :            :     uoffset_t *pvd, *pvd_head;
    1103                 :            :     uoffset_t next;
    1104                 :            :     voffset_t *vt_;
    1105                 :            : 
    1106                 :            :     /* This just gets the hash table slot, we still have to inspect it. */
    1107         [ +  - ]:      11289 :     if (!(pvd_head = lookup_ht(B, vt_hash))) {
    1108                 :            :         return 0;
    1109                 :            :     }
    1110                 :            :     pvd = pvd_head;
    1111                 :      11289 :     next = *pvd;
    1112                 :            :     /* Tracks if there already is a cached copy. */
    1113                 :            :     vd2 = 0;
    1114         [ +  + ]:      11309 :     while (next) {
    1115                 :      11157 :         vd = vd_ptr(next);
    1116                 :      11157 :         vt_ = vb_ptr(vd->vb_start);
    1117 [ +  + ][ -  + ]:      11157 :         if (vt_[0] != vt_size || 0 != memcmp(vt, vt_, vt_size)) {
    1118                 :         20 :             pvd = &vd->next;
    1119                 :         20 :             next = vd->next;
    1120                 :         20 :             continue;
    1121                 :            :         }
    1122                 :            :         /* Can't share emitted vtables between buffers, */
    1123         [ -  + ]:      11137 :         if (vd->buffer_mark != B->buffer_mark) {
    1124                 :            :             /* but we don't have to resubmit to cache. */
    1125                 :            :             vd2 = vd;
    1126                 :            :             /* See if there is a better match. */
    1127                 :          0 :             pvd = &vd->next;
    1128                 :          0 :             next = vd->next;
    1129                 :          0 :             continue;
    1130                 :            :         }
    1131                 :            :         /* Move to front hash strategy. */
    1132         [ +  + ]:      11137 :         if (pvd != pvd_head) {
    1133                 :         16 :             *pvd = vd->next;
    1134                 :         16 :             vd->next = *pvd_head;
    1135                 :         16 :             *pvd_head = next;
    1136                 :            :         }
    1137                 :            :         /* vtable exists and has been emitted within current buffer. */
    1138                 :      11157 :         return vd->vt_ref;
    1139                 :            :     }
    1140                 :            :     /* Allocate new descriptor. */
    1141         [ +  - ]:        152 :     if (!(vd = reserve_buffer(B, flatcc_builder_alloc_vd, B->vd_end, sizeof(vtable_descriptor_t), 0))) {
    1142                 :            :         return 0;
    1143                 :            :     }
    1144                 :        152 :     next = B->vd_end;
    1145                 :        152 :     B->vd_end += sizeof(vtable_descriptor_t);
    1146                 :            : 
    1147                 :            :     /* Identify the buffer this vtable descriptor belongs to. */
    1148                 :        152 :     vd->buffer_mark = B->buffer_mark;
    1149                 :            : 
    1150                 :            :     /* Move to front hash strategy. */
    1151                 :        152 :     vd->next = *pvd_head;
    1152                 :        152 :     *pvd_head = next;
    1153         [ +  - ]:        152 :     if (0 == (vd->vt_ref = flatcc_builder_create_vtable(B, vt, vt_size))) {
    1154                 :            :         return 0;
    1155                 :            :     }
    1156         [ -  + ]:        152 :     if (vd2) {
    1157                 :            :         /* Reuse cached copy. */
    1158                 :          0 :         vd->vb_start = vd2->vb_start;
    1159                 :            :     } else {
    1160 [ -  + ][ #  # ]:        152 :         if (B->vb_flush_limit && B->vb_flush_limit < B->vb_end + vt_size) {
    1161                 :            :             flatcc_builder_flush_vtable_cache(B);
    1162                 :            :         } else {
    1163                 :            :             /* Make space in vtable cache. */
    1164         [ +  - ]:        152 :             if (!(vt_ = reserve_buffer(B, flatcc_builder_alloc_vb, B->vb_end, vt_size, 0))) {
    1165                 :            :                 return -1;
    1166                 :            :             }
    1167                 :        152 :             vd->vb_start = B->vb_end;
    1168                 :        152 :             B->vb_end += vt_size;
    1169                 :        152 :             memcpy(vt_, vt, vt_size);
    1170                 :            :         }
    1171                 :            :     }
    1172                 :        152 :     return vd->vt_ref;
    1173                 :            : }
    1174                 :            : 
    1175                 :      11289 : flatcc_builder_ref_t flatcc_builder_create_table(flatcc_builder_t *B, const void *data, size_t size, uint16_t align,
    1176                 :            :         flatbuffers_voffset_t *offsets, int offset_count, flatcc_builder_vt_ref_t vt_ref)
    1177                 :            : {
    1178                 :            :     int i;
    1179                 :            :     uoffset_t pad, vt_offset, vt_offset_field, vt_base, base, offset, *offset_field;
    1180                 :            :     iov_state_t iov;
    1181                 :            : 
    1182                 :            :     check(offset_count >= 0, "expected non-negative offset_count");
    1183                 :            :     /*
    1184                 :            :      * vtable references are offset by 1 to avoid confusion with
    1185                 :            :      * 0 as an error reference. It also uniquely identifies them
    1186                 :            :      * as vtables being the only uneven reference type.
    1187                 :            :      */
    1188                 :            :     check(vt_ref & 1, "invalid vtable referenc");
    1189                 :            :     get_min_align(&align, field_size);
    1190                 :      11289 :     set_min_align(B, align);
    1191                 :            :     /* Alignment is calculated for the first element, not the header. */
    1192                 :      11289 :     pad = front_pad(B, (uoffset_t)size, align);
    1193                 :      11289 :     base = (uoffset_t)B->emit_start - (uoffset_t)(pad + size + field_size);
    1194                 :            :     /* Adjust by 1 to get unencoded vtable reference. */
    1195                 :      11289 :     vt_base = (uoffset_t)(vt_ref - 1);
    1196                 :      11289 :     vt_offset = base - vt_base;
    1197                 :            :     /* Avoid overflow. */
    1198                 :            :     if (base - vt_offset != vt_base) {
    1199                 :            :         return -1;
    1200                 :            :     }
    1201                 :            :     /* Protocol endian encoding. */
    1202                 :      11289 :     vt_offset_field = store_uoffset(vt_offset);
    1203         [ +  + ]:      33672 :     for (i = 0; i < offset_count; ++i) {
    1204                 :      22383 :         offset_field = (uoffset_t *)((size_t)data + offsets[i]);
    1205                 :      22383 :         offset = *offset_field - base - offsets[i] - field_size;
    1206                 :      22383 :         *offset_field = store_uoffset(offset);
    1207                 :            :     }
    1208                 :            :     init_iov();
    1209                 :      11289 :     push_iov(&vt_offset_field, field_size);
    1210         [ +  + ]:      11289 :     push_iov(data, size);
    1211         [ +  + ]:      11289 :     push_iov(_pad, pad);
    1212                 :      11289 :     return emit_front(B, &iov);
    1213                 :            : }
    1214                 :            : 
    1215                 :         49 : int flatcc_builder_check_required_field(flatcc_builder_t *B, flatbuffers_voffset_t id)
    1216                 :            : {
    1217                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1218                 :            : 
    1219 [ +  - ][ -  + ]:         49 :     return id < B->id_end && B->vs[id] != 0;
    1220                 :            : }
    1221                 :            : 
    1222                 :          0 : int flatcc_builder_check_union_field(flatcc_builder_t *B, flatbuffers_voffset_t id)
    1223                 :            : {
    1224                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1225                 :            : 
    1226 [ #  # ][ #  # ]:          0 :     if (id == 0 || id >= B->id_end) {
    1227                 :            :         return 0;
    1228                 :            :     }
    1229         [ #  # ]:          0 :     if (B->vs[id - 1] == 0) {
    1230                 :          0 :         return B->vs[id] == 0;
    1231                 :            :     }
    1232         [ #  # ]:          0 :     if (*(uint8_t *)(B->ds + B->vs[id - 1])) {
    1233                 :          0 :         return B->vs[id] != 0;
    1234                 :            :     }
    1235                 :          0 :     return B->vs[id] == 0;
    1236                 :            : }
    1237                 :            : 
    1238                 :          0 : int flatcc_builder_check_required(flatcc_builder_t *B, const flatbuffers_voffset_t *required, int count)
    1239                 :            : {
    1240                 :            :     int i;
    1241                 :            : 
    1242                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1243                 :            : 
    1244         [ #  # ]:          0 :     if (B->id_end < count) {
    1245                 :            :         return 0;
    1246                 :            :     }
    1247         [ #  # ]:          0 :     for (i = 0; i < count; ++i) {
    1248         [ #  # ]:          0 :         if (B->vs[required[i]] == 0) {
    1249                 :            :             return 0;
    1250                 :            :         }
    1251                 :            :     }
    1252                 :            :     return 1;
    1253                 :            : }
    1254                 :            : 
    1255                 :      11289 : flatcc_builder_ref_t flatcc_builder_end_table(flatcc_builder_t *B)
    1256                 :            : {
    1257                 :            :     voffset_t *vt, vt_size;
    1258                 :            :     flatcc_builder_ref_t table_ref, vt_ref;
    1259                 :            :     int pl_count;
    1260                 :            :     voffset_t *pl;
    1261                 :            : 
    1262                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1263                 :            : 
    1264                 :            :     /* We have `ds_limit`, so we should not have to check for overflow here. */
    1265                 :            : 
    1266                 :      11289 :     vt = B->vs - 2;
    1267                 :      11289 :     vt_size = sizeof(voffset_t) * (B->id_end + 2);
    1268                 :            :     /* Update vtable header fields, first vtable size, then object table size. */
    1269                 :      11289 :     vt[0] = vt_size;
    1270                 :            :     /*
    1271                 :            :      * The `ds` buffer is always at least `field_size` aligned but excludes the
    1272                 :            :      * initial vtable offset field. Therefore `field_size` is added here
    1273                 :            :      * to the total table size in the vtable.
    1274                 :            :      */
    1275                 :      11289 :     vt[1] = (voffset_t)B->ds_offset + field_size;
    1276                 :      11289 :     FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)vt[0], (uint32_t)vt[1]);
    1277                 :            :     /* Find already emitted vtable, or emit a new one. */
    1278         [ +  - ]:      11289 :     if (!(vt_ref = flatcc_builder_create_cached_vtable(B, vt, vt_size, B->vt_hash))) {
    1279                 :            :         return 0;
    1280                 :            :     }
    1281                 :            :     /* Clear vs stack so it is ready for the next vtable (ds stack is cleared by exit frame). */
    1282                 :      11289 :     memset(vt, 0, vt_size);
    1283                 :            : 
    1284                 :      11289 :     pl = pl_ptr(frame(table.pl_end));
    1285                 :      11289 :     pl_count = (int)(B->pl - pl);
    1286         [ +  - ]:      11289 :     if (0 == (table_ref = flatcc_builder_create_table(B, B->ds, B->ds_offset, B->align, pl, pl_count, vt_ref))) {
    1287                 :            :         return 0;
    1288                 :            :     }
    1289                 :      11289 :     B->vt_hash = frame(table.vt_hash);
    1290                 :      11289 :     B->id_end = frame(table.id_end);
    1291                 :      11289 :     B->vs = vs_ptr(frame(table.vs_end));
    1292                 :      11289 :     B->pl = pl_ptr(frame(table.pl_end));
    1293                 :      11289 :     exit_frame(B);
    1294                 :      11289 :     return table_ref;
    1295                 :            : }
    1296                 :            : 
    1297                 :      11021 : flatcc_builder_ref_t flatcc_builder_create_vector(flatcc_builder_t *B,
    1298                 :            :         const void *data, size_t count, size_t elem_size, uint16_t align, size_t max_count)
    1299                 :            : {
    1300                 :            :     /*
    1301                 :            :      * Note: it is important that vec_size is uoffset not size_t
    1302                 :            :      * in case sizeof(uoffset_t) > sizeof(size_t) because max_count is
    1303                 :            :      * defined in terms of uoffset_t representation size, and also
    1304                 :            :      * because we risk accepting too large a vector even if max_count is
    1305                 :            :      * not violated.
    1306                 :            :      */
    1307                 :            :     uoffset_t vec_size, vec_pad, length_prefix;
    1308                 :            :     iov_state_t iov;
    1309                 :            : 
    1310         [ +  - ]:      11021 :     check_error(count <= max_count, 0, "vector max_count violated");
    1311                 :            :     get_min_align(&align, field_size);
    1312                 :      11021 :     set_min_align(B, align);
    1313                 :      11021 :     vec_size = (uoffset_t)count * (uoffset_t)elem_size;
    1314                 :            :     /*
    1315                 :            :      * That can happen on 32 bit systems when uoffset_t is defined as 64-bit.
    1316                 :            :      * `emit_front/back` captures overflow, but not if our size type wraps first.
    1317                 :            :      */
    1318                 :            : #if FLATBUFFERS_UOFFSET_MAX > SIZE_MAX
    1319                 :            :     check_error(vec_size < SIZE_MAX, 0, "vector larger than address space");
    1320                 :            : #endif
    1321                 :      11021 :     length_prefix = store_uoffset((uoffset_t)count);
    1322                 :            :     /* Alignment is calculated for the first element, not the header. */
    1323                 :            :     vec_pad = front_pad(B, vec_size, align);
    1324                 :            :     init_iov();
    1325                 :      11021 :     push_iov(&length_prefix, field_size);
    1326         [ +  - ]:      11021 :     push_iov(data, vec_size);
    1327         [ +  + ]:      11021 :     push_iov(_pad, vec_pad);
    1328                 :      11021 :     return emit_front(B, &iov);
    1329                 :            : }
    1330                 :            : 
    1331                 :            : /*
    1332                 :            :  * Note: FlatBuffers official documentation states that the size field of a
    1333                 :            :  * vector is a 32-bit element count. It is not quite clear if the
    1334                 :            :  * intention is to have the size field be of type uoffset_t since tables
    1335                 :            :  * also have a uoffset_t sized header, or if the vector size should
    1336                 :            :  * remain unchanged if uoffset is changed to 16- or 64-bits
    1337                 :            :  * respectively. Since it makes most sense to have a vector compatible
    1338                 :            :  * with the addressable space, we choose to use uoffset_t as size field,
    1339                 :            :  * which remains compatible with the default 32-bit version of uoffset_t.
    1340                 :            :  */
    1341                 :      11008 : flatcc_builder_ref_t flatcc_builder_end_vector(flatcc_builder_t *B)
    1342                 :            : {
    1343                 :            :     flatcc_builder_ref_t vector_ref;
    1344                 :            : 
    1345                 :            :     check(frame(type) == flatcc_builder_vector, "expected vector frame");
    1346                 :            : 
    1347         [ +  - ]:      11008 :     if (0 == (vector_ref = flatcc_builder_create_vector(B, B->ds,
    1348                 :      22016 :             frame(vector.count), frame(vector.elem_size),
    1349                 :      22016 :             B->align, frame(vector.max_count)))) {
    1350                 :            :         return 0;
    1351                 :            :     }
    1352                 :      11008 :     exit_frame(B);
    1353                 :      11008 :     return vector_ref;
    1354                 :            : }
    1355                 :            : 
    1356                 :          0 : size_t flatcc_builder_vector_count(flatcc_builder_t *B)
    1357                 :            : {
    1358                 :          0 :     return frame(vector.count);
    1359                 :            : }
    1360                 :            : 
    1361                 :          2 : void *flatcc_builder_vector_edit(flatcc_builder_t *B)
    1362                 :            : {
    1363                 :          2 :     return B->ds;
    1364                 :            : }
    1365                 :            : 
    1366                 :            : /* This function destroys the source content but avoids stack allocation. */
    1367                 :         49 : flatcc_builder_ref_t flatcc_builder_create_offset_vector_direct(flatcc_builder_t *B,
    1368                 :            :         flatcc_builder_ref_t *vec, size_t count)
    1369                 :            : {
    1370                 :            :     uoffset_t vec_size, vec_pad;
    1371                 :            :     uoffset_t length_prefix, base, offset;
    1372                 :            :     uoffset_t i;
    1373                 :            :     iov_state_t iov;
    1374                 :            : 
    1375         [ +  - ]:         49 :     if ((uoffset_t)count > max_offset_count) {
    1376                 :            :         return 0;
    1377                 :            :     }
    1378                 :            :     set_min_align(B, field_size);
    1379                 :         49 :     vec_size = (uoffset_t)count * field_size;
    1380                 :         49 :     length_prefix = store_uoffset((uoffset_t)count);
    1381                 :            :     /* Alignment is calculated for the first element, not the header. */
    1382                 :            :     vec_pad = front_pad(B, vec_size, field_size);
    1383                 :            :     init_iov();
    1384                 :         49 :     push_iov(&length_prefix, field_size);
    1385         [ +  + ]:         49 :     push_iov(vec, vec_size);
    1386         [ -  + ]:         49 :     push_iov(_pad, vec_pad);
    1387                 :         49 :     base = (uoffset_t)B->emit_start - (uoffset_t)iov.len;
    1388         [ +  + ]:      11193 :     for (i = 0; i < (uoffset_t)count; ++i) {
    1389                 :            :         /*
    1390                 :            :          * 0 is either end of buffer, start of vtables, or start of
    1391                 :            :          * buffer depending on the direction in which the buffer is
    1392                 :            :          * built. None of these can create a valid 0 reference but it
    1393                 :            :          * is easy to create by mistake when manually building offset
    1394                 :            :          * vectors.
    1395                 :            :          */
    1396                 :            :         check(vec[i] != 0, "offset vector cannot have null entry");
    1397                 :      11144 :         offset = vec[i] - base - i * field_size - field_size;
    1398                 :      11144 :         vec[i] = store_uoffset(offset);
    1399                 :            :     }
    1400                 :         49 :     return emit_front(B, &iov);
    1401                 :            : }
    1402                 :            : 
    1403                 :         49 : flatcc_builder_ref_t flatcc_builder_end_offset_vector(flatcc_builder_t *B)
    1404                 :            : {
    1405                 :            :     flatcc_builder_ref_t vector_ref;
    1406                 :            : 
    1407                 :            :     check(frame(type) == flatcc_builder_offset_vector, "expected offset vector");
    1408         [ +  - ]:         49 :     if (0 == (vector_ref = flatcc_builder_create_offset_vector_direct(B,
    1409                 :         98 :             (flatcc_builder_ref_t *)B->ds, frame(vector.count)))) {
    1410                 :            :         return 0;
    1411                 :            :     }
    1412                 :         49 :     exit_frame(B);
    1413                 :         49 :     return vector_ref;
    1414                 :            : }
    1415                 :            : 
    1416                 :          0 : size_t flatcc_builder_offset_vector_count(flatcc_builder_t *B)
    1417                 :            : {
    1418                 :          0 :     return frame(vector.count);
    1419                 :            : }
    1420                 :            : 
    1421                 :          2 : void *flatcc_builder_offset_vector_edit(flatcc_builder_t *B)
    1422                 :            : {
    1423                 :          2 :     return B->ds;
    1424                 :            : }
    1425                 :            : 
    1426                 :      11222 : flatcc_builder_ref_t flatcc_builder_create_string(flatcc_builder_t *B, const char *s, size_t len)
    1427                 :            : {
    1428                 :            :     uoffset_t s_pad;
    1429                 :            :     uoffset_t length_prefix;
    1430                 :            :     iov_state_t iov;
    1431                 :            : 
    1432         [ +  - ]:      11222 :     if (len > max_string_len) {
    1433                 :            :         return 0;
    1434                 :            :     }
    1435                 :      11222 :     length_prefix = store_uoffset((uoffset_t)len);
    1436                 :            :     /* Add 1 for zero termination. */
    1437                 :      22444 :     s_pad = front_pad(B, (uoffset_t)len + 1, field_size) + 1;
    1438                 :            :     init_iov();
    1439                 :      11222 :     push_iov(&length_prefix, field_size);
    1440         [ +  - ]:      11222 :     push_iov(s, len);
    1441         [ +  - ]:      11222 :     push_iov(_pad, s_pad);
    1442                 :      11222 :     return emit_front(B, &iov);
    1443                 :            : }
    1444                 :            : 
    1445                 :         74 : flatcc_builder_ref_t flatcc_builder_create_string_str(flatcc_builder_t *B, const char *s)
    1446                 :            : {
    1447                 :         74 :     return flatcc_builder_create_string(B, s, strlen(s));
    1448                 :            : }
    1449                 :            : 
    1450                 :          4 : flatcc_builder_ref_t flatcc_builder_create_string_strn(flatcc_builder_t *B, const char *s, size_t max_len)
    1451                 :            : {
    1452                 :          4 :     return flatcc_builder_create_string(B, s, strnlen(s, max_len));
    1453                 :            : }
    1454                 :            : 
    1455                 :            : 
    1456                 :      11005 : flatcc_builder_ref_t flatcc_builder_end_string(flatcc_builder_t *B)
    1457                 :            : {
    1458                 :            :     flatcc_builder_ref_t string_ref;
    1459                 :            : 
    1460                 :            :     check(frame(type) == flatcc_builder_string, "expected string frame");
    1461                 :            :     assert(frame(vector.count) == B->ds_offset);
    1462         [ +  - ]:      11005 :     if (0 == (string_ref = flatcc_builder_create_string(B,
    1463                 :      22010 :             (const char *)B->ds, B->ds_offset))) {
    1464                 :            :         return 0;
    1465                 :            :     }
    1466                 :      11005 :     exit_frame(B);
    1467                 :      11005 :     return string_ref;
    1468                 :            : }
    1469                 :            : 
    1470                 :          1 : char *flatcc_builder_string_edit(flatcc_builder_t *B)
    1471                 :            : {
    1472                 :          1 :     return (char *)B->ds;
    1473                 :            : }
    1474                 :            : 
    1475                 :          0 : size_t flatcc_builder_string_len(flatcc_builder_t *B)
    1476                 :            : {
    1477                 :          0 :     return frame(vector.count);
    1478                 :            : }
    1479                 :            : 
    1480                 :        342 : void *flatcc_builder_table_add(flatcc_builder_t *B, int id, size_t size, uint16_t align)
    1481                 :            : {
    1482                 :            :     /*
    1483                 :            :      * We align the offset relative to the first table field, excluding
    1484                 :            :      * the header holding the vtable reference. On the stack, `ds_first`
    1485                 :            :      * is aligned to 8 bytes thanks to the `enter_frame` logic, and this
    1486                 :            :      * provides a safe way to update the fields on the stack, but here
    1487                 :            :      * we are concerned with the target buffer alignment.
    1488                 :            :      *
    1489                 :            :      * We could also have aligned relative to the end of the table which
    1490                 :            :      * would allow us to emit each field immediately, but it would be a
    1491                 :            :      * confusing user experience wrt. field ordering, and it would add
    1492                 :            :      * more variability to vtable layouts, thus reducing reuse, and
    1493                 :            :      * frequent emissions to external emitter interface would be
    1494                 :            :      * sub-optimal. Also, with that appoach, the vtable offsets would
    1495                 :            :      * have to be adjusted at table end.
    1496                 :            :      *
    1497                 :            :      * As we have it, each emit occur at table end, vector end, string
    1498                 :            :      * end, or buffer end, which might be helpful to various backend
    1499                 :            :      * processors.
    1500                 :            :      */
    1501                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1502                 :            :     check(id >= 0 && id <= (int)FLATBUFFERS_ID_MAX, "table id out of range");
    1503         [ +  + ]:        342 :     if (align > B->align) {
    1504                 :         36 :         B->align = align;
    1505                 :            :     }
    1506         [ +  - ]:        342 :     if (B->vs[id] == 0) {
    1507                 :        342 :         FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)id, (uint32_t)size);
    1508                 :        342 :         return push_ds_field(B, (uoffset_t)size, align, id);
    1509                 :            :     } else {
    1510                 :            : #if FLATCC_BUILDER_ALLOW_REPEAT_TABLE_ADD
    1511                 :            :         check_error(B->vs[id] == 0, 0, "field already set");
    1512                 :            : #else
    1513                 :          0 :         return B->ds + B->vs[id] - field_size;
    1514                 :            : #endif
    1515                 :            :     }
    1516                 :            : }
    1517                 :            : 
    1518                 :          0 : void *flatcc_builder_table_edit(flatcc_builder_t *B, size_t size)
    1519                 :            : {
    1520                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1521                 :            : 
    1522                 :          0 :     return B->ds + B->ds_offset - size;
    1523                 :            : }
    1524                 :            : 
    1525                 :          1 : void *flatcc_builder_table_add_copy(flatcc_builder_t *B, int id, const void *data, size_t size, uint16_t align)
    1526                 :            : {
    1527                 :            :     void *p;
    1528                 :            : 
    1529         [ +  - ]:          1 :     if ((p = flatcc_builder_table_add(B, id, size, align))) {
    1530                 :          1 :         memcpy(p, data, size);
    1531                 :            :     }
    1532                 :          1 :     return p;
    1533                 :            : }
    1534                 :            : 
    1535                 :      22383 : flatcc_builder_ref_t *flatcc_builder_table_add_offset(flatcc_builder_t *B, int id)
    1536                 :            : {
    1537                 :            :     check(frame(type) == flatcc_builder_table, "expected table frame");
    1538                 :            :     check(id >= 0 && id <= (int)FLATBUFFERS_ID_MAX, "table id out of range");
    1539                 :            : #if FLATCC_BUILDER_ALLOW_REPEAT_TABLE_ADD
    1540                 :            :     if (B->vs[id] != 0) {
    1541                 :            :         return B->ds + B->vs[id] - field_size;
    1542                 :            :     }
    1543                 :            : #else
    1544         [ +  - ]:      22383 :     if (B->vs[id] != 0) {
    1545                 :            :         check(0, "table field already set");
    1546                 :            :         return 0;
    1547                 :            :     }
    1548                 :            : #endif
    1549                 :      22383 :     FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)id, (uint32_t)field_size);
    1550                 :      22383 :     return push_ds_offset_field(B, id);
    1551                 :            : }
    1552                 :            : 
    1553                 :          0 : uint16_t flatcc_builder_push_buffer_alignment(flatcc_builder_t *B)
    1554                 :            : {
    1555                 :          0 :     uint16_t old_min_align = B->min_align;
    1556                 :            : 
    1557                 :          0 :     B->min_align = field_size;
    1558                 :          0 :     return old_min_align;
    1559                 :            : }
    1560                 :            : 
    1561                 :          0 : void flatcc_builder_pop_buffer_alignment(flatcc_builder_t *B, uint16_t pushed_align)
    1562                 :            : {
    1563                 :            :     set_min_align(B, pushed_align);
    1564                 :          0 : }
    1565                 :            : 
    1566                 :          0 : uint16_t flatcc_builder_get_buffer_alignment(flatcc_builder_t *B)
    1567                 :            : {
    1568                 :          8 :     return B->min_align;
    1569                 :            : }
    1570                 :            : 
    1571                 :          0 : void flatcc_builder_set_vtable_clustering(flatcc_builder_t *B, int enable)
    1572                 :            : {
    1573                 :            :     /* Inverted because we zero all memory in B on init. */
    1574                 :          0 :     B->disable_vt_clustering = !enable;
    1575                 :          0 : }
    1576                 :            : 
    1577                 :          0 : void flatcc_builder_set_block_align(flatcc_builder_t *B, uint16_t align)
    1578                 :            : {
    1579                 :          0 :     B->block_align = align;
    1580                 :          0 : }
    1581                 :            : 
    1582                 :          0 : int flatcc_builder_get_level(flatcc_builder_t *B)
    1583                 :            : {
    1584                 :          0 :     return B->level;
    1585                 :            : }
    1586                 :            : 
    1587                 :          0 : void flatcc_builder_set_max_level(flatcc_builder_t *B, int max_level)
    1588                 :            : {
    1589                 :          0 :     B->max_level = max_level;
    1590         [ #  # ]:          0 :     if (B->limit_level < B->max_level) {
    1591                 :          0 :         B->limit_level = B->max_level;
    1592                 :            :     }
    1593                 :          0 : }
    1594                 :            : 
    1595                 :          3 : size_t flatcc_builder_get_buffer_size(flatcc_builder_t *B)
    1596                 :            : {
    1597                 :         60 :     return (size_t)(B->emit_end - B->emit_start);
    1598                 :            : }
    1599                 :            : 
    1600                 :          0 : flatcc_builder_ref_t flatcc_builder_get_buffer_start(flatcc_builder_t *B)
    1601                 :            : {
    1602                 :          0 :     return B->emit_start;
    1603                 :            : }
    1604                 :            : 
    1605                 :          0 : flatcc_builder_ref_t flatcc_builder_get_buffer_end(flatcc_builder_t *B)
    1606                 :            : {
    1607                 :          0 :     return B->emit_end;
    1608                 :            : }
    1609                 :            : 
    1610                 :          0 : void flatcc_builder_set_vtable_cache_limit(flatcc_builder_t *B, size_t size)
    1611                 :            : {
    1612                 :          0 :     B->vb_flush_limit = size;
    1613                 :          0 : }
    1614                 :            : 
    1615                 :          0 : void flatcc_builder_set_identifier(flatcc_builder_t *B, const char identifier[identifier_size])
    1616                 :            : {
    1617         [ #  # ]:          0 :     set_identifier(identifier);
    1618                 :          0 : }
    1619                 :            : 
    1620                 :          0 : enum flatcc_builder_type flatcc_builder_get_type(flatcc_builder_t *B)
    1621                 :            : {
    1622         [ #  # ]:          0 :     return B->frame ? frame(type) : flatcc_builder_empty;
    1623                 :            : }
    1624                 :            : 
    1625                 :          0 : enum flatcc_builder_type flatcc_builder_get_type_at(flatcc_builder_t *B, int level)
    1626                 :            : {
    1627 [ #  # ][ #  # ]:          0 :     if (level < 1 || level > B->level) {
    1628                 :            :         return flatcc_builder_empty;
    1629                 :            :     }
    1630                 :          0 :     return B->frame[level - B->level].type;
    1631                 :            : }
    1632                 :            : 
    1633                 :         10 : void *flatcc_builder_get_direct_buffer(flatcc_builder_t *B, size_t *size_out)
    1634                 :            : {
    1635         [ +  - ]:         10 :     if (B->is_default_emitter) {
    1636                 :            :         return flatcc_emitter_get_direct_buffer(&B->default_emit_context, size_out);
    1637                 :            :     } else {
    1638         [ #  # ]:          0 :         if (size_out) {
    1639                 :          0 :             *size_out = 0;
    1640                 :            :         }
    1641                 :            :     }
    1642                 :            :     return 0;
    1643                 :            : }
    1644                 :            : 
    1645                 :         12 : void *flatcc_builder_copy_buffer(flatcc_builder_t *B, void *buffer, size_t size)
    1646                 :            : {
    1647                 :            :     /* User is allowed to call tentatively to see if there is support. */
    1648 [ +  - ][ +  - ]:         69 :     if (!B->is_default_emitter) {
                 [ +  - ]
    1649                 :            :         return 0;
    1650                 :            :     }
    1651                 :         69 :     buffer = flatcc_emitter_copy_buffer(&B->default_emit_context, buffer, size);
    1652                 :            :     check(buffer, "default emitter declined to copy buffer");
    1653                 :         12 :     return buffer;
    1654                 :            : }
    1655                 :            : 
    1656                 :         49 : void *flatcc_builder_finalize_buffer(flatcc_builder_t *B, size_t *size_out)
    1657                 :            : {
    1658                 :            :     void * buffer;
    1659                 :            :     size_t size;
    1660                 :            : 
    1661                 :            :     size = flatcc_builder_get_buffer_size(B);
    1662                 :            : 
    1663         [ +  - ]:         49 :     if (size_out) {
    1664                 :         49 :         *size_out = size;
    1665                 :            :     }
    1666                 :            : 
    1667                 :         49 :     buffer = malloc(size);
    1668                 :            : 
    1669         [ +  - ]:         49 :     if (!buffer) {
    1670                 :            :         check(0, "failed to allocated memory for finalized buffer");
    1671                 :            :         goto done;
    1672                 :            :     }
    1673         [ -  + ]:         49 :     if (!flatcc_builder_copy_buffer(B, buffer, size)) {
    1674                 :            :         check(0, "default emitter declined to copy buffer");
    1675                 :          0 :         free(buffer);
    1676                 :            :         buffer = 0;
    1677                 :            :     }
    1678                 :            : done:
    1679         [ -  + ]:         49 :     if (!buffer && size_out) {
    1680                 :          0 :         *size_out = 0;
    1681                 :            :     }
    1682                 :         49 :     return buffer;
    1683                 :            : }
    1684                 :            : 
    1685                 :            : #ifndef aligned_free
    1686                 :            : #define aligned_free free
    1687                 :            : #endif
    1688                 :            : 
    1689                 :          8 : void *flatcc_builder_finalize_aligned_buffer(flatcc_builder_t *B, size_t *size_out)
    1690                 :            : {
    1691                 :            :     void * buffer;
    1692                 :            :     size_t align;
    1693                 :            :     size_t size;
    1694                 :            : 
    1695                 :            :     size = flatcc_builder_get_buffer_size(B);
    1696                 :            : 
    1697         [ +  - ]:          8 :     if (size_out) {
    1698                 :          8 :         *size_out = size;
    1699                 :            :     }
    1700                 :          8 :     align = flatcc_builder_get_buffer_alignment(B);
    1701                 :            : 
    1702                 :          8 :     size = (size + align - 1) & ~(align - 1);
    1703                 :          8 :     buffer = aligned_alloc(align, size);
    1704                 :            : 
    1705         [ +  - ]:          8 :     if (!buffer) {
    1706                 :            :         goto done;
    1707                 :            :     }
    1708         [ -  + ]:          8 :     if (!flatcc_builder_copy_buffer(B, buffer, size)) {
    1709                 :            :         aligned_free(buffer);
    1710                 :            :         buffer = 0;
    1711                 :          0 :         goto done;
    1712                 :            :     }
    1713                 :            : done:
    1714         [ -  + ]:          8 :     if (!buffer && size_out) {
    1715                 :          0 :         *size_out = 0;
    1716                 :            :     }
    1717                 :          8 :     return buffer;
    1718                 :            : }
    1719                 :            : 
    1720                 :          1 : void *flatcc_builder_get_emit_context(flatcc_builder_t *B)
    1721                 :            : {
    1722                 :          1 :     return B->emit_context;
    1723                 :            : }

Generated by: LCOV version 1.12