diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..42e227d67 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +name: CI + +on: [push, pull_request] + +env: + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + ubuntu-ninja-clang: + name: Ubuntu (ninja, clang) + runs-on: ubuntu-22.04 + steps: + - name: Prepare + run: | + sudo apt update + sudo apt install ninja-build + - uses: actions/checkout@v3 + - name: Build and run tests + env: + CC: clang + CXX: clang++ + run: | + scripts/test.sh + + ubuntu-make-gcc: + name: Ubuntu (make, gcc) + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - name: Build and run tests + env: + CC: gcc + CXX: g++ + run: | + scripts/initbuild.sh make + scripts/test.sh + + macos: + name: macOS + runs-on: macos-12 + steps: + - name: Prepare + run: | + brew install cmake ninja + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + scripts/test.sh + + windows: + name: Windows + runs-on: windows-2022 + steps: + - uses: microsoft/setup-msbuild@v1.1 + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + cmake . + msbuild FlatCC.sln /m /property:Configuration=Release + ctest -VV diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml new file mode 100644 index 000000000..ba78294e4 --- /dev/null +++ b/.github/workflows/weekly.yml @@ -0,0 +1,193 @@ +name: Weekly + +on: + workflow_dispatch: + schedule: + - cron: '0 10 * * 1' # Mon 10.00 UTC + +env: + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + clang: + name: Clang ${{ matrix.clang-version }} + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + clang-version: [5, 7, 9, 11, 13, 15] + steps: + - name: Setup Clang + uses: aminya/setup-cpp@v1 + with: + llvm: ${{ matrix.clang-version }} + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + scripts/initbuild.sh make-concurrent + scripts/test.sh + + clang-32bit: + name: Clang 32bit + runs-on: ubuntu-20.04 + steps: + - name: Prepare + run: | + sudo apt update + sudo apt install gcc-multilib g++-multilib + - uses: actions/checkout@v3 + - name: Build and run tests + env: + CC: clang + CXX: clang++ + run: | + scripts/initbuild.sh make-32bit + scripts/test.sh + + gcc-old: + name: GCC 4.4 + runs-on: ubuntu-20.04 + steps: + - name: Setup GCC + run: | + wget http://launchpadlibrarian.net/336269522/libmpfr4_3.1.6-1_amd64.deb + wget http://old-releases.ubuntu.com/ubuntu/pool/universe/g/gcc-4.4/gcc-4.4-base_4.4.7-8ubuntu1_amd64.deb + wget http://old-releases.ubuntu.com/ubuntu/pool/universe/g/gcc-4.4/cpp-4.4_4.4.7-8ubuntu1_amd64.deb + wget http://old-releases.ubuntu.com/ubuntu/pool/universe/g/gcc-4.4/gcc-4.4_4.4.7-8ubuntu1_amd64.deb + wget http://old-releases.ubuntu.com/ubuntu/pool/universe/g/gcc-4.4/libstdc++6-4.4-dev_4.4.7-8ubuntu1_amd64.deb + wget http://old-releases.ubuntu.com/ubuntu/pool/universe/g/gcc-4.4/g++-4.4_4.4.7-8ubuntu1_amd64.deb + sudo dpkg -i ./libmpfr4_3.1.6-1_amd64.deb + sudo dpkg -i ./gcc-4.4-base_4.4.7-8ubuntu1_amd64.deb + sudo dpkg -i ./cpp-4.4_4.4.7-8ubuntu1_amd64.deb + sudo dpkg -i ./gcc-4.4_4.4.7-8ubuntu1_amd64.deb + sudo dpkg -i ./libstdc++6-4.4-dev_4.4.7-8ubuntu1_amd64.deb ./g++-4.4_4.4.7-8ubuntu1_amd64.deb + - uses: actions/checkout@v3 + - name: Build and run tests + env: + CC: gcc-4.4 + CXX: g++-4.4 + run: | + scripts/initbuild.sh make-concurrent + scripts/test.sh + + gcc: + name: GCC ${{ matrix.gcc-version }} + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + gcc-version: [7, 9, 11] + steps: + - name: Setup GCC + uses: aminya/setup-cpp@v1 + with: + gcc: ${{ matrix.gcc-version }} + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + scripts/initbuild.sh make-concurrent + scripts/test.sh + + gcc-32bit: + name: GCC 32bit + runs-on: ubuntu-20.04 + steps: + - name: Prepare + run: | + sudo apt update + sudo apt install gcc-multilib g++-multilib + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + scripts/initbuild.sh make-32bit + scripts/test.sh + + intel: + name: Intel ${{ matrix.compiler }} + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + compiler: [icc, icx] + steps: + - name: Prepare + run: | + wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | \ + gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | \ + sudo tee /etc/apt/sources.list.d/oneAPI.list + sudo apt update + sudo apt install intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-2021.4.0 + - name: Setup Intel oneAPI + run: | + source /opt/intel/oneapi/setvars.sh + printenv >> $GITHUB_ENV + - uses: actions/checkout@v3 + - name: Build and run tests + env: + CC: ${{ matrix.compiler }} + CXX: ${{ matrix.compiler }} + run: | + scripts/initbuild.sh make-concurrent + scripts/test.sh + + macos-clang: + name: macOS Clang + runs-on: macos-11 + steps: + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + scripts/initbuild.sh make-concurrent + scripts/test.sh + + macos-gcc: + name: macOS GCC ${{ matrix.gcc-version }} + runs-on: macos-11 + strategy: + fail-fast: false + matrix: + gcc-version: [9, 12] + steps: + - uses: actions/checkout@v3 + - name: Prepare + run: | + brew install gcc@${{ matrix.gcc-version }} + - name: Build and run tests + env: + CC: gcc-${{ matrix.gcc-version }} + CXX: g++-${{ matrix.gcc-version }} + run: | + scripts/initbuild.sh make-concurrent + scripts/test.sh + + windows: + name: Windows Visual Studio ${{ matrix.version }} + runs-on: windows-${{ matrix.version }} + strategy: + fail-fast: false + matrix: + version: [2019, 2022] + steps: + - uses: microsoft/setup-msbuild@v1.1 + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + cmake . + msbuild FlatCC.sln /m /property:Configuration=Release + ctest -VV + + cmake-minimum-required: + name: CMake 2.8.12 (min. required) + runs-on: ubuntu-20.04 + steps: + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v1 + with: + cmake-version: 2.8.12 + - uses: actions/checkout@v3 + - name: Build and run tests + run: | + cmake --version + scripts/initbuild.sh make-concurrent + scripts/test.sh diff --git a/.gitignore b/.gitignore index eba83e37c..2d7483235 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ bin/* lib/* release/* scripts/build.cfg +compile_flags.txt +compile_commands.json +.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index cf39d87ce..552c96006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,36 @@ # Change Log -## [0.6.1-pre] +## [0.6.2-pre] + +- CMake: avoid assuming location of build dir during configuration. +- Use untyped integer constants in place of enums for public interface flags to + allow for safe bit masking operations (PR #248). +- Added experimental support for generating `compile_commands.json` via + `CMakeList.txt` for use with clangd. +- Remove `fallthrough` macro for improved portability (#247, #252). +- Added `parse_float/double_compare`, `parse_float/double_is_equal` to + portable library, and added `parse_float/double_isnan` to mirror isinf. + This should help with GCC 32-bit double precision conversion issue. +- Add Github Actions builds to replace stale Travis CI build. This also + includes source code fixes for some build variants. Although + Windows build is included it only covers recent 64-bit Windows. More + work is need for older Windows variants. (#250). +- Increase maximum allowed schema file size from 64 KiB to 1 MB (#256). +- Fix seg fault in json parser while adding null characters to a too + short input string for a fixed length char array struct field (#257). +- Fix regression where empty namespace in schema does not reset root scope + correctly in parser (#265). +- Fix lexer checks that breaks with UTF-8, notably UTF-8 schema comments (#267). +- Add sanitizer flag for clang debug and related warnings (input from several + PRs incl. #237). +- Fix missing runtime check for building too large tables (#235). +- Fix alignment of large objects created outside root buffer (#127). +- Pad top level buffer end to largest object in buffer + +## [0.6.1] - Add `flatcc_builder_alloc` and `flatcc_builder_free` to handle situations - where stanard allocation has been redefined via macros so `free` is no longer + where standard allocation has been redefined via macros so `free` is no longer safe to use. These are similar to the existing `aligned_alloc/free` functions. - Fix a potential, but never seen, low level race condition in the builder when writing a union field because the builder might reallocate between type @@ -60,6 +87,12 @@ affected because warnigs were disabled more broadly than intended. Also note that warnings will still be disabled after pop if the compiler does not support push/pop diagnostics (#205). +- Fix verifier crash on malicious string length input (#221). +- Fix potential crash parsing unterminated JSON (#223). +- Allow 0 (and other unknown values) as schema default value for enums with + `bit_flags` attribute. +- Disable -pedantic flag for GCC >= 8, it just keeps breaking perfectly valid + code (#227). ## [0.6.0] diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a201691d..cb6715a9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,14 @@ # Ubuntu 14.04 (Trusty) -#cmake_minimum_required (VERSION 2.8.12.2) +cmake_minimum_required (VERSION 2.8.12.2) # Centos 7 #cmake_minimum_required (VERSION 2.8.11) -cmake_minimum_required (VERSION 2.8) +#cmake_minimum_required (VERSION 2.8) + +# Experimental for generating compile_commands.json so editors with +# clangd language server support can use it. Symlink +# build/Debug/compile_commands.json to project root where it is +# gitignored. +#set(CMAKE_EXPORT_COMPILE_COMMANDS 1) # Disable build of tests and samples. Due to custom build step # dependency on flatcc tool, some custom build configurations may @@ -14,6 +20,10 @@ option(FLATCC_TEST "enable tests" ON) # project. option(FLATCC_CXX_TEST "enable C++ tests" ON) +# Note that linking with flatcc debug libraries may require souce code to also use +# the sanitize flag. +option(FLATCC_DEBUG_CLANG_SANITIZE "enable clang sanitize flag for debug build" ON) + # Conditionally set project languages based on FLATCC_TEST, as C++ is # only necessary if building the tests. if (FLATCC_TEST AND FLATCC_CXX_TEST) @@ -134,12 +144,8 @@ endif() if (FLATCC_REFLECTION) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFLATCC_REFLECTION=1") - file(WRITE ${PROJECT_SOURCE_DIR}/build/reflection_enabled "REFLECTION=1") - file(REMOVE ${PROJECT_SOURCE_DIR}/build/reflection_disabled) else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFLATCC_REFLECTION=0") - file(REMOVE ${PROJECT_SOURCE_DIR}/build/reflection_enabled) - file(WRITE ${PROJECT_SOURCE_DIR}/build/reflection_disabled "REFLECTION=0") endif() @@ -169,7 +175,7 @@ message(STATUS "lib install dir ${dist_dir}/${lib_dir}") # and constants should be turned off - those are plentiful. They are # silenced for Clang, GCC and MSVC in generated headers.headers. -if (CMAKE_C_COMPILER_ID MATCHES "Clang") +if (CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") # Clang or AppleClang message(STATUS "Setting Clang compiler options") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes") @@ -179,13 +185,23 @@ if (CMAKE_C_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra") # Fix broken C++ alignas - either will do set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPORTABLE_PATCH_CPLUSPLUS_STDALIGN") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPORTABLE_PATCH_CPLUSPLUS_STDALIGN") if (FLATCC_ALLOW_WERROR) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") endif() if (FLATCC_IGNORE_CONST_COND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-tautological-constant-out-of-range-compare") endif() + if (FLATCC_DEBUG_CLANG_SANITIZE) + if (CMAKE_BUILD_TYPE MATCHES Debug) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + endif() + endif() + # Suppress warning relaxed in clang-6, see https://reviews.llvm.org/D28148 + if (CMAKE_C_COMPILER_VERSION VERSION_LESS 6) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers") + endif() # To get assembly output # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -save-temps") @@ -209,8 +225,9 @@ elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU") endif() else() message(STATUS "Setting GNU C compiler options with c11 and Posix") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -pedantic -Wall -Wextra") - if (NOT (GCC_VERSION VERSION_LESS 8.0)) + if (GCC_VERSION VERSION_LESS 8.0) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -pedantic -Wall -Wextra") + elseif (NOT (GCC_VERSION VERSION_LESS 8.0)) # Disable some GCC checks: # (warnings exist since 8.0, but are more aggressive in 9.0) # @@ -219,9 +236,11 @@ elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU") # structs, but these are valid as zero-paddded, not zero terminated. # # -Wno-format-overflow: - # GCC 9 warns on mistakenly assumed NULL string when + # GCC 9 warns on mistakenly assumed NULL string when # printing from a required FlatBuffer string field. # + message(STATUS "Disabling -pedantic for GCC >= 8.0") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Wextra") message(STATUS "Disabling GNU C compiler warnings: -Wstringop-truncation -Wno-format-overflow") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-stringop-truncation -Wno-format-overflow") endif() diff --git a/README.md b/README.md index 78aa7e5d3..3d15466a8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -OS-X & Ubuntu: [![Build Status](https://travis-ci.org/dvidelabs/flatcc.svg?branch=master)](https://travis-ci.org/dvidelabs/flatcc) +Ubuntu, macOS and Windows: [![Build Status](https://github.com/dvidelabs/flatcc/actions/workflows/ci.yml/badge.svg)](https://github.com/dvidelabs/flatcc/actions/workflows/ci.yml) Windows: [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/dvidelabs/flatcc?branch=master&svg=true)](https://ci.appveyor.com/project/dvidelabs/flatcc) +Weekly: [![Build Status](https://github.com/dvidelabs/flatcc/actions/workflows/weekly.yml/badge.svg)](https://github.com/dvidelabs/flatcc/actions/workflows/weekly.yml) _The JSON parser may change the interface for parsing union vectors in a @@ -25,7 +26,7 @@ executable also handle optional json parsing or printing in less than 2 us for a * [Poll on Meson Build](#poll-on-meson-build) * [Reporting Bugs](#reporting-bugs) * [Status](#status) - * [Main features supported as of 0.6.0](#main-features-supported-as-of-060) + * [Main features supported as of 0.6.1](#main-features-supported-as-of-061) * [Supported platforms (CI tested)](#supported-platforms-ci-tested) * [Platforms reported to work by users](#platforms-reported-to-work-by-users) * [Portability](#portability) @@ -81,6 +82,7 @@ executable also handle optional json parsing or printing in less than 2 us for a * [Using the Compiler and Builder library](#using-the-compiler-and-builder-library) * [FlatBuffers Binary Format](#flatbuffers-binary-format) * [Security Considerations](#security-considerations) +* [Style Guide](#style-guide) * [Benchmarks](#benchmarks) @@ -292,6 +294,30 @@ fi ## Status +Release 0.6.2 (in development) is primarily a bug fix release, refer +to CHANGELOG for details. A long standing bug has been fixed where +where objects created before a call to _create_as_root would not be +properly aligned, and buffer end is now also padded to largest object +seen within the buffer. +Note that for clang debug builds, -fsanitize=undefined has been +added and this may require dependent source code to also use +that flag to avoid missing linker symbols. The feature can be disabled +in CMakeLists.txt. + +Release 0.6.1 contains primarily bug fixes and numerous contributions +from the community to handle platform edge cases. Additionally, +pendantic GCC warnings are disabled, relying instead on clang, since GCC +is too aggressive, breaks builds frequently and works against +portability. An existing C++ test case ensures that C code also works +with common C++ compilers, but it can break some environments, so there +is now a flag to disable that test without disabling all tests. Support +for Optional Scalar Values in the FlatBuffer format has been added. +There is also improved support for abstracting memory allocation on +various platforms. `_identifier` has been deprecated in favor +`
_file_identifier` in generated code due to `identifier` easily +leading to name conflicts. `file_extension` constant in generated code +is now without prefixed dot (.). + Release 0.6.0 introduces a "primary" attribute to be used together with a key attribute to chose default key for finding and sorting. If primary is absent, the key with the lowest id becomes primary. Tables and @@ -339,7 +365,7 @@ low-level union interface so the terms { type, value } are used consistently over { type, member } and { types, members }. -### Main features supported as of 0.6.0 +### Main features supported as of 0.6.1 - generated FlatBuffers reader and builder headers for C - generated FlatBuffers verifier headers for C @@ -364,6 +390,7 @@ consistently over { type, member } and { types, members }. - base64(url) encoded binary data in JSON. - sort fields by primary key (as of 0.6.0) - char arrays (as of 0.6.0) +- optional scalar values (as of 0.6.1) There are no plans to make frequent updates once the project becomes stable, but input from the community will always be welcome and included @@ -373,6 +400,11 @@ different target platforms. ### Supported platforms (CI tested) +This list is somewhat outdated, more recent compiler versions are added and +some old ones are removed when CI platforms no longer supported but largely +the supported targets remain unchanged. MSVC 2010 might become deprecated +in the future. + The ci-more branch tests additional compilers: - Ubuntu Trusty gcc 4.4, 4.6-4.9, 5, 6, 7 and clang 3.6, 3.8 @@ -1233,6 +1265,25 @@ For advanced debugging the [hexdump.h] file can be used to dump the buffer contents. It is used in [test_json.c] and also in [monster_test.c]. See also [FlatBuffers Binary Format]. +As of April 2022, Googles flatc tool has implemented an `--annotate` feature. +This provides an annotated hex dump given a binary buffer and a schema. The +output can be used to troubleshoot and rule out or confirm suspected encoding +bugs in the buffer at hand. The eclectic example in the [FlatBuffers Binary +Format] document contains a hand written annotated example which inspired the +`--annotate` feature, but it is not the exact same output format. Note also that +`flatc` generated buffers tend to have vtables before the table it is referenced +by, while flatcc normally packs all vtables at the end of the buffer for +better padding and cache efficiency. + +See also [flatc --annotate]. + +Note: There is experimental support for text editor that supports +clangd language server or similar. You can edit `CMakeList.txt` +to generate `build/Debug/compile_comands.json`, at least when +using clang as a compiler, and copy or symlink it from root. Or +come with a better suggestion. There are `.gitignore` entries for +`compile_flags.txt` and `compile_commands.json` in project root. + ## File and Type Identifiers @@ -2191,8 +2242,15 @@ Optionally switch to a different build tool by choosing one of: scripts/initbuild.sh make-concurrent scripts/initbuild.sh ninja -where `ninja` is the default and `make-concurrent` is `make` with the `-j` -flag. A custom build configuration `X` can be added by adding a +where `ninja` is the default and `make-concurrent` is `make` with the `-j` flag. + +To enforce a 32-bit build on a 64-bit machine the following configuration +can be used: + + scripts/initbuild.sh make-32bit + +which uses `make` and provides the `-m32` flag to the compiler. +A custom build configuration `X` can be added by adding a `scripts/build.cfg.X` file. `scripts/initbuild.sh` cleans the build if a specific build @@ -2527,6 +2585,31 @@ Mostly for implementers: [FlatBuffers Binary Format] See [Security Considerations]. +## Style Guide + +FlatCC coding style is largely similar to the [WebKit Style], with the following notable exceptions: + +* Syntax requiring C99 or later is avoided, except `` types are made available. +* If conditions always use curly brackets, or single line statements without linebreak: `if (err) return -1;`. +* NULL and nullptr are generally just represented as `0`. +* Comments are old-school C-style (pre C99). Text is generally cased with punctuation: `/* A comment. */` +* `true` and `false` keywords are not used (pre C99). +* In code generation there is essentially no formatting to avoid excessive bloat. +* Struct names and other types is lower case since this is C, not C++. +* `snake_case` is used over `camelCase`. +* Header guards are used over `#pragma once` because it is non-standard and not always reliable in filesystems with ambigious paths. +* Comma is not placed first in multi-line calls (but maybe that would be a good idea for diff stability). +* `config.h` inclusion might be handled differently in that `flatbuffers.h` includes the config file. +* `unsigned` is not used without `int` for historical reasons. Generally a type like `uint32_t` is preferred. +* Use `TODO:` instead of `FIXME:` in comments for historical reasons. + +All the main source code in compiler and runtime aim to be C11 compatible and +uses many C11 constructs. This is made possible through the included portable +library such that older compilers can also function. Therefore any platform specific adaptations will be provided by updating +the portable library rather than introducing compile time flags in the main +source code. + + ## Benchmarks See [Benchmarks] @@ -2548,3 +2631,5 @@ See [Benchmarks] [hexdump.h]: https://github.com/dvidelabs/flatcc/blob/master/include/flatcc/support/hexdump.h [readfile.h]: include/flatcc/support/readfile.h [Security Considerations]: https://github.com/dvidelabs/flatcc/blob/master/doc/security.md +[flatc --annotate]: https://github.com/google/flatbuffers/tree/master/tests/annotated_binary +[WebKit Style]: https://webkit.org/code-style-guidelines/ diff --git a/config/config.h b/config/config.h index 041ec228c..b07fa6cc8 100644 --- a/config/config.h +++ b/config/config.h @@ -54,7 +54,7 @@ * is covers the accumulated size of all included files. 0 is unlimited. */ #ifndef FLATCC_MAX_SCHEMA_SIZE -#define FLATCC_MAX_SCHEMA_SIZE 64 * 1024 +#define FLATCC_MAX_SCHEMA_SIZE 1000000 #endif /* diff --git a/external/lex/luthor.c b/external/lex/luthor.c index fc81985f3..5f037d726 100644 --- a/external/lex/luthor.c +++ b/external/lex/luthor.c @@ -176,16 +176,16 @@ static const char lex_alnum[256] = { #endif #ifndef lex_isdigit -#define lex_isdigit(c) ((c) >= '0' && (c) <= '9') +#define lex_isdigit(c) ((unsigned)(c) >= '0' && (unsigned)(c) <= '9') #endif #ifndef lex_ishexdigit -#define lex_ishexdigit(c) (((c) >= '0' && (c) <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f')) +#define lex_ishexdigit(c) (((c) >= '0' && ((unsigned)c) <= '9') || ((unsigned)(c | 0x20) >= 'a' && (unsigned)(c | 0x20) <= 'f')) #endif #ifndef lex_isctrl #include -#define lex_isctrl(c) ((c) < 0x20 || (c) == 0x7f) +#define lex_isctrl(c) (((unsigned)c) < 0x20 || (c) == 0x7f) #endif #ifndef lex_isblank diff --git a/include/flatcc/flatcc_builder.h b/include/flatcc/flatcc_builder.h index 3871b1d07..2e84d2979 100644 --- a/include/flatcc/flatcc_builder.h +++ b/include/flatcc/flatcc_builder.h @@ -710,10 +710,13 @@ static inline void flatcc_builder_refmap_reset(flatcc_builder_t *B) } -enum flatcc_builder_buffer_flags { - flatcc_builder_is_nested = 1, - flatcc_builder_with_size = 2, -}; +typedef uint16_t flatcc_builder_buffer_flags_t; +static const flatcc_builder_buffer_flags_t flatcc_builder_is_nested = 1; +static const flatcc_builder_buffer_flags_t flatcc_builder_with_size = 2; + +/* The flag size in the API needs to match the internal size. */ +static_assert(sizeof(flatcc_builder_buffer_flags_t) == + sizeof(((flatcc_builder_t *)0)->buffer_flags), "flag size mismatch"); /** * An alternative to start buffer, start struct/table ... end buffer. @@ -776,7 +779,7 @@ enum flatcc_builder_buffer_flags { flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B, const char identifier[FLATBUFFERS_IDENTIFIER_SIZE], uint16_t block_align, - flatcc_builder_ref_t ref, uint16_t align, int flags); + flatcc_builder_ref_t ref, uint16_t align, flatcc_builder_buffer_flags_t flags); /** * Creates a struct within the current buffer without using any @@ -867,7 +870,7 @@ flatcc_builder_ref_t flatcc_builder_end_struct(flatcc_builder_t *B); */ int flatcc_builder_start_buffer(flatcc_builder_t *B, const char identifier[FLATBUFFERS_IDENTIFIER_SIZE], - uint16_t block_align, int flags); + uint16_t block_align, flatcc_builder_buffer_flags_t flags); /** * The root object should be a struct or a table to conform to the @@ -923,7 +926,7 @@ flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_build */ flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B, uint16_t block_align, - const void *data, size_t size, uint16_t align, int flags); + const void *data, size_t size, uint16_t align, flatcc_builder_buffer_flags_t flags); /** * Applies to the innermost open buffer. The identifier may be null or diff --git a/include/flatcc/flatcc_json_parser.h b/include/flatcc/flatcc_json_parser.h index 1907fc7fc..f8281295a 100644 --- a/include/flatcc/flatcc_json_parser.h +++ b/include/flatcc/flatcc_json_parser.h @@ -22,13 +22,12 @@ extern "C" { #define PDIAGNOSTIC_IGNORE_UNUSED #include "flatcc/portable/pdiagnostic_push.h" -enum flatcc_json_parser_flags { - flatcc_json_parser_f_skip_unknown = 1, - flatcc_json_parser_f_force_add = 2, - flatcc_json_parser_f_with_size = 4, - flatcc_json_parser_f_skip_array_overflow = 8, - flatcc_json_parser_f_reject_array_underflow = 16 -}; +typedef uint32_t flatcc_json_parser_flags_t; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_skip_unknown = 1; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_force_add = 2; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_with_size = 4; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_skip_array_overflow = 8; +static const flatcc_json_parser_flags_t flatcc_json_parser_f_reject_array_underflow = 16; #define FLATCC_JSON_PARSE_ERROR_MAP(XX) \ XX(ok, "ok") \ @@ -92,7 +91,7 @@ typedef struct flatcc_json_parser_ctx flatcc_json_parser_t; struct flatcc_json_parser_ctx { flatcc_builder_t *ctx; const char *line_start; - int flags; + flatcc_json_parser_flags_t flags; #if FLATCC_JSON_PARSE_ALLOW_UNQUOTED int unquoted; #endif @@ -111,7 +110,7 @@ static inline int flatcc_json_parser_get_error(flatcc_json_parser_t *ctx) return ctx->error; } -static inline void flatcc_json_parser_init(flatcc_json_parser_t *ctx, flatcc_builder_t *B, const char *buf, const char *end, int flags) +static inline void flatcc_json_parser_init(flatcc_json_parser_t *ctx, flatcc_builder_t *B, const char *buf, const char *end, flatcc_json_parser_flags_t flags) { memset(ctx, 0, sizeof(*ctx)); ctx->ctx = B; @@ -243,24 +242,38 @@ static inline uint64_t flatcc_json_parser_symbol_part_ext(const char *buf, const } /* This can bloat inlining for a rarely executed case. */ #if 1 - /* Fall through comments needed to silence gcc 7 warnings. */ switch (n) { - case 8: w |= ((uint64_t)buf[7]) << (0 * 8); - fallthrough; - case 7: w |= ((uint64_t)buf[6]) << (1 * 8); - fallthrough; - case 6: w |= ((uint64_t)buf[5]) << (2 * 8); - fallthrough; - case 5: w |= ((uint64_t)buf[4]) << (3 * 8); - fallthrough; - case 4: w |= ((uint64_t)buf[3]) << (4 * 8); - fallthrough; - case 3: w |= ((uint64_t)buf[2]) << (5 * 8); - fallthrough; - case 2: w |= ((uint64_t)buf[1]) << (6 * 8); - fallthrough; - case 1: w |= ((uint64_t)buf[0]) << (7 * 8); - fallthrough; + case 8: + w |= ((uint64_t)buf[7]) << (0 * 8); + goto lbl_n_7; + case 7: +lbl_n_7: + w |= ((uint64_t)buf[6]) << (1 * 8); + goto lbl_n_6; + case 6: +lbl_n_6: + w |= ((uint64_t)buf[5]) << (2 * 8); + goto lbl_n_5; + case 5: +lbl_n_5: + w |= ((uint64_t)buf[4]) << (3 * 8); + goto lbl_n_4; + case 4: +lbl_n_4: + w |= ((uint64_t)buf[3]) << (4 * 8); + goto lbl_n_3; + case 3: +lbl_n_3: + w |= ((uint64_t)buf[2]) << (5 * 8); + goto lbl_n_2; + case 2: +lbl_n_2: + w |= ((uint64_t)buf[1]) << (6 * 8); + goto lbl_n_1; + case 1: +lbl_n_1: + w |= ((uint64_t)buf[0]) << (7 * 8); + break; case 0: break; } @@ -872,10 +885,10 @@ const char *flatcc_json_parser_union_type_vector(flatcc_json_parser_t *ctx, * `buf`, `bufsiz` may be larger than the parsed json if trailing * space or zeroes are expected, but they must represent a valid memory buffer. * `fid` must be null, or a valid file identifier. - * `flags` default to 0. See also `flatcc_json_parser_flags`. + * `flags` default to 0. See also `flatcc_json_parser_f_` constants. */ int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_table_f *parser); /* @@ -883,7 +896,7 @@ int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t * * root. */ int flatcc_json_parser_struct_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_struct_f *parser); #include "flatcc/portable/pdiagnostic_pop.h" diff --git a/include/flatcc/flatcc_json_printer.h b/include/flatcc/flatcc_json_printer.h index 0ce49c146..cab49a1a4 100644 --- a/include/flatcc/flatcc_json_printer.h +++ b/include/flatcc/flatcc_json_printer.h @@ -243,14 +243,13 @@ static inline void flatcc_json_printer_set_nonstrict(flatcc_json_printer_t *ctx) flatcc_json_printer_set_noenum(ctx, 0); } -enum flatcc_json_printer_flags { - flatcc_json_printer_f_unquote = 1, - flatcc_json_printer_f_noenum = 2, - flatcc_json_printer_f_skip_default = 4, - flatcc_json_printer_f_force_default = 8, - flatcc_json_printer_f_pretty = 16, - flatcc_json_printer_f_nonstrict = 32, -}; +typedef uint32_t flatcc_json_printer_flags_t; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_unquote = 1; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_noenum = 2; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_skip_default = 4; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_force_default = 8; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_pretty = 16; +static const flatcc_json_printer_flags_t flatcc_json_printer_f_nonstrict = 32; /* * May be called instead of setting operational modes individually. @@ -268,7 +267,7 @@ enum flatcc_json_printer_flags { * `pretty` flag sets indentation to 2. * `nonstrict` implies: `noenum`, `unquote`, `pretty`. */ -static inline void flatcc_json_printer_set_flags(flatcc_json_printer_t *ctx, int flags) +static inline void flatcc_json_printer_set_flags(flatcc_json_printer_t *ctx, flatcc_json_printer_flags_t flags) { ctx->unquote = !!(flags & flatcc_json_printer_f_unquote); ctx->noenum = !!(flags & flatcc_json_printer_f_noenum); diff --git a/include/flatcc/flatcc_version.h b/include/flatcc/flatcc_version.h index 87158986b..78bc9c8d3 100644 --- a/include/flatcc/flatcc_version.h +++ b/include/flatcc/flatcc_version.h @@ -2,10 +2,10 @@ extern "C" { #endif -#define FLATCC_VERSION_TEXT "0.6.1-dev" +#define FLATCC_VERSION_TEXT "0.6.2" #define FLATCC_VERSION_MAJOR 0 #define FLATCC_VERSION_MINOR 6 -#define FLATCC_VERSION_PATCH 1 +#define FLATCC_VERSION_PATCH 2 /* 1 or 0 */ #define FLATCC_VERSION_RELEASED 0 diff --git a/include/flatcc/portable/paligned_alloc.h b/include/flatcc/portable/paligned_alloc.h index 3dcf4efcd..70b00b9ea 100644 --- a/include/flatcc/portable/paligned_alloc.h +++ b/include/flatcc/portable/paligned_alloc.h @@ -61,6 +61,8 @@ extern "C" { #define PORTABLE_C11_ALIGNED_ALLOC 0 #elif defined (__clang__) #define PORTABLE_C11_ALIGNED_ALLOC 0 +#elif defined (__APPLE__) +#define PORTABLE_C11_ALIGNED_ALLOC 0 #elif defined(__IBMC__) #define PORTABLE_C11_ALIGNED_ALLOC 0 #elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) diff --git a/include/flatcc/portable/pattributes.h b/include/flatcc/portable/pattributes.h index 30b3b23d3..9240fa319 100644 --- a/include/flatcc/portable/pattributes.h +++ b/include/flatcc/portable/pattributes.h @@ -40,7 +40,7 @@ extern "C" { #endif #ifndef PORTABLE_EXPOSE_ATTRIBUTES -#define PORTABLE_EXPOSE_ATTRIBUTES 1 +#define PORTABLE_EXPOSE_ATTRIBUTES 0 #endif #ifdef __has_c_attribute diff --git a/include/flatcc/portable/pparsefp.h b/include/flatcc/portable/pparsefp.h index 1d2b9da26..7fa1c247d 100644 --- a/include/flatcc/portable/pparsefp.h +++ b/include/flatcc/portable/pparsefp.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include /* memcpy */ + /* * Parses a float or double number and returns the length parsed if * successful. The length argument is of limited value due to dependency @@ -34,7 +36,7 @@ extern "C" { * Other compilers such as xlc may require linking with -lm which may not * be convienent so a default isinf is provided. If isinf is available * and there is a noticable performance issue, define - * `PORTABLE_USE_ISINF`. + * `PORTABLE_USE_ISINF`. This flag also affects isnan. */ #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || defined(PORTABLE_USE_ISINF) #include @@ -44,12 +46,13 @@ extern "C" { #define isinf(x) (!_finite(x)) #endif /* - * clang-5 through clang-8 but not clang-9 issues incorrect precision + * clang-3 through clang-8 but not clang-9 issues incorrect precision * loss warning with -Wconversion flag when cast is absent. */ #if defined(__clang__) -#if __clang_major__ >= 5 && __clang_major__ <= 8 +#if __clang_major__ >= 3 && __clang_major__ <= 8 #define parse_double_isinf(x) isinf((float)x) +#define parse_double_isnan(x) isnan((float)x) #endif #endif #if !defined(parse_double_isinf) @@ -64,19 +67,29 @@ extern "C" { #endif /* Avoid linking with libmath but depends on float/double being IEEE754 */ -static inline int parse_double_isinf(double x) +static inline int parse_double_isinf(const double x) { - union { uint64_t u64; double f64; } v; - v.f64 = x; - return (v.u64 & 0x7fffffff00000000ULL) == 0x7ff0000000000000ULL; + uint64_t u64x; + + memcpy(&u64x, &x, sizeof(u64x)); + return (u64x & 0x7fffffff00000000ULL) == 0x7ff0000000000000ULL; } static inline int parse_float_isinf(float x) { - union { uint32_t u32; float f32; } v; - v.f32 = x; - return (v.u32 & 0x7fffffff) == 0x7f800000; + uint32_t u32x; + + memcpy(&u32x, &x, sizeof(u32x)); + return (u32x & 0x7fffffff) == 0x7f800000; } + +#endif + +#if !defined(parse_double_isnan) +#define parse_double_isnan isnan +#endif +#if !defined(parse_float_isnan) +#define parse_float_isnan isnan #endif /* Returns 0 when in range, 1 on overflow, and -1 on underflow. */ @@ -131,6 +144,79 @@ static inline const char *parse_float(const char *buf, size_t len, float *result return end; } +/* Inspired by https://bitbashing.io/comparing-floats.html */ + +/* Return signed ULP distance or INT64_MAX if any value is nan. */ +static inline int64_t parse_double_compare(const double x, const double y) +{ + int64_t i64x, i64y; + + if (x == y) return 0; + if (parse_double_isnan(x)) return INT64_MAX; + if (parse_double_isnan(y)) return INT64_MAX; + memcpy(&i64x, &x, sizeof(i64x)); + memcpy(&i64y, &y, sizeof(i64y)); + if ((i64x < 0) != (i64y < 0)) return INT64_MAX; + return i64x - i64y; +} + +/* Same as double, but INT32_MAX if nan. */ +static inline int32_t parse_float_compare(const float x, const float y) +{ + int32_t i32x, i32y; + + if (x == y) return 0; + if (parse_float_isnan(x)) return INT32_MAX; + if (parse_float_isnan(y)) return INT32_MAX; + memcpy(&i32x, &x, sizeof(i32x)); + memcpy(&i32y, &y, sizeof(i32y)); + if ((i32x < 0) != (i32y < 0)) return INT32_MAX; + return i32x - i32y; +} + +/* + * Returns the absolute distance in floating point ULP (representational bit difference). + * Uses signed return value so that INT64_MAX and INT32_MAX indicates NaN similar to + * the compare function. + */ +static inline int64_t parse_double_dist(const double x, const double y) +{ + uint64_t m64; + int64_t i64; + + i64 = parse_double_compare(x, y); + /* Absolute integer value of compare. */ + m64 = (uint64_t)-(i64 < 0); + return (int64_t)(((uint64_t)i64 + m64) ^ m64); +} + +/* Same as double, but INT32_MAX if NaN. */ +static inline int32_t parse_float_dist(const float x, const float y) +{ + uint32_t m32; + int32_t i32; + + i32 = parse_float_compare(x, y); + /* Absolute integer value of compare. */ + m32 = (uint32_t)-(i32 < 0); + return (int32_t)(((uint32_t)i32 + m32) ^ m32); +} + +/* + * Returns 1 if no value is NaN, and the difference is at most one ULP (1 bit), and the + * sign is the same, and 0 otherwise. + */ +static inline int parse_double_is_equal(const double x, const double y) +{ + return parse_double_dist(x, y) >> 1 == 0; +} + +/* Same as double, but at lower precision. */ +static inline int parse_float_is_equal(const float x, const float y) +{ + return parse_float_dist(x, y) >> 1 == 0; +} + #include "pdiagnostic_pop.h" #ifdef __cplusplus diff --git a/include/flatcc/reflection/flatbuffers_common_builder.h b/include/flatcc/reflection/flatbuffers_common_builder.h index b5ce8a5ce..a4be1ce6e 100644 --- a/include/flatcc/reflection/flatbuffers_common_builder.h +++ b/include/flatcc/reflection/flatbuffers_common_builder.h @@ -1,7 +1,7 @@ #ifndef FLATBUFFERS_COMMON_BUILDER_H #define FLATBUFFERS_COMMON_BUILDER_H -/* Generated by flatcc 0.6.1-dev FlatBuffers schema compiler for C by dvide.com */ +/* Generated by flatcc 0.6.1 FlatBuffers schema compiler for C by dvide.com */ /* Common FlatBuffers build functionality for C. */ diff --git a/include/flatcc/reflection/flatbuffers_common_reader.h b/include/flatcc/reflection/flatbuffers_common_reader.h index 67971e9af..c57530868 100644 --- a/include/flatcc/reflection/flatbuffers_common_reader.h +++ b/include/flatcc/reflection/flatbuffers_common_reader.h @@ -1,7 +1,7 @@ #ifndef FLATBUFFERS_COMMON_READER_H #define FLATBUFFERS_COMMON_READER_H -/* Generated by flatcc 0.6.1-dev FlatBuffers schema compiler for C by dvide.com */ +/* Generated by flatcc 0.6.1 FlatBuffers schema compiler for C by dvide.com */ /* Common FlatBuffers read functionality for C. */ diff --git a/include/flatcc/reflection/reflection_builder.h b/include/flatcc/reflection/reflection_builder.h index 4b05199ee..65aef73e5 100644 --- a/include/flatcc/reflection/reflection_builder.h +++ b/include/flatcc/reflection/reflection_builder.h @@ -1,7 +1,7 @@ #ifndef REFLECTION_BUILDER_H #define REFLECTION_BUILDER_H -/* Generated by flatcc 0.6.1-dev FlatBuffers schema compiler for C by dvide.com */ +/* Generated by flatcc 0.6.1 FlatBuffers schema compiler for C by dvide.com */ #ifndef REFLECTION_READER_H #include "reflection_reader.h" @@ -13,7 +13,7 @@ #undef flatbuffers_identifier #define flatbuffers_identifier "BFBS" #undef flatbuffers_extension -#define flatbuffers_extension ".bfbs" +#define flatbuffers_extension "bfbs" #define __reflection_BaseType_formal_args , reflection_BaseType_enum_t v0 #define __reflection_BaseType_call_args , v0 diff --git a/include/flatcc/reflection/reflection_reader.h b/include/flatcc/reflection/reflection_reader.h index 06b1dfb46..bf6a0e946 100644 --- a/include/flatcc/reflection/reflection_reader.h +++ b/include/flatcc/reflection/reflection_reader.h @@ -1,7 +1,7 @@ #ifndef REFLECTION_READER_H #define REFLECTION_READER_H -/* Generated by flatcc 0.6.1-dev FlatBuffers schema compiler for C by dvide.com */ +/* Generated by flatcc 0.6.1 FlatBuffers schema compiler for C by dvide.com */ #ifndef FLATBUFFERS_COMMON_READER_H #include "flatbuffers_common_reader.h" @@ -14,7 +14,7 @@ #undef flatbuffers_identifier #define flatbuffers_identifier "BFBS" #undef flatbuffers_extension -#define flatbuffers_extension ".bfbs" +#define flatbuffers_extension "bfbs" typedef const struct reflection_Type_table *reflection_Type_table_t; @@ -54,86 +54,113 @@ typedef struct reflection_Schema_table *reflection_Schema_mutable_table_t; typedef const flatbuffers_uoffset_t *reflection_Schema_vec_t; typedef flatbuffers_uoffset_t *reflection_Schema_mutable_vec_t; #ifndef reflection_Type_file_identifier -#define reflection_Type_file_identifier flatbuffers_identifier +#define reflection_Type_file_identifier "BFBS" #endif /* deprecated, use reflection_Type_file_identifier */ #ifndef reflection_Type_identifier -#define reflection_Type_identifier flatbuffers_identifier +#define reflection_Type_identifier "BFBS" #endif #define reflection_Type_type_hash ((flatbuffers_thash_t)0x44c8fe5e) #define reflection_Type_type_identifier "\x5e\xfe\xc8\x44" +#ifndef reflection_Type_file_extension +#define reflection_Type_file_extension "bfbs" +#endif #ifndef reflection_KeyValue_file_identifier -#define reflection_KeyValue_file_identifier flatbuffers_identifier +#define reflection_KeyValue_file_identifier "BFBS" #endif /* deprecated, use reflection_KeyValue_file_identifier */ #ifndef reflection_KeyValue_identifier -#define reflection_KeyValue_identifier flatbuffers_identifier +#define reflection_KeyValue_identifier "BFBS" #endif #define reflection_KeyValue_type_hash ((flatbuffers_thash_t)0x8c761eaa) #define reflection_KeyValue_type_identifier "\xaa\x1e\x76\x8c" +#ifndef reflection_KeyValue_file_extension +#define reflection_KeyValue_file_extension "bfbs" +#endif #ifndef reflection_EnumVal_file_identifier -#define reflection_EnumVal_file_identifier flatbuffers_identifier +#define reflection_EnumVal_file_identifier "BFBS" #endif /* deprecated, use reflection_EnumVal_file_identifier */ #ifndef reflection_EnumVal_identifier -#define reflection_EnumVal_identifier flatbuffers_identifier +#define reflection_EnumVal_identifier "BFBS" #endif #define reflection_EnumVal_type_hash ((flatbuffers_thash_t)0x9531c946) #define reflection_EnumVal_type_identifier "\x46\xc9\x31\x95" +#ifndef reflection_EnumVal_file_extension +#define reflection_EnumVal_file_extension "bfbs" +#endif #ifndef reflection_Enum_file_identifier -#define reflection_Enum_file_identifier flatbuffers_identifier +#define reflection_Enum_file_identifier "BFBS" #endif /* deprecated, use reflection_Enum_file_identifier */ #ifndef reflection_Enum_identifier -#define reflection_Enum_identifier flatbuffers_identifier +#define reflection_Enum_identifier "BFBS" #endif #define reflection_Enum_type_hash ((flatbuffers_thash_t)0xacffa90f) #define reflection_Enum_type_identifier "\x0f\xa9\xff\xac" +#ifndef reflection_Enum_file_extension +#define reflection_Enum_file_extension "bfbs" +#endif #ifndef reflection_Field_file_identifier -#define reflection_Field_file_identifier flatbuffers_identifier +#define reflection_Field_file_identifier "BFBS" #endif /* deprecated, use reflection_Field_file_identifier */ #ifndef reflection_Field_identifier -#define reflection_Field_identifier flatbuffers_identifier +#define reflection_Field_identifier "BFBS" #endif #define reflection_Field_type_hash ((flatbuffers_thash_t)0x9f7e408a) #define reflection_Field_type_identifier "\x8a\x40\x7e\x9f" +#ifndef reflection_Field_file_extension +#define reflection_Field_file_extension "bfbs" +#endif #ifndef reflection_Object_file_identifier -#define reflection_Object_file_identifier flatbuffers_identifier +#define reflection_Object_file_identifier "BFBS" #endif /* deprecated, use reflection_Object_file_identifier */ #ifndef reflection_Object_identifier -#define reflection_Object_identifier flatbuffers_identifier +#define reflection_Object_identifier "BFBS" #endif #define reflection_Object_type_hash ((flatbuffers_thash_t)0xb09729bd) #define reflection_Object_type_identifier "\xbd\x29\x97\xb0" +#ifndef reflection_Object_file_extension +#define reflection_Object_file_extension "bfbs" +#endif #ifndef reflection_RPCCall_file_identifier -#define reflection_RPCCall_file_identifier flatbuffers_identifier +#define reflection_RPCCall_file_identifier "BFBS" #endif /* deprecated, use reflection_RPCCall_file_identifier */ #ifndef reflection_RPCCall_identifier -#define reflection_RPCCall_identifier flatbuffers_identifier +#define reflection_RPCCall_identifier "BFBS" #endif #define reflection_RPCCall_type_hash ((flatbuffers_thash_t)0xe2d586f1) #define reflection_RPCCall_type_identifier "\xf1\x86\xd5\xe2" +#ifndef reflection_RPCCall_file_extension +#define reflection_RPCCall_file_extension "bfbs" +#endif #ifndef reflection_Service_file_identifier -#define reflection_Service_file_identifier flatbuffers_identifier +#define reflection_Service_file_identifier "BFBS" #endif /* deprecated, use reflection_Service_file_identifier */ #ifndef reflection_Service_identifier -#define reflection_Service_identifier flatbuffers_identifier +#define reflection_Service_identifier "BFBS" #endif #define reflection_Service_type_hash ((flatbuffers_thash_t)0xf31a13b5) #define reflection_Service_type_identifier "\xb5\x13\x1a\xf3" +#ifndef reflection_Service_file_extension +#define reflection_Service_file_extension "bfbs" +#endif #ifndef reflection_Schema_file_identifier -#define reflection_Schema_file_identifier flatbuffers_identifier +#define reflection_Schema_file_identifier "BFBS" #endif /* deprecated, use reflection_Schema_file_identifier */ #ifndef reflection_Schema_identifier -#define reflection_Schema_identifier flatbuffers_identifier +#define reflection_Schema_identifier "BFBS" #endif #define reflection_Schema_type_hash ((flatbuffers_thash_t)0xfaf93779) #define reflection_Schema_type_identifier "\x79\x37\xf9\xfa" +#ifndef reflection_Schema_file_extension +#define reflection_Schema_file_extension "bfbs" +#endif typedef int8_t reflection_BaseType_enum_t; __flatbuffers_define_integer_type(reflection_BaseType, reflection_BaseType_enum_t, 8) diff --git a/include/flatcc/reflection/reflection_verifier.h b/include/flatcc/reflection/reflection_verifier.h index 7d04f34df..5b5bd374a 100644 --- a/include/flatcc/reflection/reflection_verifier.h +++ b/include/flatcc/reflection/reflection_verifier.h @@ -1,7 +1,7 @@ #ifndef REFLECTION_VERIFIER_H #define REFLECTION_VERIFIER_H -/* Generated by flatcc 0.6.1-dev FlatBuffers schema compiler for C by dvide.com */ +/* Generated by flatcc 0.6.1 FlatBuffers schema compiler for C by dvide.com */ #ifndef REFLECTION_READER_H #include "reflection_reader.h" diff --git a/scripts/_user_build.in b/scripts/_user_build.in index dfcc40a62..d235a0e8f 100644 --- a/scripts/_user_build.in +++ b/scripts/_user_build.in @@ -15,12 +15,21 @@ mkdir -p generated cd build +# we cannot link with debug library unless we use the sanitize flag. +SANFLAG_DEBUG="" +compiler_info="$($CC --version 2>&1)" +echo "using compiler: $compiler_info" +if echo $compiler_info | grep -q -i "clang"; then + SANFLAG_DEBUG="-fsanitize=undefined" + echo "debug sanitizer flag: $SANFLAG_DEBUG" +fi + if [[ "$FLATCC_PORTABLE" = "yes" ]]; then CFLAGS="$CFLAGS -DFLATCC_PORTABLE" fi CFLAGS="$CFLAGS -I ${ROOT}/include -I ${ROOT}/generated" -CFLAGS_DEBUG=${CFLAGS_DEBUG:--g} +CFLAGS_DEBUG=${CFLAGS_DEBUG:--g $SANFLAG_DEBUG} CFLAGS_RELEASE=${CFLAGS_RELEASE:--O2 -DNDEBUG} ${ROOT}/bin/flatcc -a -o ${ROOT}/generated ${ROOT}/src/*.fbs diff --git a/scripts/build.cfg.make b/scripts/build.cfg.make index 684ecfc81..ae9c33258 100644 --- a/scripts/build.cfg.make +++ b/scripts/build.cfg.make @@ -1,2 +1,3 @@ FLATCC_BUILD_GEN="Unix Makefiles" FLATCC_BUILD_CMD=make +FLATCC_BUILD_FLAGS="" diff --git a/scripts/build.cfg.make-32bit b/scripts/build.cfg.make-32bit new file mode 100644 index 000000000..2299d679e --- /dev/null +++ b/scripts/build.cfg.make-32bit @@ -0,0 +1,3 @@ +FLATCC_BUILD_GEN="Unix Makefiles" +FLATCC_BUILD_CMD=make +FLATCC_BUILD_FLAGS="-DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32" diff --git a/scripts/build.cfg.make-concurrent b/scripts/build.cfg.make-concurrent index 35d82f0ea..76846426b 100644 --- a/scripts/build.cfg.make-concurrent +++ b/scripts/build.cfg.make-concurrent @@ -1,2 +1,3 @@ FLATCC_BUILD_GEN="Unix Makefiles" FLATCC_BUILD_CMD="make -j" +FLATCC_BUILD_FLAGS="" diff --git a/scripts/build.cfg.ninja b/scripts/build.cfg.ninja index d69bb6d24..07ead7000 100644 --- a/scripts/build.cfg.ninja +++ b/scripts/build.cfg.ninja @@ -1,2 +1,3 @@ FLATCC_BUILD_GEN=Ninja FLATCC_BUILD_CMD=ninja +FLATCC_BUILD_FLAGS="" diff --git a/scripts/initbuild.sh b/scripts/initbuild.sh index 00561fa73..2b18cd257 100755 --- a/scripts/initbuild.sh +++ b/scripts/initbuild.sh @@ -36,5 +36,5 @@ mkdir -p ${ROOT}/build/Release rm -rf ${ROOT}/build/Debug/* rm -rf ${ROOT}/build/Release/* -cd ${ROOT}/build/Debug && cmake -G "$FLATCC_BUILD_GEN" ../.. -DCMAKE_BUILD_TYPE=Debug -cd ${ROOT}/build/Release && cmake -G "$FLATCC_BUILD_GEN" ../.. -DCMAKE_BUILD_TYPE=Release +cd ${ROOT}/build/Debug && cmake -G "$FLATCC_BUILD_GEN" $FLATCC_BUILD_FLAGS ../.. -DCMAKE_BUILD_TYPE=Debug +cd ${ROOT}/build/Release && cmake -G "$FLATCC_BUILD_GEN" $FLATCC_BUILD_FLAGS ../.. -DCMAKE_BUILD_TYPE=Release diff --git a/scripts/test.sh b/scripts/test.sh index 0728e1660..d87924b9e 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -36,7 +36,3 @@ else echo "DEBUG TEST PASSED" fi -if [ ! -e ${ROOT}/build/reflection_enabled ]; then - echo "(reflection disabled, skipping affected test and example)" -fi - diff --git a/src/compiler/codegen_c_json_parser.c b/src/compiler/codegen_c_json_parser.c index 29ebc85dd..307ce76f4 100644 --- a/src/compiler/codegen_c_json_parser.c +++ b/src/compiler/codegen_c_json_parser.c @@ -8,8 +8,6 @@ #include #endif -#include "flatcc/portable/pattributes.h" /* fallthrough */ - #define PRINTLN_SPMAX 64 static char println_spaces[PRINTLN_SPMAX]; @@ -1424,7 +1422,7 @@ static int gen_struct_parser(fb_output_t *out, fb_compound_type_t *ct) println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime);"); unindent(); println(out, "}"); println(out, ""); - println(out, "static inline int %s_parse_json_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, const char *buf, size_t bufsiz, int flags, const char *fid)", snt.text); + println(out, "static inline int %s_parse_json_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid)", snt.text); println(out, "{"); indent(); println(out, "return flatcc_json_parser_struct_as_root(B, ctx, buf, bufsiz, flags, fid, %s_parse_json_struct);", snt.text); @@ -1527,7 +1525,7 @@ static int gen_table_parser(fb_output_t *out, fb_compound_type_t *ct) println(out, "return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_runtime);"); unindent(); println(out, "}"); println(out, ""); - println(out, "static inline int %s_parse_json_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, const char *buf, size_t bufsiz, int flags, const char *fid)", snt.text); + println(out, "static inline int %s_parse_json_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid)", snt.text); println(out, "{"); indent(); println(out, "return flatcc_json_parser_table_as_root(B, ctx, buf, bufsiz, flags, fid, %s_parse_json_table);", snt.text); @@ -1661,7 +1659,7 @@ static int gen_root_table_parser(fb_output_t *out, fb_compound_type_t *ct) println(out, "static int %s_parse_json(flatcc_builder_t *B, flatcc_json_parser_t *ctx,", out->S->basename); indent(); indent(); - println(out, "const char *buf, size_t bufsiz, int flags)"); + println(out, "const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags)"); unindent(); unindent(); println(out, "{"); indent(); println(out, "flatcc_json_parser_t parser;"); @@ -1767,10 +1765,10 @@ static int gen_json_parser_prototypes(fb_output_t *out) println(out, "static int %s_parse_json(flatcc_builder_t *B, flatcc_json_parser_t *ctx,", out->S->basename); indent(); indent(); - println(out, "const char *buf, size_t bufsiz, int flags);"); + println(out, "const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags);"); unindent(); unindent(); println(out, ""); - fallthrough; + break; default: break; } diff --git a/src/compiler/codegen_c_json_printer.c b/src/compiler/codegen_c_json_printer.c index 2bdaba63d..efc4c3d14 100644 --- a/src/compiler/codegen_c_json_printer.c +++ b/src/compiler/codegen_c_json_printer.c @@ -6,8 +6,6 @@ #include #endif -#include "flatcc/portable/pattributes.h" /* fallthrough */ - static int gen_json_printer_pretext(fb_output_t *out) { fprintf(out->fp, @@ -583,7 +581,7 @@ static int gen_json_printer_prototypes(fb_output_t *out) fprintf(out->fp, "static int %s_print_json(flatcc_json_printer_t *ctx, const char *buf, size_t bufsiz);\n\n", out->S->basename); - fallthrough; + break; default: break; } diff --git a/src/compiler/codegen_c_reader.c b/src/compiler/codegen_c_reader.c index 67f8055bc..6de0f2166 100644 --- a/src/compiler/codegen_c_reader.c +++ b/src/compiler/codegen_c_reader.c @@ -1593,7 +1593,6 @@ static void gen_table(fb_output_t *out, fb_compound_type_t *ct) const char *nsc = out->nsc; fb_scoped_name_t snt; fb_scoped_name_t snref; - uint64_t present_id; fb_literal_t literal; int is_optional; @@ -1629,7 +1628,6 @@ static void gen_table(fb_output_t *out, fb_compound_type_t *ct) for (sym = ct->members; sym; sym = sym->link) { current_key_processed = 0; member = (fb_member_t *)sym; - present_id = member->id; is_primary_key = ct->primary_key == member; is_optional = !!(member->flags & fb_fm_optional); print_doc(out, "", member->doc); @@ -1807,7 +1805,6 @@ static void gen_table(fb_output_t *out, fb_compound_type_t *ct) } break; case fb_is_union: - present_id--; fprintf(out->fp, "__%sdefine_union_field(%s, %"PRIu64", %s, %.*s, %s, %u)\n", nsc, nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r); @@ -1833,7 +1830,6 @@ static void gen_table(fb_output_t *out, fb_compound_type_t *ct) break; } if (member->type.ct->symbol.kind == fb_is_union) { - present_id--; fprintf(out->fp, "__%sdefine_union_vector_field(%s, %"PRIu64", %s, %.*s, %s, %u)\n", nsc, nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r); diff --git a/src/compiler/codegen_schema.c b/src/compiler/codegen_schema.c index 0313d9ef8..d0c9fde3c 100644 --- a/src/compiler/codegen_schema.c +++ b/src/compiler/codegen_schema.c @@ -465,17 +465,15 @@ static void sort_objects(void *buffer) static FILE *open_file(fb_options_t *opts, fb_schema_t *S) { FILE *fp = 0; - char *path; + char *path = 0, *ext = 0; const char *prefix = opts->outpath ? opts->outpath : ""; size_t len, prefix_len = strlen(prefix); const char *name; - const char *ext; name = S->basename; len = strlen(name); - ext = flatbuffers_extension; - + ext = fb_create_path_ext(".", flatbuffers_extension); /* We generally should not use cgen options here, but in this case it makes sense. */ if (opts->gen_stdout) { return stdout; @@ -486,6 +484,7 @@ static FILE *open_file(fb_options_t *opts, fb_schema_t *S) fprintf(stderr, "error opening file for writing binary schema: %s\n", path); } free(path); + free(ext); return fp; } diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 250d6600d..006bb86f0 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -16,7 +16,6 @@ #include "codegen.h" #include "fileio.h" #include "pstrutil.h" -#include "flatcc/portable/pattributes.h" /* fallthrough */ #include "flatcc/portable/pparseint.h" void fb_default_error_out(void *err_ctx, const char *buf, size_t len) @@ -156,8 +155,6 @@ void error_ref_sym(fb_parser_t *P, fb_ref_t *ref, const char *msg, fb_symbol_t * /* Accept numbers like -0x42 as integer literals. */ #define LEX_HEX_NUMERIC -#define lex_isblank(c) ((c) == ' ' || (c) == '\t') - #include "parser.h" #ifdef LEX_DEBUG @@ -920,7 +917,7 @@ static void parse_enum_decl(fb_parser_t *P, fb_compound_type_t *ct) case tok_kw_float32: case tok_kw_float64: error_tok(P, ct->type.t, "integral type expected"); - fallthrough; + break; default: break; } @@ -1070,7 +1067,7 @@ static void parse_namespace(fb_parser_t *P) if (optional(P, ';') && t) { /* Revert to global namespace. */ - P->current_scope = 0; + P->current_scope = P->root_scope; return; } if (P->token->id != LEX_TOK_ID) { @@ -1273,7 +1270,6 @@ static void push_token(fb_parser_t *P, long id, const char *first, const char *l size_t offset; fb_token_t *t; - P->te = P->ts + P->tcapacity; if (P->token == P->te) { offset = (size_t)(P->token - P->ts); P->tcapacity = P->tcapacity ? 2 * P->tcapacity : 1024; @@ -1336,10 +1332,10 @@ static void inject_token(fb_token_t *t, const char *lex, long id) push_token((fb_parser_t*)context, LEX_TOK_COMMENT_UNTERMINATED, pos, pos) #define lex_emit_comment_ctrl(pos) \ - if (lex_isblank(*pos)) { \ + if (lex_isblank(*pos) || !lex_isctrl(*pos)) { \ push_comment((fb_parser_t*)context, pos, pos + 1); \ } else { \ - push_token((fb_parser_t*)context, LEX_TOK_COMMENT_CTRL, \ + push_token((fb_parser_t*)context, LEX_TOK_CTRL, \ pos, pos + 1); \ } @@ -1433,11 +1429,14 @@ int fb_init_parser(fb_parser_t *P, fb_options_t *opts, const char *name, P->schema.name.name.s.s = s; P->schema.name.name.s.len = (int)n; checkmem((P->schema.errorname = fb_create_basename(name, name_len, ""))); + P->schema.prefix.s = ""; + P->schema.prefix.len = 0; if (opts->ns) { P->schema.prefix.s = (char *)opts->ns; P->schema.prefix.len = (int)strlen(opts->ns); } - P->current_scope = fb_add_scope(P, 0); + P->root_scope = fb_add_scope(P, 0); + P->current_scope = P->root_scope; assert(P->current_scope == fb_scope_table_find(&P->schema.root_schema->scope_index, 0, 0)); return 0; } diff --git a/src/compiler/parser.h b/src/compiler/parser.h index ef2ecc15a..f09337fe2 100644 --- a/src/compiler/parser.h +++ b/src/compiler/parser.h @@ -71,6 +71,7 @@ struct fb_parser { int has_schema; fb_options_t opts; fb_schema_t schema; + fb_scope_t *root_scope; fb_scope_t *current_scope; char *path; char *referer_path; diff --git a/src/compiler/semantics.c b/src/compiler/semantics.c index a2866cf33..d0a766a61 100644 --- a/src/compiler/semantics.c +++ b/src/compiler/semantics.c @@ -11,8 +11,6 @@ #include #endif -#include "flatcc/portable/pattributes.h" /* fallthrough */ - /* Same order as enum! */ static const char *fb_known_attribute_names[] = { "", @@ -131,10 +129,11 @@ static inline void set_type_hash(fb_compound_type_t *ct) uint32_t hash; hash = fb_hash_fnv1a_32_init(); - if (ct->scope) - for (name = ct->scope->name; name; name = name->link) { - hash = fb_hash_fnv1a_32_append(hash, name->ident->text, (size_t)name->ident->len); - hash = fb_hash_fnv1a_32_append(hash, ".", 1); + if (ct->scope) { + for (name = ct->scope->name; name; name = name->link) { + hash = fb_hash_fnv1a_32_append(hash, name->ident->text, (size_t)name->ident->len); + hash = fb_hash_fnv1a_32_append(hash, ".", 1); + } } sym = &ct->symbol; hash = fb_hash_fnv1a_32_append(hash, sym->ident->text, (size_t)sym->ident->len); @@ -524,7 +523,6 @@ static int analyze_struct(fb_parser_t *P, fb_compound_type_t *ct) member = (fb_member_t *)sym; switch (member->type.type) { case vt_fixed_array_type: - /* fall through */ case vt_scalar_type: t = member->type.t; member->type.st = map_scalar_token_type(t); @@ -537,7 +535,6 @@ static int analyze_struct(fb_parser_t *P, fb_compound_type_t *ct) member->size = size * member->type.len; break; case vt_fixed_array_compound_type_ref: - /* fall through */ case vt_compound_type_ref: /* Enums might not be valid, but then it would be detected earlier. */ if (member->type.ct->symbol.kind == fb_is_enum) { @@ -617,7 +614,7 @@ static int analyze_struct(fb_parser_t *P, fb_compound_type_t *ct) } ct->symbol.flags |= fb_circular_closed; - ct->symbol.flags &= ~fb_circular_open; + ct->symbol.flags &= (uint16_t)~fb_circular_open; ct->order = P->schema.ordered_structs; P->schema.ordered_structs = ct; return ret; @@ -701,8 +698,9 @@ static int process_struct(fb_parser_t *P, fb_compound_type_t *ct) switch (member->type.type) { case vt_fixed_array_type_ref: key_ok = 0; - fallthrough; + goto lbl_type_ref; case vt_type_ref: +lbl_type_ref: type_sym = lookup_type_reference(P, ct->scope, member->type.ref); if (!type_sym) { error_ref_sym(P, member->type.ref, "unknown type reference used with struct field", sym); @@ -1146,7 +1144,9 @@ static int process_table(fb_parser_t *P, fb_compound_type_t *ct) member->type.type = vt_invalid; continue; } - if (P->opts.strict_enum_init && !(member->flags & fb_fm_optional)) { + /* Bitflags can have complex combinations of values, and do not nativele have a 0 value. */ + if (P->opts.strict_enum_init && !(member->type.ct->metadata_flags & fb_f_bit_flags) + && !(member->flags & fb_fm_optional)) { if (!is_in_value_set(&member->type.ct->value_set, &member->value)) { error_sym(P, sym, "initializer does not match a defined enum value"); member->type.type = vt_invalid; @@ -1164,6 +1164,7 @@ static int process_table(fb_parser_t *P, fb_compound_type_t *ct) continue; } if (P->opts.strict_enum_init) { + /* TODO: consider if this error is necessary for bit_flags - flatc 2.0.0 errors on this. */ if (!is_in_value_set(&member->type.ct->value_set, &member->value)) { error_sym_2(P, sym, "enum type requires an explicit initializer because it has no 0 value", type_sym); @@ -1545,7 +1546,7 @@ static int process_enum(fb_parser_t *P, fb_compound_type_t *ct) fb_symbol_t *sym, *old, *type_sym; fb_member_t *member; fb_metadata_t *knowns[KNOWN_ATTR_COUNT]; - fb_value_t index = { 0 }; + fb_value_t index = { { { 0 } }, 0, 0 }; fb_value_t old_index; int first = 1; int bit_flags = 0; diff --git a/src/runtime/builder.c b/src/runtime/builder.c index 9f54d884f..961bd2208 100644 --- a/src/runtime/builder.c +++ b/src/runtime/builder.c @@ -177,7 +177,7 @@ int flatcc_builder_default_alloc(void *alloc_context, iovec_t *b, size_t request return 0; } -#define T_ptr(base, pos) ((void *)((uint8_t *)(base) + (uoffset_t)(pos))) +#define T_ptr(base, pos) ((void *)((size_t)(base) + (size_t)(pos))) #define ds_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_ds].iov_base, (pos))) #define vs_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_vs].iov_base, (pos))) #define pl_ptr(pos) (T_ptr(B->buffers[flatcc_builder_alloc_pl].iov_base, (pos))) @@ -698,7 +698,8 @@ static inline flatcc_builder_ref_t emit_back(flatcc_builder_t *B, iov_state_t *i return ref + 1; } -static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_align, int is_nested) +/* If nested we cannot pad the end of the buffer without moving the entire buffer, so we don't. */ +static int align_buffer_end(flatcc_builder_t *B, uint16_t *align, uint16_t block_align, int is_nested) { size_t end_pad; iov_state_t iov; @@ -708,7 +709,7 @@ static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_a get_min_align(align, block_align); /* Pad end of buffer to multiple. */ if (!is_nested) { - end_pad = back_pad(B, block_align); + end_pad = back_pad(B, *align); if (end_pad) { init_iov(); push_iov(_pad, end_pad); @@ -723,13 +724,13 @@ static int align_to_block(flatcc_builder_t *B, uint16_t *align, uint16_t block_a flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B, uint16_t block_align, - const void *data, size_t size, uint16_t align, int flags) + const void *data, size_t size, uint16_t align, flatcc_builder_buffer_flags_t flags) { uoffset_t size_field, pad; iov_state_t iov; - int with_size = flags & flatcc_builder_with_size; + int with_size = (flags & flatcc_builder_with_size) != 0; - if (align_to_block(B, &align, block_align, !is_top_buffer(B))) { + if (align_buffer_end(B, &align, block_align, !is_top_buffer(B))) { return 0; } pad = front_pad(B, (uoffset_t)(size + (with_size ? field_size : 0)), align); @@ -744,7 +745,7 @@ flatcc_builder_ref_t flatcc_builder_embed_buffer(flatcc_builder_t *B, flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B, const char identifier[identifier_size], uint16_t block_align, - flatcc_builder_ref_t object_ref, uint16_t align, int flags) + flatcc_builder_ref_t object_ref, uint16_t align, flatcc_builder_buffer_flags_t flags) { flatcc_builder_ref_t buffer_ref; uoffset_t header_pad, id_size = 0; @@ -754,7 +755,7 @@ flatcc_builder_ref_t flatcc_builder_create_buffer(flatcc_builder_t *B, int is_nested = (flags & flatcc_builder_is_nested) != 0; int with_size = (flags & flatcc_builder_with_size) != 0; - if (align_to_block(B, &align, block_align, is_nested)) { + if (align_buffer_end(B, &align, block_align, is_nested)) { return 0; } set_min_align(B, align); @@ -808,7 +809,7 @@ flatcc_builder_ref_t flatcc_builder_create_struct(flatcc_builder_t *B, const voi } int flatcc_builder_start_buffer(flatcc_builder_t *B, - const char identifier[identifier_size], uint16_t block_align, int flags) + const char identifier[identifier_size], uint16_t block_align, flatcc_builder_buffer_flags_t flags) { /* * This saves the parent `min_align` in the align field since we @@ -820,7 +821,11 @@ int flatcc_builder_start_buffer(flatcc_builder_t *B, return -1; } /* B->align now has parent min_align, and child frames will save it. */ - B->min_align = 1; + /* Since we allow objects to be created before the buffer at top level, + we need to respect min_align in that case. */ + if (!is_top_buffer(B) || B->min_align == 0) { + B->min_align = 1; + } /* Save the parent block align, and set proper defaults for this buffer. */ frame(container.buffer.block_align) = B->block_align; B->block_align = block_align; @@ -845,9 +850,9 @@ int flatcc_builder_start_buffer(flatcc_builder_t *B, flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_builder_ref_t root) { flatcc_builder_ref_t buffer_ref; - int flags; + flatcc_builder_buffer_flags_t flags; - flags = B->buffer_flags & flatcc_builder_with_size; + flags = (flatcc_builder_buffer_flags_t)B->buffer_flags & flatcc_builder_with_size; flags |= is_top_buffer(B) ? 0 : flatcc_builder_is_nested; check(frame(type) == flatcc_builder_buffer, "expected buffer frame"); set_min_align(B, B->block_align); @@ -859,6 +864,8 @@ flatcc_builder_ref_t flatcc_builder_end_buffer(flatcc_builder_t *B, flatcc_build B->nest_id = frame(container.buffer.nest_id); B->identifier = frame(container.buffer.identifier); B->buffer_flags = frame(container.buffer.flags); + B->block_align = frame(container.buffer.block_align); + exit_frame(B); return buffer_ref; } @@ -1327,6 +1334,7 @@ flatcc_builder_ref_t flatcc_builder_end_table(flatcc_builder_t *B) flatcc_builder_ref_t table_ref, vt_ref; int pl_count; voffset_t *pl; + size_t tsize; check(frame(type) == flatcc_builder_table, "expected table frame"); @@ -1341,7 +1349,14 @@ flatcc_builder_ref_t flatcc_builder_end_table(flatcc_builder_t *B) * initial vtable offset field. Therefore `field_size` is added here * to the total table size in the vtable. */ - vt[1] = (voffset_t)(B->ds_offset + field_size); + tsize = (size_t)(B->ds_offset + field_size); + /* + * Tables are limited to 64K in standard FlatBuffers format due to the voffset + * 16 bit size, but we must also be able to store the table size, so the + * table payload has to be slightly less than that. + */ + check(tsize <= FLATBUFFERS_VOFFSET_MAX, "table too large"); + vt[1] = (voffset_t)tsize; FLATCC_BUILDER_UPDATE_VT_HASH(B->vt_hash, (uint32_t)vt[0], (uint32_t)vt[1]); /* Find already emitted vtable, or emit a new one. */ if (!(vt_ref = flatcc_builder_create_cached_vtable(B, vt, vt_size, B->vt_hash))) { diff --git a/src/runtime/json_parser.c b/src/runtime/json_parser.c index 313bd8085..4472af2d8 100644 --- a/src/runtime/json_parser.c +++ b/src/runtime/json_parser.c @@ -141,11 +141,10 @@ const char *flatcc_json_parser_space_ext(flatcc_json_parser_t *ctx, const char * ++buf; } while (buf != end && *buf <= 0x20) { - /* Fall through comments needed to silence gcc 7 warnings. */ switch (*buf) { case 0x0d: buf += (end - buf > 1 && buf[1] == 0x0a); /* Consume following LF or treating CR as LF. */ - fallthrough; + ++ctx->line; ctx->line_start = ++buf; continue; case 0x0a: ++ctx->line; ctx->line_start = ++buf; continue; case 0x09: ++buf; continue; case 0x20: goto again; /* Don't consume here, sync with power of 2 spaces. */ @@ -259,7 +258,7 @@ static inline int decode_utf16_surrogate_pair(uint32_t high, uint32_t low, char } -/* +/* * UTF-8 code points can have up to 4 bytes but JSON can only * encode up to 3 bytes via the \uXXXX syntax. * To handle the range U+10000..U+10FFFF two UTF-16 surrogate @@ -329,7 +328,7 @@ const char *flatcc_json_parser_string_escape(flatcc_json_parser_t *ctx, const ch return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); }; /* If a high UTF-16 surrogate half pair was detected */ - if (u >= 0xd800 && u <= 0xdbff && + if (u >= 0xd800 && u <= 0xdbff && /* and there is space for a matching low half pair */ end - buf >= 12 && /* and there is a second escape following immediately */ @@ -344,7 +343,7 @@ const char *flatcc_json_parser_string_escape(flatcc_json_parser_t *ctx, const ch return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); } return buf + 12; - /* + /* * Otherwise decode unmatched surrogate pairs as is any * other UTF-8. Some systems might depend on these surviving. * Leave ignored errors for the next parse step. @@ -489,7 +488,7 @@ const char *flatcc_json_parser_match_constant(flatcc_json_parser_t *ctx, const c *more = 0; return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_invalid_escape); case '\"': - buf = flatcc_json_parser_space(ctx, buf + 1, 0); + buf = flatcc_json_parser_space(ctx, buf + 1, end); *more = 0; return buf; } @@ -855,7 +854,7 @@ const char *flatcc_json_parser_char_array(flatcc_json_parser_t *ctx, if (k > n) { if (!(ctx->flags & flatcc_json_parser_f_skip_array_overflow)) { return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_overflow); - } + } k = n; /* Might truncate UTF-8. */ } memcpy(s, mark, k); @@ -869,7 +868,7 @@ const char *flatcc_json_parser_char_array(flatcc_json_parser_t *ctx, if (k > n) { if (!(ctx->flags & flatcc_json_parser_f_skip_array_overflow)) { return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_overflow); - } + } k = n; /* Might truncate UTF-8. */ } memcpy(s, mark, k); @@ -880,7 +879,7 @@ const char *flatcc_json_parser_char_array(flatcc_json_parser_t *ctx, if (ctx->flags & flatcc_json_parser_f_reject_array_underflow) { return flatcc_json_parser_set_error(ctx, buf, end, flatcc_json_parser_error_array_underflow); } - memset(s, 0, n - k); + memset(s, 0, n); } return flatcc_json_parser_string_end(ctx, buf, end); } @@ -1258,12 +1257,12 @@ const char *flatcc_json_parser_union_type_vector(flatcc_json_parser_t *ctx, } int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_table_f *parser) { flatcc_json_parser_t _ctx; flatcc_builder_ref_t root; - int builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; + flatcc_builder_buffer_flags_t builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; ctx = ctx ? ctx : &_ctx; flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags); @@ -1278,12 +1277,12 @@ int flatcc_json_parser_table_as_root(flatcc_builder_t *B, flatcc_json_parser_t * } int flatcc_json_parser_struct_as_root(flatcc_builder_t *B, flatcc_json_parser_t *ctx, - const char *buf, size_t bufsiz, int flags, const char *fid, + const char *buf, size_t bufsiz, flatcc_json_parser_flags_t flags, const char *fid, flatcc_json_parser_table_f *parser) { flatcc_json_parser_t _ctx; flatcc_builder_ref_t root; - int builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; + flatcc_builder_buffer_flags_t builder_flags = flags & flatcc_json_parser_f_with_size ? flatcc_builder_with_size : 0; ctx = ctx ? ctx : &_ctx; flatcc_json_parser_init(ctx, B, buf, buf + bufsiz, flags); diff --git a/src/runtime/verifier.c b/src/runtime/verifier.c index 1831fcf6b..9c43bf613 100644 --- a/src/runtime/verifier.c +++ b/src/runtime/verifier.c @@ -265,7 +265,7 @@ static inline int verify_string(const void *buf, uoffset_t end, uoffset_t base, base += offset; n = read_uoffset(buf, base); base += offset_size; - verify(end - base >= n + 1, flatcc_verify_error_string_out_of_range); + verify(end - base > n, flatcc_verify_error_string_out_of_range); verify(((uint8_t *)buf + base)[n] == 0, flatcc_verify_error_string_not_zero_terminated); return flatcc_verify_ok; } diff --git a/test/cgen_test/cgen_test.c b/test/cgen_test/cgen_test.c index 94f4bba9b..6d58ed1a9 100644 --- a/test/cgen_test/cgen_test.c +++ b/test/cgen_test/cgen_test.c @@ -41,7 +41,7 @@ #include #include "flatcc/flatcc.h" -int main() +int main(void) { const char *name = "../xyzzy.fbs"; diff --git a/test/emit_test/emit_test.c b/test/emit_test/emit_test.c index fa18034ac..a271a3159 100644 --- a/test/emit_test/emit_test.c +++ b/test/emit_test/emit_test.c @@ -2,8 +2,13 @@ #include #include "emit_test_builder.h" #include "flatcc/support/hexdump.h" +#include "flatcc/portable/pparsefp.h" #define test_assert(x) do { if (!(x)) { assert(0); return -1; }} while(0) +/* Direct floating point comparisons are not always directly comparable, + * especially not for GCC 32-bit compilers. */ +#define test_assert_floateq(x, y) test_assert(parse_float_is_equal((x), (y))) +#define test_assert_doubleeq(x, y) test_assert(parse_double_is_equal((x), (y))) int dbg_emitter(void *emit_context, const flatcc_iovec_t *iov, int iov_count, @@ -61,13 +66,13 @@ int emit_test(void) "\x04\x00\x00\x00\xd4\xff\xff\xff\x2a\x00\x00\x00\x00\x00\x00\x00" "\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00" "\x00\x00\x80\x3f\xcd\xcc\x8c\x3f\x9a\x99\x99\x3f\x66\x66\xa6\x3f" - "\x0a\x00\x11\x00\x04\x00\x10\x00\x0c\x00"; + "\x0a\x00\x11\x00\x04\x00\x10\x00\x0c\x00\x00\x00"; #else "\x00\x00\x00\x04\xff\xff\xff\xd4\x00\x00\x00\x00\x00\x00\x00\x2a" "\x00\x00\x00\x0c\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04" "\x3f\x80\x00\x00\x3f\x8c\xcc\xcd\x3f\x99\x99\x9a\x3f\xa6\x66\x66" - "\x00\x0a\x00\x11\x00\x04\x00\x10\x00\x0c"; + "\x00\x0a\x00\x11\x00\x04\x00\x10\x00\x0c\x00\x00"; #endif size_t size; @@ -103,7 +108,8 @@ int emit_test(void) fprintf(stderr, "buffer size: %d\n", (int)size); hexdump("emit_test", buf, size, stderr); - test_assert(size == 58); + /* 58 without tail padding, 60 with padding to 4 byte alignment. */ + test_assert(size == 60); test_assert(sizeof(expect) - 1 == size); test_assert(0 == memcmp(buf, expect, size)); @@ -112,7 +118,7 @@ int emit_test(void) test_assert(time == 42); test_assert(main_device(mt) == 1); test_assert(flatbuffers_float_vec_len(main_samples(mt)) == 4); - test_assert(flatbuffers_float_vec_at(main_samples(mt), 2) == 1.2f); + test_assert_floateq(flatbuffers_float_vec_at(main_samples(mt), 2), 1.2f); /* We use get_direct_buffer, so we can't clear the builder until last. */ flatcc_builder_clear(B); diff --git a/test/json_test/test_basic_parse.c b/test/json_test/test_basic_parse.c index de27ee775..7b8f4bac9 100644 --- a/test/json_test/test_basic_parse.c +++ b/test/json_test/test_basic_parse.c @@ -277,7 +277,7 @@ const char *test(flatcc_builder_t *B, const char *buf, const char *end, int *ret return buf; } -int main() +int main(void) { int ret = -1; flatcc_builder_t builder; diff --git a/test/json_test/test_json.c b/test/json_test/test_json.c index 6d6698b80..aeee13a04 100644 --- a/test/json_test/test_json.c +++ b/test/json_test/test_json.c @@ -47,7 +47,7 @@ static const struct test_scope Movie = { int test_json(const struct test_scope *scope, char *json, char *expect, int expect_err, - int parse_flags, int print_flags, int line) + flatcc_json_parser_flags_t parse_flags, flatcc_json_printer_flags_t print_flags, int line) { int ret = -1; int err; @@ -582,7 +582,7 @@ int fixed_array_tests(void) * covered in the printer and parser tests using the golden data * set. */ -int main() +int main(void) { BEGIN_TEST(Monster); diff --git a/test/json_test/test_json_parser.c b/test/json_test/test_json_parser.c index de2b738b2..a985cfab5 100644 --- a/test/json_test/test_json_parser.c +++ b/test/json_test/test_json_parser.c @@ -80,7 +80,7 @@ int test_parse(void) flatcc_builder_t builder; flatcc_builder_t *B = &builder; int ret = -1; - int flags = 0; + flatcc_json_parser_flags_t flags = 0; flatcc_builder_init(B); diff --git a/test/monster_test/monster_test.c b/test/monster_test/monster_test.c index 400415c5d..f3150d8e3 100644 --- a/test/monster_test/monster_test.c +++ b/test/monster_test/monster_test.c @@ -5,6 +5,7 @@ #include "flatcc/support/hexdump.h" #include "flatcc/support/elapsed.h" +#include "flatcc/portable/pparsefp.h" #include "../../config/config.h" /* @@ -162,8 +163,8 @@ int test_type_aliases(flatcc_builder_t *B) if (ns(TypeAliases_u16(ta)) != UINT16_MAX) goto failed; if (ns(TypeAliases_u32(ta)) != UINT32_MAX) goto failed; if (ns(TypeAliases_u64(ta)) != UINT64_MAX) goto failed; - if (ns(TypeAliases_f32(ta)) != 2.3f) goto failed; - if (ns(TypeAliases_f64(ta)) != 2.3) goto failed; + if (!parse_float_is_equal(ns(TypeAliases_f32(ta)), 2.3f)) goto failed; + if (!parse_double_is_equal(ns(TypeAliases_f64(ta)), 2.3)) goto failed; if (sizeof(ns(TypeAliases_i8(ta))) != 1) goto failed; if (sizeof(ns(TypeAliases_i16(ta))) != 2) goto failed; if (sizeof(ns(TypeAliases_i32(ta))) != 4) goto failed; @@ -371,13 +372,17 @@ int verify_monster(void *buffer) if ((size_t)vec & 15) { printf("Force align of Vec3 struct not correct\n"); } - /* -3.2f is actually -3.20000005 and not -3.2 due to representation loss. */ - if (ns(Vec3_z(vec)) != -3.2f) { + /* -3.2f is actually -3.20000005 and not -3.2 due to representation loss. + * For 32-bit GCC compilers, -3.2f might be another value, so use lower + * precision portable comparison. */ + if (!parse_float_is_equal(ns(Vec3_z(vec)), -3.2f)) { printf("Position failing on z coordinate\n"); return -1; } if (nsc(is_native_pe())) { - if (vec->x != 1.0f || vec->y != 2.0f || vec->z != -3.2f) { + if (!parse_float_is_equal(vec->x, 1.0f) || + !parse_float_is_equal(vec->y, 2.0f) || + !parse_float_is_equal(vec->z, -3.2f)) { printf("Position is incorrect\n"); return -1; } @@ -396,7 +401,9 @@ int verify_monster(void *buffer) */ ns(Vec3_clear(&v)); /* Not strictly needed here. */ ns(Vec3_copy_from_pe(&v, vec)); - if (v.x != 1.0f || v.y != 2.0f || v.z != -3.2f) { + if (!parse_float_is_equal(v.x, 1.0f) || + !parse_float_is_equal(v.y, 2.0f) || + !parse_float_is_equal(v.z, -3.2f)) { printf("Position is incorrect after copy\n"); return -1; } @@ -1601,7 +1608,7 @@ int test_clone_slice(flatcc_builder_t *B) printf("sliced bool has wrong content\n"); goto done; } - if (ns(Monster_pos(mon2)->x != -42.3f)) { + if (!parse_float_is_equal(ns(Monster_pos(mon2))->x, -42.3f)) { printf("cloned pos struct failed\n"); goto done; }; @@ -2561,8 +2568,8 @@ int test_struct_buffer(flatcc_builder_t *B) /* Convert buffer to native in place - a nop on native platform. */ v = (ns(Vec3_t) *)vec3; ns(Vec3_from_pe(v)); - if (v->x != 1.0f || v->y != 2.0f || v->z != 3.0f - || v->test1 != 4.2 || v->test2 != ns(Color_Blue) + if (!parse_float_is_equal(v->x, 1.0f) || !parse_float_is_equal(v->y, 2.0f) || !parse_float_is_equal(v->z, 3.0f) + || !parse_double_is_equal(v->test1, 4.2) || v->test2 != ns(Color_Blue) || v->test3.a != 2730 || v->test3.b != -17 ) { printf("struct buffer not valid\n"); @@ -2626,8 +2633,8 @@ int test_typed_struct_buffer(flatcc_builder_t *B) /* Convert buffer to native in place - a nop on native platform. */ v = (ns(Vec3_t) *)vec3; ns(Vec3_from_pe(v)); - if (v->x != 1.0f || v->y != 2.0f || v->z != 3.0f - || v->test1 != 4.2 || v->test2 != ns(Color_Blue) + if (!parse_float_is_equal(v->x, 1.0f) || !parse_float_is_equal(v->y, 2.0f) || !parse_float_is_equal(v->z, 3.0f) + || !parse_double_is_equal(v->test1, 4.2) || v->test2 != ns(Color_Blue) || v->test3.a != 2730 || v->test3.b != -17 ) { printf("struct buffer not valid\n"); diff --git a/test/test.sh b/test/test.sh index 40dc31699..d4fae6fc9 100755 --- a/test/test.sh +++ b/test/test.sh @@ -83,13 +83,13 @@ $CC -O3 -DNDEBUG -DFLATBUFFERS_BENCHMARK -I ${ROOT}/include monster_test.c \ echo "running optimized version of main monster test" ./monster_test -if [ -e ${ROOT}/build/reflection_enabled ]; then - echo "running reflection test" - ${ROOT}/test/reflection_test//reflection_test.sh +# This may fail if reflection feature is disabled +echo "running reflection test" +${ROOT}/test/reflection_test/reflection_test.sh - echo "running reflection sample" - ${ROOT}/samples/reflection/build.sh -fi +# This may fail if reflection feature is disabled +echo "running reflection sample" +${ROOT}/samples/reflection/build.sh echo "running monster sample" ${ROOT}/samples/monster/build.sh @@ -101,6 +101,3 @@ echo "running load test with large buffer" ${ROOT}/test/load_test/load_test.sh echo "TEST PASSED" -if [ ! -e ${ROOT}/build/reflection_enabled ]; then - echo "(reflection disabled, skipping affected test and example)" -fi