diff options
author | leonidlazarev <leonidlazarev@yandex-team.com> | 2023-06-02 15:07:38 +0300 |
---|---|---|
committer | leonidlazarev <leonidlazarev@yandex-team.com> | 2023-06-02 15:07:38 +0300 |
commit | 59e0045a61e61c2ac38878f2adc7ec91ca914cc1 (patch) | |
tree | b6b64c51025630a7d40923d4aa7b7b882e1a8848 /contrib/libs/grpc/third_party | |
parent | 7506c5c295065b4360d617393af34203f037946d (diff) | |
download | ydb-59e0045a61e61c2ac38878f2adc7ec91ca914cc1.tar.gz |
feat grpc: update to grpc 1.50.2
update grpc to 1.50.2
update grpcio to 1.50.0
Удаленные патчи:
06-flow_control.patch - логика в upstream удалена
10-fix-crash-on-fork.patch - логика в upstream удалена
12-coverity-fix.patch - логика в upstream удалена
20-P2166-string-nullptr.patch - в upstream временный объект вместо nullptr
PR29209-fix-heap-use-after-free.patch - решение есть в upstream
Добавленные патчи:
pr33085_fix_epoll1_engine_reinit.patch
21-windows_build.patch
Diffstat (limited to 'contrib/libs/grpc/third_party')
47 files changed, 5715 insertions, 1104 deletions
diff --git a/contrib/libs/grpc/third_party/README.md b/contrib/libs/grpc/third_party/README.md index 19ab6d424e..4425c05620 100644 --- a/contrib/libs/grpc/third_party/README.md +++ b/contrib/libs/grpc/third_party/README.md @@ -118,13 +118,18 @@ Apart from the above steps, please perform the following two steps to generate t Since upb is vendored in the gRPC repo, you cannot use submodule to update it. Please follow the steps below. 1. Update third_party/upb directory by running - `git subtree pull --squash --prefix=third_party/upb https://github.com/protocolbuffers/upb.git master` + - `export GRPC_ROOT=~/git/grpc` + - `wget https://github.com/protocolbuffers/upb/archive/refs/heads/main.zip` + - `rm -rf $GRPC_ROOT/third_party/upb` + - `unzip main.zip -d $GRPC_ROOT/third_party` + - `mv $GRPC_ROOT/third_party/upb-main $GRPC_ROOT/third_party/upb` 2. Update the dependency in `grpc_deps.bzl` to the same commit 3. Populate the bazel download mirror by running `bazel/update_mirror.sh` 4. Update `src/upb/gen_build_yaml.py` for newly added or removed upb files + - Running `bazel query "deps(upb) union deps(json) union deps(textformat)"` + under third_party/upb would give some idea on what needs to be included. 5. Run `tools/buildgen/generate_projects.sh` to regenerate the generated files 6. Run `tools/codegen/core/gen_upb_api.sh` to regenerate upb files. - If you see breaking changes here, you may want to import upb into Google3 along with gRPC. ### Updating third_party/xxhash diff --git a/contrib/libs/grpc/third_party/upb/CMakeLists.darwin-x86_64.txt b/contrib/libs/grpc/third_party/upb/CMakeLists.darwin-x86_64.txt index 95e91287c1..f371cc9d39 100644 --- a/contrib/libs/grpc/third_party/upb/CMakeLists.darwin-x86_64.txt +++ b/contrib/libs/grpc/third_party/upb/CMakeLists.darwin-x86_64.txt @@ -25,12 +25,20 @@ target_sources(grpc-third_party-upb PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/naive.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-neon.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-sse.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/arena.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/array.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode_fast.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/def.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/extension_registry.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_decode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/map.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/mini_table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/msg.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/reflection.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/status.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/text_encode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/upb.c diff --git a/contrib/libs/grpc/third_party/upb/CMakeLists.linux-aarch64.txt b/contrib/libs/grpc/third_party/upb/CMakeLists.linux-aarch64.txt index a0963907a3..2949b633aa 100644 --- a/contrib/libs/grpc/third_party/upb/CMakeLists.linux-aarch64.txt +++ b/contrib/libs/grpc/third_party/upb/CMakeLists.linux-aarch64.txt @@ -28,12 +28,20 @@ target_sources(grpc-third_party-upb PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/naive.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-neon.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-sse.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/arena.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/array.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode_fast.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/def.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/extension_registry.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_decode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/map.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/mini_table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/msg.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/reflection.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/status.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/text_encode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/upb.c diff --git a/contrib/libs/grpc/third_party/upb/CMakeLists.linux-x86_64.txt b/contrib/libs/grpc/third_party/upb/CMakeLists.linux-x86_64.txt index a0963907a3..2949b633aa 100644 --- a/contrib/libs/grpc/third_party/upb/CMakeLists.linux-x86_64.txt +++ b/contrib/libs/grpc/third_party/upb/CMakeLists.linux-x86_64.txt @@ -28,12 +28,20 @@ target_sources(grpc-third_party-upb PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/naive.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-neon.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-sse.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/arena.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/array.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode_fast.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/def.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/extension_registry.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_decode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/map.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/mini_table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/msg.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/reflection.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/status.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/text_encode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/upb.c diff --git a/contrib/libs/grpc/third_party/upb/CMakeLists.windows-x86_64.txt b/contrib/libs/grpc/third_party/upb/CMakeLists.windows-x86_64.txt index f9d6d5f4dd..0178cbffda 100644 --- a/contrib/libs/grpc/third_party/upb/CMakeLists.windows-x86_64.txt +++ b/contrib/libs/grpc/third_party/upb/CMakeLists.windows-x86_64.txt @@ -24,12 +24,20 @@ target_sources(grpc-third_party-upb PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/naive.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-neon.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/third_party/utf8_range/range2-sse.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/arena.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/array.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/decode_fast.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/def.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/extension_registry.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_decode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/json_encode.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/map.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/mini_table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/msg.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/reflection.c + ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/status.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/table.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/text_encode.c ${CMAKE_SOURCE_DIR}/contrib/libs/grpc/third_party/upb/upb/upb.c diff --git a/contrib/libs/grpc/third_party/upb/DESIGN.md b/contrib/libs/grpc/third_party/upb/DESIGN.md index 73388d037a..aa6a288280 100644 --- a/contrib/libs/grpc/third_party/upb/DESIGN.md +++ b/contrib/libs/grpc/third_party/upb/DESIGN.md @@ -68,7 +68,7 @@ typedef struct { Note in particular that messages do *not* have: - A pointer to reflection or a parse table (upb messages are not self-describing). -- A pointer to an arena (the arena must be expicitly passed into any function that +- A pointer to an arena (the arena must be explicitly passed into any function that allocates). The upb compiler computes a layout for each message, and determines the offset for @@ -160,7 +160,7 @@ together. together, their lifetimes are irreversibly joined, such that none of the arena blocks in either arena will be freed until *both* arenas are freed with `upb_arena_free()`. This is useful when joining two messages from separate -arenas (making one a sub-message of the other). Fuse is an a very cheap +arenas (making one a sub-message of the other). Fuse is a very cheap operation, and an unlimited number of arenas can be fused together efficiently. ## Reflection and Descriptors diff --git a/contrib/libs/grpc/third_party/upb/README.md b/contrib/libs/grpc/third_party/upb/README.md index 92a081bbef..9b74b969ce 100644 --- a/contrib/libs/grpc/third_party/upb/README.md +++ b/contrib/libs/grpc/third_party/upb/README.md @@ -57,6 +57,22 @@ For PHP, use [PECL](https://pecl.php.net/package/protobuf): $ sudo pecl install protobuf ``` +Alternatively, you can build and install upb using +[vcpkg](https://github.com/microsoft/vcpkg/) dependency manager: + + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + ./bootstrap-vcpkg.sh + ./vcpkg integrate install + ./vcpkg install upb + +The upb port in vcpkg is kept up to date by microsoft team members and community +contributors. + +If the version is out of date, please +[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the +vcpkg repository. + ## Contributing Please see [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/contrib/libs/grpc/third_party/upb/upb/arena.c b/contrib/libs/grpc/third_party/upb/upb/arena.c new file mode 100644 index 0000000000..3c872698cd --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/arena.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/arena.h" + +#include <stdlib.h> + +#include "upb/internal/upb.h" + +// Must be last. +#include "upb/port_def.inc" + +/* upb_alloc ******************************************************************/ + +static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); + } +} + +static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { + return (uint32_t*)(cleanup_metadata & ~0x1); +} + +static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { + return cleanup_metadata & 0x1; +} + +static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, + bool has_initial_block) { + return (uintptr_t)cleanup | has_initial_block; +} + +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + +/* upb_Arena ******************************************************************/ + +struct mem_block { + struct mem_block* next; + uint32_t size; + uint32_t cleanups; + /* Data follows. */ +}; + +typedef struct cleanup_ent { + upb_CleanupFunc* cleanup; + void* ud; +} cleanup_ent; + +static const size_t memblock_reserve = + UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN); + +static upb_Arena* arena_findroot(upb_Arena* a) { + /* Path splitting keeps time complexity down, see: + * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ + while (a->parent != a) { + upb_Arena* next = a->parent; + a->parent = next->parent; + a = next; + } + return a; +} + +static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, + size_t size) { + mem_block* block = ptr; + + /* The block is for arena |a|, but should appear in the freelist of |root|. */ + block->next = root->freelist; + block->size = (uint32_t)size; + block->cleanups = 0; + root->freelist = block; + a->last_size = block->size; + if (!root->freelist_tail) root->freelist_tail = block; + + a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); + a->head.end = UPB_PTR_AT(block, size, char); + a->cleanup_metadata = upb_cleanup_metadata( + &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); + + UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); +} + +static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { + upb_Arena* root = arena_findroot(a); + size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; + mem_block* block = upb_malloc(root->block_alloc, block_size); + + if (!block) return false; + upb_Arena_addblock(a, root, block, block_size); + return true; +} + +void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { + if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= size); + return upb_Arena_Malloc(a, size); +} + +static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ + return upb_Arena_Realloc(a, ptr, oldsize, size); +} + +/* Public Arena API ***********************************************************/ + +upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { + const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; + upb_Arena* a; + + /* We need to malloc the initial block. */ + n = first_block_overhead + 256; + if (!alloc || !(mem = upb_malloc(alloc, n))) { + return NULL; + } + + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + n -= sizeof(*a); + + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->freelist = NULL; + a->freelist_tail = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, false); + + upb_Arena_addblock(a, a, mem, n); + + return a; +} + +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { + upb_Arena* a; + + if (n) { + /* Align initial pointer up so that we return properly-aligned pointers. */ + void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN); + size_t delta = (uintptr_t)aligned - (uintptr_t)mem; + n = delta <= n ? n - delta : 0; + mem = aligned; + } + + /* Round block size down to alignof(*a) since we will allocate the arena + * itself at the end. */ + n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); + + if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { + return arena_initslow(mem, n, alloc); + } + + a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); + + a->head.alloc.func = &upb_Arena_doalloc; + a->block_alloc = alloc; + a->parent = a; + a->refcount = 1; + a->last_size = UPB_MAX(128, n); + a->head.ptr = mem; + a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); + a->freelist = NULL; + a->cleanup_metadata = upb_cleanup_metadata(NULL, true); + + return a; +} + +static void arena_dofree(upb_Arena* a) { + mem_block* block = a->freelist; + UPB_ASSERT(a->parent == a); + UPB_ASSERT(a->refcount == 0); + + while (block) { + /* Load first since we are deleting block. */ + mem_block* next = block->next; + + if (block->cleanups > 0) { + cleanup_ent* end = UPB_PTR_AT(block, block->size, void); + cleanup_ent* ptr = end - block->cleanups; + + for (; ptr < end; ptr++) { + ptr->cleanup(ptr->ud); + } + } + + upb_free(a->block_alloc, block); + block = next; + } +} + +void upb_Arena_Free(upb_Arena* a) { + a = arena_findroot(a); + if (--a->refcount == 0) arena_dofree(a); +} + +bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { + cleanup_ent* ent; + uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); + + if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { + if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ + UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); + cleanups = upb_cleanup_pointer(a->cleanup_metadata); + } + + a->head.end -= sizeof(cleanup_ent); + ent = (cleanup_ent*)a->head.end; + (*cleanups)++; + UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); + + ent->cleanup = func; + ent->ud = ud; + + return true; +} + +bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { + upb_Arena* r1 = arena_findroot(a1); + upb_Arena* r2 = arena_findroot(a2); + + if (r1 == r2) return true; /* Already fused. */ + + /* Do not fuse initial blocks since we cannot lifetime extend them. */ + if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; + if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; + + /* Only allow fuse with a common allocator */ + if (r1->block_alloc != r2->block_alloc) return false; + + /* We want to join the smaller tree to the larger tree. + * So swap first if they are backwards. */ + if (r1->refcount < r2->refcount) { + upb_Arena* tmp = r1; + r1 = r2; + r2 = tmp; + } + + /* r1 takes over r2's freelist and refcount. */ + r1->refcount += r2->refcount; + if (r2->freelist_tail) { + UPB_ASSERT(r2->freelist_tail->next == NULL); + r2->freelist_tail->next = r1->freelist; + r1->freelist = r2->freelist; + } + r2->parent = r1; + return true; +} diff --git a/contrib/libs/grpc/third_party/upb/upb/arena.h b/contrib/libs/grpc/third_party/upb/upb/arena.h new file mode 100644 index 0000000000..0c4fd1b83c --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/arena.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_ARENA_H_ +#define UPB_ARENA_H_ + +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +/** upb_alloc *****************************************************************/ + +/* A upb_alloc is a possibly-stateful allocator object. + * + * It could either be an arena allocator (which doesn't require individual + * free() calls) or a regular malloc() (which does). The client must therefore + * free memory unless it knows that the allocator is an arena allocator. */ + +struct upb_alloc; +typedef struct upb_alloc upb_alloc; + +/* A malloc()/free() function. + * If "size" is 0 then the function acts like free(), otherwise it acts like + * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ +typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size); + +struct upb_alloc { + upb_alloc_func* func; +}; + +UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) { + UPB_ASSERT(alloc); + return alloc->func(alloc, NULL, 0, size); +} + +UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize, + size_t size) { + UPB_ASSERT(alloc); + return alloc->func(alloc, ptr, oldsize, size); +} + +UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) { + assert(alloc); + alloc->func(alloc, ptr, 0, 0); +} + +/* The global allocator used by upb. Uses the standard malloc()/free(). */ + +extern upb_alloc upb_alloc_global; + +/* Functions that hard-code the global malloc. + * + * We still get benefit because we can put custom logic into our global + * allocator, like injecting out-of-memory faults in debug/testing builds. */ + +UPB_INLINE void* upb_gmalloc(size_t size) { + return upb_malloc(&upb_alloc_global, size); +} + +UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) { + return upb_realloc(&upb_alloc_global, ptr, oldsize, size); +} + +UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } + +/* upb_Arena ******************************************************************/ + +/* upb_Arena is a specific allocator implementation that uses arena allocation. + * The user provides an allocator that will be used to allocate the underlying + * arena blocks. Arenas by nature do not require the individual allocations + * to be freed. However the Arena does allow users to register cleanup + * functions that will run when the arena is destroyed. + * + * A upb_Arena is *not* thread-safe. + * + * You could write a thread-safe arena allocator that satisfies the + * upb_alloc interface, but it would not be as efficient for the + * single-threaded case. */ + +typedef void upb_CleanupFunc(void* ud); + +struct upb_Arena; +typedef struct upb_Arena upb_Arena; + +typedef struct { + /* We implement the allocator interface. + * This must be the first member of upb_Arena! + * TODO(haberman): remove once handlers are gone. */ + upb_alloc alloc; + + char *ptr, *end; +} _upb_ArenaHead; + +/* Creates an arena from the given initial block (if any -- n may be 0). + * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this + * is a fixed-size arena and cannot grow. */ +upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc); +void upb_Arena_Free(upb_Arena* a); +bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func); +bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b); +void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size); + +UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; } + +UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + return (size_t)(h->end - h->ptr); +} + +UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + void* ret = h->ptr; + UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret); + UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size); + UPB_UNPOISON_MEMORY_REGION(ret, size); + + h->ptr += size; + +#if UPB_ASAN + { + size_t guard_size = 32; + if (_upb_ArenaHas(a) >= guard_size) { + h->ptr += guard_size; + } else { + h->ptr = h->end; + } + } +#endif + + return ret; +} + +UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { + size = UPB_ALIGN_MALLOC(size); + + if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { + return _upb_Arena_SlowMalloc(a, size); + } + + return _upb_Arena_FastMalloc(a, size); +} + +// Shrinks the last alloc from arena. +// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena. +// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if +// this was not the last alloc. +UPB_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize, + size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + UPB_ASSERT((char*)ptr + oldsize == h->ptr); // Must be the last alloc. + UPB_ASSERT(size <= oldsize); + h->ptr = (char*)ptr + size; +} + +UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, + size_t size) { + _upb_ArenaHead* h = (_upb_ArenaHead*)a; + oldsize = UPB_ALIGN_MALLOC(oldsize); + size = UPB_ALIGN_MALLOC(size); + bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr; + + if (is_most_recent_alloc) { + ptrdiff_t diff = size - oldsize; + if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) { + h->ptr += diff; + return ptr; + } + } else if (size <= oldsize) { + return ptr; + } + + void* ret = upb_Arena_Malloc(a, size); + + if (ret && oldsize > 0) { + memcpy(ret, ptr, UPB_MIN(oldsize, size)); + } + + return ret; +} + +UPB_INLINE upb_Arena* upb_Arena_New(void) { + return upb_Arena_Init(NULL, 0, &upb_alloc_global); +} + +#include "upb/port_undef.inc" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_ARENA_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/array.c b/contrib/libs/grpc/third_party/upb/upb/array.c new file mode 100644 index 0000000000..b4cdc49924 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/array.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/array.h" + +#include <string.h> + +#include "upb/internal/table.h" +#include "upb/msg.h" +#include "upb/port_def.inc" + +static const char _upb_CTypeo_sizelg2[12] = { + 0, + 0, /* kUpb_CType_Bool */ + 2, /* kUpb_CType_Float */ + 2, /* kUpb_CType_Int32 */ + 2, /* kUpb_CType_UInt32 */ + 2, /* kUpb_CType_Enum */ + UPB_SIZE(2, 3), /* kUpb_CType_Message */ + 3, /* kUpb_CType_Double */ + 3, /* kUpb_CType_Int64 */ + 3, /* kUpb_CType_UInt64 */ + UPB_SIZE(3, 4), /* kUpb_CType_String */ + UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ +}; + +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { + return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); +} + +size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } + +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { + upb_MessageValue ret; + const char* data = _upb_array_constptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(&ret, data + (i << lg2), 1 << lg2); + return ret; +} + +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + UPB_ASSERT(i < arr->len); + memcpy(data + (i << lg2), &val, 1 << lg2); +} + +bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + if (!upb_Array_Resize(arr, arr->len + 1, arena)) { + return false; + } + upb_Array_Set(arr, arr->len - 1, val); + return true; +} + +void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, + size_t count) { + char* data = _upb_array_ptr(arr); + int lg2 = arr->data & 7; + memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); +} + +bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, + upb_Arena* arena) { + UPB_ASSERT(i <= arr->len); + UPB_ASSERT(count + arr->len >= count); + size_t oldsize = arr->len; + if (!upb_Array_Resize(arr, arr->len + count, arena)) { + return false; + } + upb_Array_Move(arr, i + count, i, oldsize - i); + return true; +} + +/* + * i end arr->len + * |------------|XXXXXXXX|--------| + */ +void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { + size_t end = i + count; + UPB_ASSERT(i <= end); + UPB_ASSERT(end <= arr->len); + upb_Array_Move(arr, i, end, arr->len - end); + arr->len -= count; +} + +bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { + return _upb_Array_Resize(arr, size, arena); +} diff --git a/contrib/libs/grpc/third_party/upb/upb/array.h b/contrib/libs/grpc/third_party/upb/upb/array.h new file mode 100644 index 0000000000..0715d58430 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/array.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_ARRAY_H_ +#define UPB_ARRAY_H_ + +#include "google/protobuf/descriptor.upb.h" +#include "upb/message_value.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Creates a new array on the given arena that holds elements of this type. */ +upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); + +/* Returns the size of the array. */ +size_t upb_Array_Size(const upb_Array* arr); + +/* Returns the given element, which must be within the array's current size. */ +upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); + +/* Sets the given element, which must be within the array's current size. */ +void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); + +/* Appends an element to the array. Returns false on allocation failure. */ +bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); + +/* Moves elements within the array using memmove(). Like memmove(), the source + * and destination elements may be overlapping. */ +void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, + size_t count); + +/* Inserts one or more empty elements into the array. Existing elements are + * shifted right. The new elements have undefined state and must be set with + * `upb_Array_Set()`. + * REQUIRES: `i <= upb_Array_Size(arr)` */ +bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, + upb_Arena* arena); + +/* Deletes one or more elements from the array. Existing elements are shifted + * left. + * REQUIRES: `i + count <= upb_Array_Size(arr)` */ +void upb_Array_Delete(upb_Array* array, size_t i, size_t count); + +/* Changes the size of a vector. New elements are initialized to empty/0. + * Returns false on allocation failure. */ +bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_ARRAY_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/decode.c b/contrib/libs/grpc/third_party/upb/upb/decode.c index 1e07d42c32..d314875313 100644 --- a/contrib/libs/grpc/third_party/upb/upb/decode.c +++ b/contrib/libs/grpc/third_party/upb/upb/decode.c @@ -30,9 +30,9 @@ #include <setjmp.h> #include <string.h> -#include "upb/decode_internal.h" +#include "upb/internal/decode.h" +#include "upb/internal/upb.h" #include "upb/upb.h" -#include "upb/upb_internal.h" /* Must be last. */ #include "upb/port_def.inc" @@ -93,13 +93,11 @@ static const unsigned FIXED64_OK_MASK = (1 << kUpb_FieldType_Double) | /* Three fake field types for MessageSet. */ #define TYPE_MSGSET_ITEM 19 -#define TYPE_MSGSET_TYPE_ID 20 -#define TYPE_COUNT 20 +#define TYPE_COUNT 19 /* Op: an action to be performed for a wire-type/field-type combination. */ #define OP_UNKNOWN -1 /* Unknown field. */ #define OP_MSGSET_ITEM -2 -#define OP_MSGSET_TYPEID -3 #define OP_SCALAR_LG2(n) (n) /* n in [0, 2, 3] => op in [0, 2, 3] */ #define OP_ENUM 1 #define OP_STRING 4 @@ -131,7 +129,6 @@ static const int8_t varint_ops[] = { OP_SCALAR_LG2(2), /* SINT32 */ OP_SCALAR_LG2(3), /* SINT64 */ OP_UNKNOWN, /* MSGSET_ITEM */ - OP_MSGSET_TYPEID, /* MSGSET TYPEID */ }; static const int8_t delim_ops[] = { @@ -156,7 +153,6 @@ static const int8_t delim_ops[] = { OP_UNKNOWN, /* SINT32 */ OP_UNKNOWN, /* SINT64 */ OP_UNKNOWN, /* MSGSET_ITEM */ - OP_UNKNOWN, /* MSGSET TYPEID */ /* For repeated field type. */ OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ @@ -266,6 +262,18 @@ static const char* decode_tag(upb_Decoder* d, const char* ptr, uint32_t* val) { } } +UPB_FORCEINLINE +static const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, + uint32_t* size) { + uint64_t size64; + ptr = decode_varint64(d, ptr, &size64); + if (size64 >= INT32_MAX || ptr - d->end + (int)size64 > d->limit) { + decode_err(d, kUpb_DecodeStatus_Malformed); + } + *size = size64; + return ptr; +} + static void decode_munge_int32(wireval* val) { if (!_upb_IsLittleEndian()) { /* The next stage will memcpy(dst, &val, 4) */ @@ -300,7 +308,9 @@ static upb_Message* decode_newsubmsg(upb_Decoder* d, const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* field) { const upb_MiniTable* subl = subs[field->submsg_index].submsg; - return _upb_Message_New_inl(subl, &d->arena); + upb_Message* msg = _upb_Message_New_inl(subl, &d->arena); + if (!msg) decode_err(d, kUpb_DecodeStatus_OutOfMemory); + return msg; } UPB_NOINLINE @@ -375,7 +385,7 @@ static const char* decode_togroup(upb_Decoder* d, const char* ptr, return decode_group(d, ptr, submsg, subl, field->number); } -static char* encode_varint32(uint32_t val, char* ptr) { +static char* upb_Decoder_EncodeVarint32(uint32_t val, char* ptr) { do { uint8_t byte = val & 0x7fU; val >>= 7; @@ -385,6 +395,18 @@ static char* encode_varint32(uint32_t val, char* ptr) { return ptr; } +static void upb_Decode_AddUnknownVarints(upb_Decoder* d, upb_Message* msg, + uint32_t val1, uint32_t val2) { + char buf[20]; + char* end = buf; + end = upb_Decoder_EncodeVarint32(val1, end); + end = upb_Decoder_EncodeVarint32(val2, end); + + if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } +} + UPB_NOINLINE static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable_Enum* e, @@ -398,17 +420,9 @@ static bool decode_checkenum_slow(upb_Decoder* d, const char* ptr, // Unrecognized enum goes into unknown fields. // For packed fields the tag could be arbitrarily far in the past, so we - // just re-encode the tag here. - char buf[20]; - char* end = buf; + // just re-encode the tag and value here. uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Varint; - end = encode_varint32(tag, end); - end = encode_varint32(v, end); - - if (!_upb_Message_AddUnknown(msg, buf, end - buf, &d->arena)) { - decode_err(d, kUpb_DecodeStatus_OutOfMemory); - } - + upb_Decode_AddUnknownVarints(d, msg, tag, v); return false; } @@ -627,8 +641,23 @@ static const char* decode_tomap(upb_Decoder* d, const char* ptr, upb_value_ptr(_upb_Message_New(entry->subs[0].submsg, &d->arena)); } + const char* start = ptr; ptr = decode_tosubmsg(d, ptr, &ent.k, subs, field, val->size); - _upb_Map_Set(map, &ent.k, map->key_size, &ent.v, map->val_size, &d->arena); + // check if ent had any unknown fields + size_t size; + upb_Message_GetUnknown(&ent.k, &size); + if (size != 0) { + uint32_t tag = ((uint32_t)field->number << 3) | kUpb_WireType_Delimited; + upb_Decode_AddUnknownVarints(d, msg, tag, (uint32_t)(ptr - start)); + if (!_upb_Message_AddUnknown(msg, start, ptr - start, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } + } else { + if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, + &d->arena) == _kUpb_MapInsertStatus_OutOfMemory) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } + } return ptr; } @@ -727,25 +756,139 @@ static bool decode_tryfastdispatch(upb_Decoder* d, const char** ptr, return false; } -static const char* decode_msgset(upb_Decoder* d, const char* ptr, - upb_Message* msg, - const upb_MiniTable* layout) { - // We create a temporary upb_MiniTable here and abuse its fields as temporary - // storage, to avoid creating lots of MessageSet-specific parsing code-paths: - // 1. We store 'layout' in item_layout.subs. We will need this later as - // a key to look up extensions for this MessageSet. - // 2. We use item_layout.fields as temporary storage to store the extension - // we - // found when parsing the type id. - upb_MiniTable item_layout = { - .subs = (const upb_MiniTable_Sub[]){{.submsg = layout}}, - .fields = NULL, - .size = 0, - .field_count = 0, - .ext = upb_ExtMode_IsMessageSet_ITEM, - .dense_below = 0, - .table_mask = -1}; - return decode_group(d, ptr, msg, &item_layout, 1); +static const char* upb_Decoder_SkipField(upb_Decoder* d, const char* ptr, + uint32_t tag) { + int field_number = tag >> 3; + int wire_type = tag & 7; + switch (wire_type) { + case kUpb_WireType_Varint: { + uint64_t val; + return decode_varint64(d, ptr, &val); + } + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_Delimited: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + return ptr + size; + } + case kUpb_WireType_StartGroup: + return decode_group(d, ptr, NULL, NULL, field_number); + default: + decode_err(d, kUpb_DecodeStatus_Malformed); + } +} + +enum { + kStartItemTag = ((1 << 3) | kUpb_WireType_StartGroup), + kEndItemTag = ((1 << 3) | kUpb_WireType_EndGroup), + kTypeIdTag = ((2 << 3) | kUpb_WireType_Varint), + kMessageTag = ((3 << 3) | kUpb_WireType_Delimited), +}; + +static void upb_Decoder_AddKnownMessageSetItem( + upb_Decoder* d, upb_Message* msg, const upb_MiniTable_Extension* item_mt, + const char* data, uint32_t size) { + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, item_mt, &d->arena); + if (UPB_UNLIKELY(!ext)) decode_err(d, kUpb_DecodeStatus_OutOfMemory); + upb_Message* submsg = decode_newsubmsg(d, &ext->ext->sub, &ext->ext->field); + upb_DecodeStatus status = upb_Decode(data, size, submsg, item_mt->sub.submsg, + d->extreg, d->options, &d->arena); + memcpy(&ext->data, &submsg, sizeof(submsg)); + if (status != kUpb_DecodeStatus_Ok) decode_err(d, status); +} + +static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, + upb_Message* msg, + uint32_t type_id, + const char* message_data, + uint32_t message_size) { + char buf[60]; + char* ptr = buf; + ptr = upb_Decoder_EncodeVarint32(kStartItemTag, ptr); + ptr = upb_Decoder_EncodeVarint32(kTypeIdTag, ptr); + ptr = upb_Decoder_EncodeVarint32(type_id, ptr); + ptr = upb_Decoder_EncodeVarint32(kMessageTag, ptr); + ptr = upb_Decoder_EncodeVarint32(message_size, ptr); + char* split = ptr; + + ptr = upb_Decoder_EncodeVarint32(kEndItemTag, ptr); + char* end = ptr; + + if (!_upb_Message_AddUnknown(msg, buf, split - buf, &d->arena) || + !_upb_Message_AddUnknown(msg, message_data, message_size, &d->arena) || + !_upb_Message_AddUnknown(msg, split, end - split, &d->arena)) { + decode_err(d, kUpb_DecodeStatus_OutOfMemory); + } +} + +static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, + const upb_MiniTable* layout, + uint32_t type_id, const char* data, + uint32_t size) { + const upb_MiniTable_Extension* item_mt = + _upb_extreg_get(d->extreg, layout, type_id); + if (item_mt) { + upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); + } else { + upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); + } +} + +static const char* upb_Decoder_DecodeMessageSetItem( + upb_Decoder* d, const char* ptr, upb_Message* msg, + const upb_MiniTable* layout) { + uint32_t type_id = 0; + upb_StringView preserved = {NULL, 0}; + typedef enum { + kUpb_HaveId = 1 << 0, + kUpb_HavePayload = 1 << 1, + } StateMask; + StateMask state_mask = 0; + while (!decode_isdone(d, &ptr)) { + uint32_t tag; + ptr = decode_tag(d, ptr, &tag); + switch (tag) { + case kEndItemTag: + return ptr; + case kTypeIdTag: { + uint64_t tmp; + ptr = decode_varint64(d, ptr, &tmp); + if (state_mask & kUpb_HaveId) break; // Ignore dup. + state_mask |= kUpb_HaveId; + type_id = tmp; + if (state_mask & kUpb_HavePayload) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, + preserved.size); + } + break; + } + case kMessageTag: { + uint32_t size; + ptr = upb_Decoder_DecodeSize(d, ptr, &size); + const char* data = ptr; + ptr += size; + if (state_mask & kUpb_HavePayload) break; // Ignore dup. + state_mask |= kUpb_HavePayload; + if (state_mask & kUpb_HaveId) { + upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, data, size); + } else { + // Out of order, we must preserve the payload. + preserved.data = data; + preserved.size = size; + } + break; + } + default: + // We do not preserve unexpected fields inside a message set item. + ptr = upb_Decoder_SkipField(d, ptr, tag); + break; + } + } + decode_err(d, kUpb_DecodeStatus_Malformed); } static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, @@ -780,38 +923,18 @@ static const upb_MiniTable_Field* decode_findfield(upb_Decoder* d, if (d->extreg) { switch (l->ext) { - case upb_ExtMode_Extendable: { + case kUpb_ExtMode_Extendable: { const upb_MiniTable_Extension* ext = _upb_extreg_get(d->extreg, l, field_number); if (ext) return &ext->field; break; } - case upb_ExtMode_IsMessageSet: + case kUpb_ExtMode_IsMessageSet: if (field_number == _UPB_MSGSET_ITEM) { static upb_MiniTable_Field item = {0, 0, 0, 0, TYPE_MSGSET_ITEM, 0}; return &item; } break; - case upb_ExtMode_IsMessageSet_ITEM: - switch (field_number) { - case _UPB_MSGSET_TYPEID: { - static upb_MiniTable_Field type_id = { - 0, 0, 0, 0, TYPE_MSGSET_TYPE_ID, 0}; - return &type_id; - } - case _UPB_MSGSET_MESSAGE: - if (l->fields) { - // We saw type_id previously and succeeded in looking up msg. - return l->fields; - } else { - // TODO: out of order MessageSet. - // This is a very rare case: all serializers will emit in-order - // MessageSets. To hit this case there has to be some kind of - // re-ordering proxy. We should eventually handle this case, but - // not today. - } - break; - } } } @@ -851,14 +974,9 @@ static const char* decode_wireval(upb_Decoder* d, const char* ptr, return ptr + 8; case kUpb_WireType_Delimited: { int ndx = field->descriptortype; - uint64_t size; if (upb_FieldMode_Get(field) == kUpb_FieldMode_Array) ndx += TYPE_COUNT; - ptr = decode_varint64(d, ptr, &size); - if (size >= INT32_MAX || ptr - d->end + (int32_t)size > d->limit) { - break; /* Length overflow. */ - } + ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); *op = delim_ops[ndx]; - val->size = size; return ptr; } case kUpb_WireType_StartGroup: @@ -885,11 +1003,11 @@ static const char* decode_known(upb_Decoder* d, const char* ptr, const upb_MiniTable_Sub* subs = layout->subs; uint8_t mode = field->mode; - if (UPB_UNLIKELY(mode & upb_LabelFlags_IsExtension)) { + if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { const upb_MiniTable_Extension* ext_layout = (const upb_MiniTable_Extension*)field; upb_Message_Extension* ext = - _upb_Message_Getorcreateext(msg, ext_layout, &d->arena); + _upb_Message_GetOrCreateExtension(msg, ext_layout, &d->arena); if (UPB_UNLIKELY(!ext)) return decode_err(d, kUpb_DecodeStatus_OutOfMemory); msg = &ext->data; subs = &ext->ext->sub; @@ -1022,14 +1140,8 @@ static const char* decode_msg(upb_Decoder* d, const char* ptr, upb_Message* msg, ptr = decode_unknown(d, ptr, msg, field_number, wire_type, val); break; case OP_MSGSET_ITEM: - ptr = decode_msgset(d, ptr, msg, layout); + ptr = upb_Decoder_DecodeMessageSetItem(d, ptr, msg, layout); break; - case OP_MSGSET_TYPEID: { - const upb_MiniTable_Extension* ext = _upb_extreg_get( - d->extreg, layout->subs[0].submsg, val.uint64_val); - if (ext) ((upb_MiniTable*)layout)->fields = &ext->field; - break; - } } } } diff --git a/contrib/libs/grpc/third_party/upb/upb/decode.h b/contrib/libs/grpc/third_party/upb/upb/decode.h index 1fa8131b7d..0c09497feb 100644 --- a/contrib/libs/grpc/third_party/upb/upb/decode.h +++ b/contrib/libs/grpc/third_party/upb/upb/decode.h @@ -32,6 +32,7 @@ #ifndef UPB_DECODE_H_ #define UPB_DECODE_H_ +#include "upb/extension_registry.h" #include "upb/msg.h" /* Must be last. */ diff --git a/contrib/libs/grpc/third_party/upb/upb/decode_fast.c b/contrib/libs/grpc/third_party/upb/upb/decode_fast.c index e05bf8e0db..a02ad0948f 100644 --- a/contrib/libs/grpc/third_party/upb/upb/decode_fast.c +++ b/contrib/libs/grpc/third_party/upb/upb/decode_fast.c @@ -37,7 +37,7 @@ #include "upb/decode_fast.h" -#include "upb/decode_internal.h" +#include "upb/internal/decode.h" /* Must be last. */ #include "upb/port_def.inc" diff --git a/contrib/libs/grpc/third_party/upb/upb/def.c b/contrib/libs/grpc/third_party/upb/upb/def.c index 363d8bb960..6ddc45bbbb 100644 --- a/contrib/libs/grpc/third_party/upb/upb/def.c +++ b/contrib/libs/grpc/third_party/upb/upb/def.c @@ -34,6 +34,7 @@ #include <string.h> #include "google/protobuf/descriptor.upb.h" +#include "upb/mini_table.h" #include "upb/reflection.h" /* Must be last. */ @@ -86,6 +87,9 @@ struct upb_FieldDef { bool has_json_name_; upb_FieldType type_; upb_Label label_; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_ExtensionRange { @@ -106,8 +110,8 @@ struct upb_MessageDef { upb_strtable ntof; /* All nested defs. - * MEM: We could save some space here by putting nested defs in a contigous - * region and calculating counts from offets or vice-versa. */ + * MEM: We could save some space here by putting nested defs in a contiguous + * region and calculating counts from offsets or vice-versa. */ const upb_FieldDef* fields; const upb_OneofDef* oneofs; const upb_ExtensionRange* ext_ranges; @@ -123,6 +127,9 @@ struct upb_MessageDef { int nested_ext_count; bool in_message_set; upb_WellKnown well_known_type; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_EnumDef { @@ -136,6 +143,9 @@ struct upb_EnumDef { const upb_EnumValueDef* values; int value_count; int32_t defaultval; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_EnumValueDef { @@ -154,6 +164,9 @@ struct upb_OneofDef { const upb_FieldDef** fields; upb_strtable ntof; upb_inttable itof; +#if UINTPTR_MAX == 0xffffffff + uint32_t padding; // Increase size to a multiple of 8. +#endif }; struct upb_FileDef { @@ -188,6 +201,7 @@ struct upb_MethodDef { const char* full_name; const upb_MessageDef* input_type; const upb_MessageDef* output_type; + int index; bool client_streaming; bool server_streaming; }; @@ -246,6 +260,20 @@ static const void* unpack_def(upb_value v, upb_deftype_t type) { } static upb_value pack_def(const void* ptr, upb_deftype_t type) { + // Our 3-bit pointer tagging requires all pointers to be multiples of 8. + // The arena will always yield 8-byte-aligned addresses, however we put + // the defs into arrays. For each element in the array to be 8-byte-aligned, + // the sizes of each def type must also be a multiple of 8. + // + // If any of these asserts fail, we need to add or remove padding on 32-bit + // machines (64-bit machines will have 8-byte alignment already due to + // pointers, which all of these structs have). + UPB_ASSERT((sizeof(upb_FieldDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_MessageDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_EnumDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_EnumValueDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_ServiceDef) & UPB_DEFTYPE_MASK) == 0); + UPB_ASSERT((sizeof(upb_OneofDef) & UPB_DEFTYPE_MASK) == 0); uintptr_t num = (uintptr_t)ptr; UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); num |= type; @@ -621,6 +649,14 @@ bool upb_FieldDef_IsString(const upb_FieldDef* f) { upb_FieldDef_CType(f) == kUpb_CType_Bytes; } +bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Optional; +} + +bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { + return upb_FieldDef_Label(f) == kUpb_Label_Required; +} + bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { return upb_FieldDef_Label(f) == kUpb_Label_Repeated; } @@ -980,6 +1016,8 @@ const char* upb_MethodDef_FullName(const upb_MethodDef* m) { return m->full_name; } +int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } + const char* upb_MethodDef_Name(const upb_MethodDef* m) { return shortdefname(m->full_name); } @@ -1384,7 +1422,12 @@ static uint8_t map_descriptortype(const upb_FieldDef* f) { if (type == kUpb_FieldType_String && f->file->syntax == kUpb_Syntax_Proto2) { return kUpb_FieldType_Bytes; } else if (type == kUpb_FieldType_Enum && - f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3) { + (f->sub.enumdef->file->syntax == kUpb_Syntax_Proto3 || + UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 || + // TODO(https://github.com/protocolbuffers/upb/issues/541): + // fix map enum values to check for unknown enum values and put + // them in the unknown field set. + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)))) { return kUpb_FieldType_Int32; } return type; @@ -1397,43 +1440,43 @@ static void fill_fieldlayout(upb_MiniTable_Field* field, if (upb_FieldDef_IsMap(f)) { field->mode = - kUpb_FieldMode_Map | (upb_FieldRep_Pointer << upb_FieldRep_Shift); + kUpb_FieldMode_Map | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); } else if (upb_FieldDef_IsRepeated(f)) { field->mode = - kUpb_FieldMode_Array | (upb_FieldRep_Pointer << upb_FieldRep_Shift); + kUpb_FieldMode_Array | (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift); } else { /* Maps descriptor type -> elem_size_lg2. */ static const uint8_t sizes[] = { - -1, /* invalid descriptor type */ - upb_FieldRep_8Byte, /* DOUBLE */ - upb_FieldRep_4Byte, /* FLOAT */ - upb_FieldRep_8Byte, /* INT64 */ - upb_FieldRep_8Byte, /* UINT64 */ - upb_FieldRep_4Byte, /* INT32 */ - upb_FieldRep_8Byte, /* FIXED64 */ - upb_FieldRep_4Byte, /* FIXED32 */ - upb_FieldRep_1Byte, /* BOOL */ - upb_FieldRep_StringView, /* STRING */ - upb_FieldRep_Pointer, /* GROUP */ - upb_FieldRep_Pointer, /* MESSAGE */ - upb_FieldRep_StringView, /* BYTES */ - upb_FieldRep_4Byte, /* UINT32 */ - upb_FieldRep_4Byte, /* ENUM */ - upb_FieldRep_4Byte, /* SFIXED32 */ - upb_FieldRep_8Byte, /* SFIXED64 */ - upb_FieldRep_4Byte, /* SINT32 */ - upb_FieldRep_8Byte, /* SINT64 */ + -1, /* invalid descriptor type */ + kUpb_FieldRep_8Byte, /* DOUBLE */ + kUpb_FieldRep_4Byte, /* FLOAT */ + kUpb_FieldRep_8Byte, /* INT64 */ + kUpb_FieldRep_8Byte, /* UINT64 */ + kUpb_FieldRep_4Byte, /* INT32 */ + kUpb_FieldRep_8Byte, /* FIXED64 */ + kUpb_FieldRep_4Byte, /* FIXED32 */ + kUpb_FieldRep_1Byte, /* BOOL */ + kUpb_FieldRep_StringView, /* STRING */ + kUpb_FieldRep_Pointer, /* GROUP */ + kUpb_FieldRep_Pointer, /* MESSAGE */ + kUpb_FieldRep_StringView, /* BYTES */ + kUpb_FieldRep_4Byte, /* UINT32 */ + kUpb_FieldRep_4Byte, /* ENUM */ + kUpb_FieldRep_4Byte, /* SFIXED32 */ + kUpb_FieldRep_8Byte, /* SFIXED64 */ + kUpb_FieldRep_4Byte, /* SINT32 */ + kUpb_FieldRep_8Byte, /* SINT64 */ }; field->mode = kUpb_FieldMode_Scalar | - (sizes[field->descriptortype] << upb_FieldRep_Shift); + (sizes[field->descriptortype] << kUpb_FieldRep_Shift); } if (upb_FieldDef_IsPacked(f)) { - field->mode |= upb_LabelFlags_IsPacked; + field->mode |= kUpb_LabelFlags_IsPacked; } if (upb_FieldDef_IsExtension(f)) { - field->mode |= upb_LabelFlags_IsExtension; + field->mode |= kUpb_LabelFlags_IsExtension; } } @@ -1471,12 +1514,12 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { if (upb_MessageDef_ExtensionRangeCount(m) > 0) { if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { - l->ext = upb_ExtMode_IsMessageSet; + l->ext = kUpb_ExtMode_IsMessageSet; } else { - l->ext = upb_ExtMode_Extendable; + l->ext = kUpb_ExtMode_Extendable; } } else { - l->ext = upb_ExtMode_NonExtendable; + l->ext = kUpb_ExtMode_NonExtendable; } /* TODO(haberman): initialize fast tables so that reflection-based parsing @@ -1551,11 +1594,11 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { fill_fieldlayout(field, f); - if (upb_FieldDef_IsSubMessage(f)) { + if (field->descriptortype == kUpb_FieldType_Message || + field->descriptortype == kUpb_FieldType_Group) { field->submsg_index = sublayout_count++; subs[field->submsg_index].submsg = upb_FieldDef_MessageSubDef(f)->layout; - } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum && - f->file->syntax == kUpb_Syntax_Proto2) { + } else if (field->descriptortype == kUpb_FieldType_Enum) { field->submsg_index = sublayout_count++; subs[field->submsg_index].subenum = upb_FieldDef_EnumSubDef(f)->layout; UPB_ASSERT(subs[field->submsg_index].subenum); @@ -1601,6 +1644,10 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { if (upb_OneofDef_IsSynthetic(o)) continue; + if (o->field_count == 0) { + symtab_errf(ctx, "Oneof must have at least one field (%s)", o->full_name); + } + /* Calculate field size: the max of all field sizes. */ for (int j = 0; j < o->field_count; j++) { const upb_FieldDef* f = o->fields[j]; @@ -1623,7 +1670,10 @@ static void make_layout(symtab_addctx* ctx, const upb_MessageDef* m) { l->size = UPB_ALIGN_UP(l->size, 8); /* Sort fields by number. */ - qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), field_number_cmp); + if (fields) { + qsort(fields, upb_MessageDef_numfields(m), sizeof(*fields), + field_number_cmp); + } assign_layout_indices(m, l, fields); } @@ -1784,8 +1834,8 @@ static const void* symtab_resolveany(symtab_addctx* ctx, } } else { /* Remove components from base until we find an entry or run out. */ - size_t baselen = strlen(base); - char* tmp = malloc(sym.size + strlen(base) + 1); + size_t baselen = base ? strlen(base) : 0; + char* tmp = malloc(sym.size + baselen + 1); while (1) { char* p = tmp; if (baselen) { @@ -1821,10 +1871,10 @@ static const void* symtab_resolve(symtab_addctx* ctx, const char* from_name_dbg, const void* ret = symtab_resolveany(ctx, from_name_dbg, base, sym, &found_type); if (ret && found_type != type) { - symtab_errf( - ctx, - "type mismatch when resolving %s: couldn't find name %s with type=%d", - from_name_dbg, sym.data, (int)type); + symtab_errf(ctx, + "type mismatch when resolving %s: couldn't find " + "name " UPB_STRINGVIEW_FORMAT " with type=%d", + from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); } return ret; } @@ -1844,6 +1894,11 @@ static void create_oneofdef( SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); + upb_value existing_v; + if (upb_strtable_lookup2(&m->ntof, name.data, name.size, &existing_v)) { + symtab_errf(ctx, "duplicate oneof name (%s)", o->full_name); + } + v = pack_def(o, UPB_DEFTYPE_ONEOF); CHK_OOM(upb_strtable_insert(&m->ntof, name.data, name.size, v, ctx->arena)); @@ -2153,7 +2208,7 @@ static void create_fielddef( f->file = ctx->file; /* Must happen prior to symtab_add(). */ if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - symtab_errf(ctx, "field has no name (%s)", upb_MessageDef_FullName(m)); + symtab_errf(ctx, "field has no name"); } name = google_protobuf_FieldDescriptorProto_name(field_proto); @@ -2292,8 +2347,7 @@ static void create_fielddef( } if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - int oneof_index = - google_protobuf_FieldDescriptorProto_oneof_index(field_proto); + uint32_t oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); upb_OneofDef* oneof; upb_value v = upb_value_constptr(f); @@ -2370,6 +2424,7 @@ static void create_service( m->service = s; m->full_name = makefullname(ctx, s->full_name, name); + m->index = i; m->client_streaming = google_protobuf_MethodDescriptorProto_client_streaming(method_proto); m->server_streaming = @@ -2397,6 +2452,12 @@ static int count_bits_debug(uint64_t x) { return n; } +static int compare_int32(const void* a_ptr, const void* b_ptr) { + int32_t a = *(int32_t*)a_ptr; + int32_t b = *(int32_t*)b_ptr; + return a < b ? -1 : (a == b ? 0 : 1); +} + upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, const upb_EnumDef* e) { int n = 0; @@ -2405,7 +2466,7 @@ upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, for (int i = 0; i < e->value_count; i++) { uint32_t val = (uint32_t)e->values[i].number; if (val < 64) { - mask |= 1 << val; + mask |= 1ULL << val; } else { n++; } @@ -2427,6 +2488,17 @@ upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx, UPB_ASSERT(p == values + n); } + // Enums can have duplicate values; we must sort+uniq them. + if (values) qsort(values, n, sizeof(*values), &compare_int32); + + int dst = 0; + for (int i = 0; i < n; dst++) { + int32_t val = values[i]; + while (i < n && values[i] == val) i++; // Skip duplicates. + values[dst] = val; + } + n = dst; + UPB_ASSERT(upb_inttable_count(&e->iton) == n + count_bits_debug(mask)); upb_MiniTable_Enum* layout = symtab_alloc(ctx, sizeof(*layout)); @@ -2510,7 +2582,7 @@ static void create_enumdef( if (ctx->layout) { UPB_ASSERT(ctx->enum_count < ctx->layout->enum_count); e->layout = ctx->layout->enums[ctx->enum_count++]; - UPB_ASSERT(n == + UPB_ASSERT(upb_inttable_count(&e->iton) == e->layout->value_count + count_bits_debug(e->layout->mask)); } else { e->layout = create_enumlayout(ctx, e); @@ -2781,15 +2853,10 @@ static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->fields[i]); } - for (int i = 0; i < m->nested_ext_count; i++) { - resolve_fielddef(ctx, m->full_name, (upb_FieldDef*)&m->nested_exts[i]); - } - - if (!ctx->layout) make_layout(ctx, m); - m->in_message_set = false; - if (m->nested_ext_count == 1) { - const upb_FieldDef* ext = &m->nested_exts[0]; + for (int i = 0; i < m->nested_ext_count; i++) { + upb_FieldDef* ext = (upb_FieldDef*)&m->nested_exts[i]; + resolve_fielddef(ctx, m->full_name, ext); if (ext->type_ == kUpb_FieldType_Message && ext->label_ == kUpb_Label_Optional && ext->sub.msgdef == m && google_protobuf_MessageOptions_message_set_wire_format( @@ -2798,6 +2865,8 @@ static void resolve_msgdef(symtab_addctx* ctx, upb_MessageDef* m) { } } + if (!ctx->layout) make_layout(ctx, m); + for (int i = 0; i < m->nested_msg_count; i++) { resolve_msgdef(ctx, (upb_MessageDef*)&m->nested_msgs[i]); } @@ -2929,7 +2998,7 @@ static void build_filedef( int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; for (i = 0; i < n; i++) { if (weak_deps[i] >= file->dep_count) { - symtab_errf(ctx, "public_dep %d is out of range", (int)public_deps[i]); + symtab_errf(ctx, "weak_dep %d is out of range", (int)weak_deps[i]); } mutable_weak_deps[i] = weak_deps[i]; } @@ -3085,7 +3154,8 @@ const upb_FileDef* upb_DefPool_AddFile( /* Include here since we want most of this file to be stdio-free. */ #include <stdio.h> -bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable) { /* Since this function should never fail (it would indicate a bug in upb) we * print errors to stderr instead of returning error status to the user. */ _upb_DefPool_Init** deps = init->deps; @@ -3102,7 +3172,7 @@ bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { arena = upb_Arena_New(); for (; *deps; deps++) { - if (!_upb_DefPool_LoadDefInit(s, *deps)) goto err; + if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; } file = google_protobuf_FileDescriptorProto_parse_ex( @@ -3119,7 +3189,8 @@ bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { goto err; } - if (!_upb_DefPool_AddFile(s, file, init->layout, &status)) { + const upb_MiniTable_File* mt = rebuild_minitable ? NULL : init->layout; + if (!_upb_DefPool_AddFile(s, file, mt, &status)) { goto err; } diff --git a/contrib/libs/grpc/third_party/upb/upb/def.h b/contrib/libs/grpc/third_party/upb/upb/def.h index 8b64a53c1d..2cb312df1a 100644 --- a/contrib/libs/grpc/third_party/upb/upb/def.h +++ b/contrib/libs/grpc/third_party/upb/upb/def.h @@ -29,7 +29,7 @@ #define UPB_DEF_H_ #include "google/protobuf/descriptor.upb.h" -#include "upb/table_internal.h" +#include "upb/internal/table.h" #include "upb/upb.h" /* Must be last. */ @@ -116,6 +116,8 @@ const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f); uint32_t upb_FieldDef_Index(const upb_FieldDef* f); bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f); bool upb_FieldDef_IsString(const upb_FieldDef* f); +bool upb_FieldDef_IsOptional(const upb_FieldDef* f); +bool upb_FieldDef_IsRequired(const upb_FieldDef* f); bool upb_FieldDef_IsRepeated(const upb_FieldDef* f); bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f); bool upb_FieldDef_IsMap(const upb_FieldDef* f); @@ -164,11 +166,11 @@ const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, #define kUpb_Any_TypeFieldNumber 1 #define kUpb_Any_ValueFieldNumber 2 -/* Well-known field tag numbers for timestamp messages. */ +/* Well-known field tag numbers for duration messages. */ #define kUpb_Duration_SecondsFieldNumber 1 #define kUpb_Duration_NanosFieldNumber 2 -/* Well-known field tag numbers for duration messages. */ +/* Well-known field tag numbers for timestamp messages. */ #define kUpb_Timestamp_SecondsFieldNumber 1 #define kUpb_Timestamp_NanosFieldNumber 2 @@ -210,6 +212,11 @@ UPB_INLINE bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { return google_protobuf_MessageOptions_map_entry(upb_MessageDef_Options(m)); } +UPB_INLINE bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { + return google_protobuf_MessageOptions_message_set_wire_format( + upb_MessageDef_Options(m)); +} + /* Nested entities. */ int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m); int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m); @@ -317,6 +324,7 @@ const google_protobuf_MethodOptions* upb_MethodDef_Options( const upb_MethodDef* m); bool upb_MethodDef_HasOptions(const upb_MethodDef* m); const char* upb_MethodDef_FullName(const upb_MethodDef* m); +int upb_MethodDef_Index(const upb_MethodDef* m); const char* upb_MethodDef_Name(const upb_MethodDef* m); const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m); const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m); @@ -389,7 +397,15 @@ typedef struct _upb_DefPool_Init { upb_StringView descriptor; /* Serialized descriptor. */ } _upb_DefPool_Init; -bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init); +// Should only be directly called by tests. This variant lets us suppress +// the use of compiled-in tables, forcing a rebuild of the tables at runtime. +bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, + bool rebuild_minitable); + +UPB_INLINE bool _upb_DefPool_LoadDefInit(upb_DefPool* s, + const _upb_DefPool_Init* init) { + return _upb_DefPool_LoadDefInitEx(s, init, false); +} #include "upb/port_undef.inc" diff --git a/contrib/libs/grpc/third_party/upb/upb/def.hpp b/contrib/libs/grpc/third_party/upb/upb/def.hpp index d179721d1f..4ce4a22250 100644 --- a/contrib/libs/grpc/third_party/upb/upb/def.hpp +++ b/contrib/libs/grpc/third_party/upb/upb/def.hpp @@ -374,11 +374,11 @@ class FileDefPtr { const upb_FileDef* ptr_; }; -// Non-const methods in upb::SymbolTable are NOT thread-safe. -class SymbolTable { +// Non-const methods in upb::DefPool are NOT thread-safe. +class DefPool { public: - SymbolTable() : ptr_(upb_DefPool_New(), upb_DefPool_Free) {} - explicit SymbolTable(upb_DefPool* s) : ptr_(s, upb_DefPool_Free) {} + DefPool() : ptr_(upb_DefPool_New(), upb_DefPool_Free) {} + explicit DefPool(upb_DefPool* s) : ptr_(s, upb_DefPool_Free) {} const upb_DefPool* ptr() const { return ptr_.get(); } upb_DefPool* ptr() { return ptr_.get(); } @@ -410,6 +410,9 @@ class SymbolTable { std::unique_ptr<upb_DefPool, decltype(&upb_DefPool_Free)> ptr_; }; +// TODO(b/236632406): This typedef is deprecated. Delete it. +using SymbolTable = DefPool; + inline FileDefPtr MessageDefPtr::file() const { return FileDefPtr(upb_MessageDef_File(ptr_)); } diff --git a/contrib/libs/grpc/third_party/upb/upb/encode.c b/contrib/libs/grpc/third_party/upb/upb/encode.c index c339c9d81e..048ecd2396 100644 --- a/contrib/libs/grpc/third_party/upb/upb/encode.c +++ b/contrib/libs/grpc/third_party/upb/upb/encode.c @@ -32,6 +32,7 @@ #include <setjmp.h> #include <string.h> +#include "upb/extension_registry.h" #include "upb/msg_internal.h" #include "upb/upb.h" @@ -76,7 +77,9 @@ static size_t upb_roundup_pow2(size_t bytes) { return ret; } -UPB_NORETURN static void encode_err(upb_encstate* e) { UPB_LONGJMP(e->err, 1); } +UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { + UPB_LONGJMP(e->err, s); +} UPB_NOINLINE static void encode_growbuffer(upb_encstate* e, size_t bytes) { @@ -84,7 +87,7 @@ static void encode_growbuffer(upb_encstate* e, size_t bytes) { size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); char* new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); - if (!new_buf) encode_err(e); + if (!new_buf) encode_err(e, kUpb_EncodeStatus_OutOfMemory); /* We want previous data at the end, realloc() put it at the beginning. */ if (old_size > 0) { @@ -255,7 +258,7 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem, if (submsg == NULL) { return; } - if (--e->depth == 0) encode_err(e); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); encode_tag(e, f->number, kUpb_WireType_EndGroup); encode_message(e, submsg, subm, &size); wire_type = kUpb_WireType_StartGroup; @@ -269,7 +272,7 @@ static void encode_scalar(upb_encstate* e, const void* _field_mem, if (submsg == NULL) { return; } - if (--e->depth == 0) encode_err(e); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); encode_message(e, submsg, subm, &size); encode_varint(e, size); wire_type = kUpb_WireType_Delimited; @@ -288,7 +291,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, const upb_MiniTable_Sub* subs, const upb_MiniTable_Field* f) { const upb_Array* arr = *UPB_PTR_AT(msg, f->offset, upb_Array*); - bool packed = f->mode & upb_LabelFlags_IsPacked; + bool packed = f->mode & kUpb_LabelFlags_IsPacked; size_t pre_len = e->limit - e->ptr; if (arr == NULL || arr->len == 0) { @@ -355,7 +358,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, const void* const* start = _upb_array_constptr(arr); const void* const* ptr = start + arr->len; const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); do { size_t size; ptr--; @@ -370,7 +373,7 @@ static void encode_array(upb_encstate* e, const upb_Message* msg, const void* const* start = _upb_array_constptr(arr); const void* const* ptr = start + arr->len; const upb_MiniTable* subm = subs[f->submsg_index].submsg; - if (--e->depth == 0) encode_err(e); + if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); do { size_t size; ptr--; @@ -413,7 +416,7 @@ static void encode_map(upb_encstate* e, const upb_Message* msg, if (map == NULL) return; - if (e->options & kUpb_Encode_Deterministic) { + if (e->options & kUpb_EncodeOption_Deterministic) { _upb_sortedmap sorted; _upb_mapsorter_pushmap(&e->sorter, layout->fields[0].descriptortype, map, &sorted); @@ -442,23 +445,29 @@ static bool encode_shouldencode(upb_encstate* e, const upb_Message* msg, if (f->presence == 0) { /* Proto3 presence or map/array. */ const void* mem = UPB_PTR_AT(msg, f->offset, void); - switch (f->mode >> upb_FieldRep_Shift) { - case upb_FieldRep_1Byte: { + switch (f->mode >> kUpb_FieldRep_Shift) { + case kUpb_FieldRep_1Byte: { char ch; memcpy(&ch, mem, 1); return ch != 0; } - case upb_FieldRep_4Byte: { +#if UINTPTR_MAX == 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_4Byte: { uint32_t u32; memcpy(&u32, mem, 4); return u32 != 0; } - case upb_FieldRep_8Byte: { +#if UINTPTR_MAX != 0xffffffff + case kUpb_FieldRep_Pointer: +#endif + case kUpb_FieldRep_8Byte: { uint64_t u64; memcpy(&u64, mem, 8); return u64 != 0; } - case upb_FieldRep_StringView: { + case kUpb_FieldRep_StringView: { const upb_StringView* str = (const upb_StringView*)mem; return str->size != 0; } @@ -514,16 +523,16 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, const upb_MiniTable* m, size_t* size) { size_t pre_len = e->limit - e->ptr; - if ((e->options & kUpb_Encode_CheckRequired) && m->required_count) { + if ((e->options & kUpb_EncodeOption_CheckRequired) && m->required_count) { uint64_t msg_head; memcpy(&msg_head, msg, 8); msg_head = _upb_BigEndian_Swap64(msg_head); if (upb_MiniTable_requiredmask(m) & ~msg_head) { - encode_err(e); + encode_err(e, kUpb_EncodeStatus_MissingRequired); } } - if ((e->options & kUpb_Encode_SkipUnknown) == 0) { + if ((e->options & kUpb_EncodeOption_SkipUnknown) == 0) { size_t unknown_size; const char* unknown = upb_Message_GetUnknown(msg, &unknown_size); @@ -532,7 +541,7 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, } } - if (m->ext != upb_ExtMode_NonExtendable) { + if (m->ext != kUpb_ExtMode_NonExtendable) { /* Encode all extensions together. Unlike C++, we do not attempt to keep * these in field number order relative to normal fields or even to each * other. */ @@ -541,7 +550,7 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, if (ext_count) { const upb_Message_Extension* end = ext + ext_count; for (; ext != end; ext++) { - if (UPB_UNLIKELY(m->ext == upb_ExtMode_IsMessageSet)) { + if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) { encode_msgset_item(e, ext); } else { encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field); @@ -564,8 +573,9 @@ static void encode_message(upb_encstate* e, const upb_Message* msg, *size = (e->limit - e->ptr) - pre_len; } -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size) { +upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size) { upb_encstate e; unsigned depth = (unsigned)options >> 16; @@ -576,23 +586,28 @@ char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, e.depth = depth ? depth : 64; e.options = options; _upb_mapsorter_init(&e.sorter); - char* ret = NULL; - if (UPB_SETJMP(e.err)) { - *size = 0; - ret = NULL; - } else { + upb_EncodeStatus status = UPB_SETJMP(e.err); + + // Unfortunately we must continue to perform hackery here because there are + // code paths which blindly copy the returned pointer without bothering to + // check for errors until much later (b/235839510). So we still set *buf to + // NULL on error and we still set it to non-NULL on a successful empty result. + if (status == kUpb_EncodeStatus_Ok) { encode_message(&e, msg, l, size); *size = e.limit - e.ptr; if (*size == 0) { static char ch; - ret = &ch; + *buf = &ch; } else { UPB_ASSERT(e.ptr); - ret = e.ptr; + *buf = e.ptr; } + } else { + *buf = NULL; + *size = 0; } _upb_mapsorter_destroy(&e.sorter); - return ret; + return status; } diff --git a/contrib/libs/grpc/third_party/upb/upb/encode.h b/contrib/libs/grpc/third_party/upb/upb/encode.h index 906b6f0c35..791d84a74c 100644 --- a/contrib/libs/grpc/third_party/upb/upb/encode.h +++ b/contrib/libs/grpc/third_party/upb/upb/encode.h @@ -26,7 +26,7 @@ */ /* - * upb_Encode: parsing into a upb_Message using a upb_MiniTable. + * upb_Encode: parsing from a upb_Message using a upb_MiniTable. */ #ifndef UPB_ENCODE_H_ @@ -48,19 +48,29 @@ enum { * * If your proto contains maps, the encoder will need to malloc()/free() * memory during encode. */ - kUpb_Encode_Deterministic = 1, + kUpb_EncodeOption_Deterministic = 1, /* When set, unknown fields are not printed. */ - kUpb_Encode_SkipUnknown = 2, + kUpb_EncodeOption_SkipUnknown = 2, /* When set, the encode will fail if any required fields are missing. */ - kUpb_Encode_CheckRequired = 4, + kUpb_EncodeOption_CheckRequired = 4, }; #define UPB_ENCODE_MAXDEPTH(depth) ((depth) << 16) -char* upb_Encode(const void* msg, const upb_MiniTable* l, int options, - upb_Arena* arena, size_t* size); +typedef enum { + kUpb_EncodeStatus_Ok = 0, + kUpb_EncodeStatus_OutOfMemory = 1, // Arena alloc failed + kUpb_EncodeStatus_MaxDepthExceeded = 2, // Exceeded UPB_ENCODE_MAXDEPTH + + // kUpb_EncodeOption_CheckRequired failed but the parse otherwise succeeded. + kUpb_EncodeStatus_MissingRequired = 3, +} upb_EncodeStatus; + +upb_EncodeStatus upb_Encode(const void* msg, const upb_MiniTable* l, + int options, upb_Arena* arena, char** buf, + size_t* size); #include "upb/port_undef.inc" diff --git a/contrib/libs/grpc/third_party/upb/upb/extension_registry.c b/contrib/libs/grpc/third_party/upb/upb/extension_registry.c new file mode 100644 index 0000000000..921cf227dd --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/extension_registry.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/extension_registry.h" + +#include "upb/internal/table.h" +#include "upb/msg.h" +#include "upb/msg_internal.h" + +// Must be last. +#include "upb/port_def.inc" + +struct upb_ExtensionRegistry { + upb_Arena* arena; + upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ +}; + +#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) + +static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { + memcpy(buf, &l, sizeof(l)); + memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); +} + +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { + upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); + if (!r) return NULL; + r->arena = arena; + if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; + return r; +} + +bool _upb_extreg_add(upb_ExtensionRegistry* r, + const upb_MiniTable_Extension** e, size_t count) { + char buf[EXTREG_KEY_SIZE]; + const upb_MiniTable_Extension** start = e; + const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); + for (; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, + upb_value_constptr(ext), r->arena)) { + goto failure; + } + } + return true; + +failure: + /* Back out the entries previously added. */ + for (end = e, e = start; e < end; e++) { + const upb_MiniTable_Extension* ext = *e; + extreg_key(buf, ext->extendee, ext->field.number); + upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); + } + return false; +} + +const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, + const upb_MiniTable* l, + uint32_t num) { + char buf[EXTREG_KEY_SIZE]; + upb_value v; + extreg_key(buf, l, num); + if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; + } +} diff --git a/contrib/libs/grpc/third_party/upb/upb/extension_registry.h b/contrib/libs/grpc/third_party/upb/upb/extension_registry.h new file mode 100644 index 0000000000..0e0a4440ca --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/extension_registry.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_EXTENSION_REGISTRY_H_ +#define UPB_EXTENSION_REGISTRY_H_ + +#include <stddef.h> + +#include "upb/upb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Extension registry: a dynamic data structure that stores a map of: + * (upb_MiniTable, number) -> extension info + * + * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing + * binary format. + * + * upb_ExtensionRegistry is part of the mini-table (msglayout) family of + * objects. Like all mini-table objects, it is suitable for reflection-less + * builds that do not want to expose names into the binary. + * + * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory + * allocation and dynamic initialization: + * * If reflection is being used, then upb_DefPool will construct an appropriate + * upb_ExtensionRegistry automatically. + * * For a mini-table only build, the user must manually construct the + * upb_ExtensionRegistry and populate it with all of the extensions the user + * cares about. + * * A third alternative is to manually unpack relevant extensions after the + * main parse is complete, similar to how Any works. This is perhaps the + * nicest solution from the perspective of reducing dependencies, avoiding + * dynamic memory allocation, and avoiding the need to parse uninteresting + * extensions. The downsides are: + * (1) parse errors are not caught during the main parse + * (2) the CPU hit of parsing comes during access, which could cause an + * undesirable stutter in application performance. + * + * Users cannot directly get or put into this map. Users can only add the + * extensions from a generated module and pass the extension registry to the + * binary decoder. + * + * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use + * reflection do not need to populate a upb_ExtensionRegistry directly. + */ + +struct upb_ExtensionRegistry; +typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; + +/* Creates a upb_ExtensionRegistry in the given arena. The arena must outlive + * any use of the extreg. */ +upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_EXTENSION_REGISTRY_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/decode_internal.h b/contrib/libs/grpc/third_party/upb/upb/internal/decode.h index 11bb9aa095..708874c9c7 100644 --- a/contrib/libs/grpc/third_party/upb/upb/decode_internal.h +++ b/contrib/libs/grpc/third_party/upb/upb/internal/decode.h @@ -30,15 +30,15 @@ * decode.c and decode_fast.c. */ -#ifndef UPB_DECODE_INT_H_ -#define UPB_DECODE_INT_H_ +#ifndef UPB_INTERNAL_DECODE_H_ +#define UPB_INTERNAL_DECODE_H_ #include <setjmp.h> -#include "third_party/utf8_range/utf8_range.h" #include "upb/decode.h" +#include "upb/internal/upb.h" #include "upb/msg_internal.h" -#include "upb/upb_internal.h" +#include "third_party/utf8_range/utf8_range.h" /* Must be last. */ #include "upb/port_def.inc" @@ -208,4 +208,4 @@ UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr, #include "upb/port_undef.inc" -#endif /* UPB_DECODE_INT_H_ */ +#endif /* UPB_INTERNAL_DECODE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/table_internal.h b/contrib/libs/grpc/third_party/upb/upb/internal/table.h index 9fb2d238cd..bc647be83f 100644 --- a/contrib/libs/grpc/third_party/upb/upb/table_internal.h +++ b/contrib/libs/grpc/third_party/upb/upb/internal/table.h @@ -44,8 +44,8 @@ * mode, we check this on insert and lookup. */ -#ifndef UPB_TABLE_H_ -#define UPB_TABLE_H_ +#ifndef UPB_INTERNAL_TABLE_H_ +#define UPB_INTERNAL_TABLE_H_ #include <stdint.h> #include <string.h> @@ -215,8 +215,8 @@ UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) { void upb_strtable_clear(upb_strtable* t); /* Inserts the given key into the hashtable with the given value. The key must - * not already exist in the hash table. For string tables, the key must be - * NULL-terminated, and the table will make an internal copy of the key. + * not already exist in the hash table. For strtables, the key is not required + * to be NULL-terminated, and the table will make an internal copy of the key. * Inttables must not insert a value of UINTPTR_MAX. * * If a table resize was required but memory allocation failed, false is @@ -374,10 +374,12 @@ void upb_inttable_iter_setdone(upb_inttable_iter* i); bool upb_inttable_iter_isequal(const upb_inttable_iter* i1, const upb_inttable_iter* i2); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); + #ifdef __cplusplus } /* extern "C" */ #endif #include "upb/port_undef.inc" -#endif /* UPB_TABLE_H_ */ +#endif /* UPB_INTERNAL_TABLE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/upb_internal.h b/contrib/libs/grpc/third_party/upb/upb/internal/upb.h index 1eb166f7d3..cdc8bfc228 100644 --- a/contrib/libs/grpc/third_party/upb/upb/upb_internal.h +++ b/contrib/libs/grpc/third_party/upb/upb/internal/upb.h @@ -25,8 +25,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef UPB_INT_H_ -#define UPB_INT_H_ +#ifndef UPB_INTERNAL_UPB_H_ +#define UPB_INTERNAL_UPB_H_ #include "upb/upb.h" @@ -65,4 +65,4 @@ enum { kUpb_RoundTripBufferSize = 32 }; void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size); void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size); -#endif /* UPB_INT_H_ */ +#endif /* UPB_INTERNAL_UPB_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/internal/vsnprintf_compat.h b/contrib/libs/grpc/third_party/upb/upb/internal/vsnprintf_compat.h new file mode 100644 index 0000000000..a9d84bb6fe --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/internal/vsnprintf_compat.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_INTERNAL_VSNPRINTF_COMPAT_H_ +#define UPB_INTERNAL_VSNPRINTF_COMPAT_H_ + +#include <stdio.h> + +// Must be last. +#include "upb/port_def.inc" + +UPB_INLINE int _upb_vsnprintf(char* buf, size_t size, const char* fmt, + va_list ap) { +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + // The msvc runtime has a non-conforming vsnprintf() that requires the + // following compatibility code to become conformant. + int n = -1; + if (size != 0) n = _vsnprintf_s(buf, size, _TRUNCATE, fmt, ap); + if (n == -1) n = _vscprintf(fmt, ap); + return n; +#else + return vsnprintf(buf, size, fmt, ap); +#endif +} + +#include "upb/port_undef.inc" + +#endif // UPB_INTERNAL_VSNPRINTF_COMPAT_H_ diff --git a/contrib/libs/grpc/third_party/upb/upb/json_decode.c b/contrib/libs/grpc/third_party/upb/upb/json_decode.c new file mode 100644 index 0000000000..4f79294ef8 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/json_decode.c @@ -0,0 +1,1512 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/json_decode.h" + +#include <errno.h> +#include <float.h> +#include <inttypes.h> +#include <limits.h> +#include <math.h> +#include <setjmp.h> +#include <stdlib.h> +#include <string.h> + +#include "upb/encode.h" +#include "upb/reflection.h" + +/* Special header, must be included last. */ +#include "upb/port_def.inc" + +typedef struct { + const char *ptr, *end; + upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ + const upb_DefPool* symtab; + int depth; + upb_Status* status; + jmp_buf err; + int line; + const char* line_begin; + bool is_first; + int options; + const upb_FieldDef* debug_field; +} jsondec; + +enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; + +/* Forward declarations of mutually-recursive functions. */ +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m); + +static bool jsondec_streql(upb_StringView str, const char* lit) { + return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; +} + +static bool jsondec_isnullvalue(const upb_FieldDef* f) { + return upb_FieldDef_CType(f) == kUpb_CType_Enum && + strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), + "google.protobuf.NullValue") == 0; +} + +static bool jsondec_isvalue(const upb_FieldDef* f) { + return (upb_FieldDef_CType(f) == kUpb_CType_Message && + upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == + kUpb_WellKnown_Value) || + jsondec_isnullvalue(f); +} + +UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, + (int)(d->ptr - d->line_begin), msg); + UPB_LONGJMP(d->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, + (int)(d->ptr - d->line_begin)); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +static void jsondec_skipws(jsondec* d) { + while (d->ptr != d->end) { + switch (*d->ptr) { + case '\n': + d->line++; + d->line_begin = d->ptr; + /* Fallthrough. */ + case '\r': + case '\t': + case ' ': + d->ptr++; + break; + default: + return; + } + } + jsondec_err(d, "Unexpected EOF"); +} + +static bool jsondec_tryparsech(jsondec* d, char ch) { + if (d->ptr == d->end || *d->ptr != ch) return false; + d->ptr++; + return true; +} + +static void jsondec_parselit(jsondec* d, const char* lit) { + size_t avail = d->end - d->ptr; + size_t len = strlen(lit); + if (avail < len || memcmp(d->ptr, lit, len) != 0) { + jsondec_errf(d, "Expected: '%s'", lit); + } + d->ptr += len; +} + +static void jsondec_wsch(jsondec* d, char ch) { + jsondec_skipws(d); + if (!jsondec_tryparsech(d, ch)) { + jsondec_errf(d, "Expected: '%c'", ch); + } +} + +static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } +static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } +static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } + +static void jsondec_entrysep(jsondec* d) { + jsondec_skipws(d); + jsondec_parselit(d, ":"); +} + +static int jsondec_rawpeek(jsondec* d) { + switch (*d->ptr) { + case '{': + return JD_OBJECT; + case '[': + return JD_ARRAY; + case '"': + return JD_STRING; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return JD_NUMBER; + case 't': + return JD_TRUE; + case 'f': + return JD_FALSE; + case 'n': + return JD_NULL; + default: + jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); + } +} + +/* JSON object/array **********************************************************/ + +/* These are used like so: + * + * jsondec_objstart(d); + * while (jsondec_objnext(d)) { + * ... + * } + * jsondec_objend(d) */ + +static int jsondec_peek(jsondec* d) { + jsondec_skipws(d); + return jsondec_rawpeek(d); +} + +static void jsondec_push(jsondec* d) { + if (--d->depth < 0) { + jsondec_err(d, "Recursion limit exceeded"); + } + d->is_first = true; +} + +static bool jsondec_seqnext(jsondec* d, char end_ch) { + bool is_first = d->is_first; + d->is_first = false; + jsondec_skipws(d); + if (*d->ptr == end_ch) return false; + if (!is_first) jsondec_parselit(d, ","); + return true; +} + +static void jsondec_arrstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '['); +} + +static void jsondec_arrend(jsondec* d) { + d->depth++; + jsondec_wsch(d, ']'); +} + +static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } + +static void jsondec_objstart(jsondec* d) { + jsondec_push(d); + jsondec_wsch(d, '{'); +} + +static void jsondec_objend(jsondec* d) { + d->depth++; + jsondec_wsch(d, '}'); +} + +static bool jsondec_objnext(jsondec* d) { + if (!jsondec_seqnext(d, '}')) return false; + if (jsondec_peek(d) != JD_STRING) { + jsondec_err(d, "Object must start with string"); + } + return true; +} + +/* JSON number ****************************************************************/ + +static bool jsondec_tryskipdigits(jsondec* d) { + const char* start = d->ptr; + + while (d->ptr < d->end) { + if (*d->ptr < '0' || *d->ptr > '9') { + break; + } + d->ptr++; + } + + return d->ptr != start; +} + +static void jsondec_skipdigits(jsondec* d) { + if (!jsondec_tryskipdigits(d)) { + jsondec_err(d, "Expected one or more digits"); + } +} + +static double jsondec_number(jsondec* d) { + const char* start = d->ptr; + + assert(jsondec_rawpeek(d) == JD_NUMBER); + + /* Skip over the syntax of a number, as specified by JSON. */ + if (*d->ptr == '-') d->ptr++; + + if (jsondec_tryparsech(d, '0')) { + if (jsondec_tryskipdigits(d)) { + jsondec_err(d, "number cannot have leading zero"); + } + } else { + jsondec_skipdigits(d); + } + + if (d->ptr == d->end) goto parse; + if (jsondec_tryparsech(d, '.')) { + jsondec_skipdigits(d); + } + if (d->ptr == d->end) goto parse; + + if (*d->ptr == 'e' || *d->ptr == 'E') { + d->ptr++; + if (d->ptr == d->end) { + jsondec_err(d, "Unexpected EOF in number"); + } + if (*d->ptr == '+' || *d->ptr == '-') { + d->ptr++; + } + jsondec_skipdigits(d); + } + +parse: + /* Having verified the syntax of a JSON number, use strtod() to parse + * (strtod() accepts a superset of JSON syntax). */ + errno = 0; + { + char* end; + double val = strtod(start, &end); + assert(end == d->ptr); + + /* Currently the min/max-val conformance tests fail if we check this. Does + * this mean the conformance tests are wrong or strtod() is wrong, or + * something else? Investigate further. */ + /* + if (errno == ERANGE) { + jsondec_err(d, "Number out of range"); + } + */ + + if (val > DBL_MAX || val < -DBL_MAX) { + jsondec_err(d, "Number out of range"); + } + + return val; + } +} + +/* JSON string ****************************************************************/ + +static char jsondec_escape(jsondec* d) { + switch (*d->ptr++) { + case '"': + return '\"'; + case '\\': + return '\\'; + case '/': + return '/'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + default: + jsondec_err(d, "Invalid escape char"); + } +} + +static uint32_t jsondec_codepoint(jsondec* d) { + uint32_t cp = 0; + const char* end; + + if (d->end - d->ptr < 4) { + jsondec_err(d, "EOF inside string"); + } + + end = d->ptr + 4; + while (d->ptr < end) { + char ch = *d->ptr++; + if (ch >= '0' && ch <= '9') { + ch -= '0'; + } else if (ch >= 'a' && ch <= 'f') { + ch = ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + ch = ch - 'A' + 10; + } else { + jsondec_err(d, "Invalid hex digit"); + } + cp = (cp << 4) | ch; + } + + return cp; +} + +/* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ +static size_t jsondec_unicode(jsondec* d, char* out) { + uint32_t cp = jsondec_codepoint(d); + if (cp >= 0xd800 && cp <= 0xdbff) { + /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ + uint32_t high = cp; + uint32_t low; + jsondec_parselit(d, "\\u"); + low = jsondec_codepoint(d); + if (low < 0xdc00 || low > 0xdfff) { + jsondec_err(d, "Invalid low surrogate"); + } + cp = (high & 0x3ff) << 10; + cp |= (low & 0x3ff); + cp += 0x10000; + } else if (cp >= 0xdc00 && cp <= 0xdfff) { + jsondec_err(d, "Unpaired low surrogate"); + } + + /* Write to UTF-8 */ + if (cp <= 0x7f) { + out[0] = cp; + return 1; + } else if (cp <= 0x07FF) { + out[0] = ((cp >> 6) & 0x1F) | 0xC0; + out[1] = ((cp >> 0) & 0x3F) | 0x80; + return 2; + } else if (cp <= 0xFFFF) { + out[0] = ((cp >> 12) & 0x0F) | 0xE0; + out[1] = ((cp >> 6) & 0x3F) | 0x80; + out[2] = ((cp >> 0) & 0x3F) | 0x80; + return 3; + } else if (cp < 0x10FFFF) { + out[0] = ((cp >> 18) & 0x07) | 0xF0; + out[1] = ((cp >> 12) & 0x3f) | 0x80; + out[2] = ((cp >> 6) & 0x3f) | 0x80; + out[3] = ((cp >> 0) & 0x3f) | 0x80; + return 4; + } else { + jsondec_err(d, "Invalid codepoint"); + } +} + +static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { + size_t oldsize = *buf_end - *buf; + size_t len = *end - *buf; + size_t size = UPB_MAX(8, 2 * oldsize); + + *buf = upb_Arena_Realloc(d->arena, *buf, len, size); + if (!*buf) jsondec_err(d, "Out of memory"); + + *end = *buf + len; + *buf_end = *buf + size; +} + +static upb_StringView jsondec_string(jsondec* d) { + char* buf = NULL; + char* end = NULL; + char* buf_end = NULL; + + jsondec_skipws(d); + + if (*d->ptr++ != '"') { + jsondec_err(d, "Expected string"); + } + + while (d->ptr < d->end) { + char ch = *d->ptr++; + + if (end == buf_end) { + jsondec_resize(d, &buf, &end, &buf_end); + } + + switch (ch) { + case '"': { + upb_StringView ret; + ret.data = buf; + ret.size = end - buf; + *end = '\0'; /* Needed for possible strtod(). */ + return ret; + } + case '\\': + if (d->ptr == d->end) goto eof; + if (*d->ptr == 'u') { + d->ptr++; + if (buf_end - end < 4) { + /* Allow space for maximum-sized code point (4 bytes). */ + jsondec_resize(d, &buf, &end, &buf_end); + } + end += jsondec_unicode(d, end); + } else { + *end++ = jsondec_escape(d); + } + break; + default: + if ((unsigned char)*d->ptr < 0x20) { + jsondec_err(d, "Invalid char in JSON string"); + } + *end++ = ch; + break; + } + } + +eof: + jsondec_err(d, "EOF inside string"); +} + +static void jsondec_skipval(jsondec* d) { + switch (jsondec_peek(d)) { + case JD_OBJECT: + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_string(d); + jsondec_entrysep(d); + jsondec_skipval(d); + } + jsondec_objend(d); + break; + case JD_ARRAY: + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + jsondec_skipval(d); + } + jsondec_arrend(d); + break; + case JD_TRUE: + jsondec_true(d); + break; + case JD_FALSE: + jsondec_false(d); + break; + case JD_NULL: + jsondec_null(d); + break; + case JD_STRING: + jsondec_string(d); + break; + case JD_NUMBER: + jsondec_number(d); + break; + } +} + +/* Base64 decoding for bytes fields. ******************************************/ + +static unsigned int jsondec_base64_tablelookup(const char ch) { + /* Table includes the normal base64 chars plus the URL-safe variant. */ + const signed char table[256] = { + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, + 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, + 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, + -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, + 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, + 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, + 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, + -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, + 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, + 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, + 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, + 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + + /* Sign-extend return value so high bit will be set on any unexpected char. */ + return table[(unsigned)ch]; +} + +static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, + char* out) { + int32_t val = -1; + + switch (end - ptr) { + case 2: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12; + out[0] = val >> 16; + out += 1; + break; + case 3: + val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6; + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out += 2; + break; + } + + if (val < 0) { + jsondec_err(d, "Corrupt base64"); + } + + return out; +} + +static size_t jsondec_base64(jsondec* d, upb_StringView str) { + /* We decode in place. This is safe because this is a new buffer (not + * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ + char* out = (char*)str.data; + const char* ptr = str.data; + const char* end = ptr + str.size; + const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ + + for (; ptr < end4; ptr += 4, out += 3) { + int val = jsondec_base64_tablelookup(ptr[0]) << 18 | + jsondec_base64_tablelookup(ptr[1]) << 12 | + jsondec_base64_tablelookup(ptr[2]) << 6 | + jsondec_base64_tablelookup(ptr[3]) << 0; + + if (val < 0) { + /* Junk chars or padding. Remove trailing padding, if any. */ + if (end - ptr == 4 && ptr[3] == '=') { + if (ptr[2] == '=') { + end -= 2; + } else { + end -= 1; + } + } + break; + } + + out[0] = val >> 16; + out[1] = (val >> 8) & 0xff; + out[2] = val & 0xff; + } + + if (ptr < end) { + /* Process remaining chars. We do not require padding. */ + out = jsondec_partialbase64(d, ptr, end, out); + } + + return out - str.data; +} + +/* Low-level integer parsing **************************************************/ + +/* We use these hand-written routines instead of strto[u]l() because the "long + * long" variants aren't in c89. Also our version allows setting a ptr limit. */ + +static const char* jsondec_buftouint64(jsondec* d, const char* ptr, + const char* end, uint64_t* val) { + uint64_t u64 = 0; + while (ptr < end) { + unsigned ch = *ptr - '0'; + if (ch >= 10) break; + if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { + jsondec_err(d, "Integer overflow"); + } + u64 *= 10; + u64 += ch; + ptr++; + } + + *val = u64; + return ptr; +} + +static const char* jsondec_buftoint64(jsondec* d, const char* ptr, + const char* end, int64_t* val) { + bool neg = false; + uint64_t u64; + + if (ptr != end && *ptr == '-') { + ptr++; + neg = true; + } + + ptr = jsondec_buftouint64(d, ptr, end, &u64); + if (u64 > (uint64_t)INT64_MAX + neg) { + jsondec_err(d, "Integer overflow"); + } + + *val = neg ? -u64 : u64; + return ptr; +} + +static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + uint64_t ret; + if (jsondec_buftouint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { + const char* end = str.data + str.size; + int64_t ret; + if (jsondec_buftoint64(d, str.data, end, &ret) != end) { + jsondec_err(d, "Non-number characters in quoted integer"); + } + return ret; +} + +/* Primitive value types ******************************************************/ + +/* Parse INT32 or INT64 value. */ +static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { + jsondec_err(d, "JSON number is out of range."); + } + val.int64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.int64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, + val.int64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.int64_val = jsondec_strtoint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || + upb_FieldDef_CType(f) == kUpb_CType_Enum) { + if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { + jsondec_err(d, "Integer out of range."); + } + val.int32_val = (int32_t)val.int64_val; + } + + return val; +} + +/* Parse UINT32 or UINT64 value. */ +static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val = {0}; + + switch (jsondec_peek(d)) { + case JD_NUMBER: { + double dbl = jsondec_number(d); + if (dbl > 18446744073709549568.0 || dbl < 0) { + jsondec_err(d, "JSON number is out of range."); + } + val.uint64_val = dbl; /* must be guarded, overflow here is UB */ + if (val.uint64_val != dbl) { + jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, + val.uint64_val); + } + break; + } + case JD_STRING: { + upb_StringView str = jsondec_string(d); + val.uint64_val = jsondec_strtouint64(d, str); + break; + } + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { + if (val.uint64_val > UINT32_MAX) { + jsondec_err(d, "Integer out of range."); + } + val.uint32_val = (uint32_t)val.uint64_val; + } + + return val; +} + +/* Parse DOUBLE or FLOAT value. */ +static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { + upb_StringView str; + upb_MessageValue val = {0}; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + val.double_val = jsondec_number(d); + break; + case JD_STRING: + str = jsondec_string(d); + if (jsondec_streql(str, "NaN")) { + val.double_val = NAN; + } else if (jsondec_streql(str, "Infinity")) { + val.double_val = INFINITY; + } else if (jsondec_streql(str, "-Infinity")) { + val.double_val = -INFINITY; + } else { + val.double_val = strtod(str.data, NULL); + } + break; + default: + jsondec_err(d, "Expected number or string"); + } + + if (upb_FieldDef_CType(f) == kUpb_CType_Float) { + if (val.double_val != INFINITY && val.double_val != -INFINITY && + (val.double_val > FLT_MAX || val.double_val < -FLT_MAX)) { + jsondec_err(d, "Float out of range"); + } + val.float_val = val.double_val; + } + + return val; +} + +/* Parse STRING or BYTES value. */ +static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { + upb_MessageValue val; + val.str_val = jsondec_string(d); + if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { + val.str_val.size = jsondec_base64(d, val.str_val); + } + return val; +} + +static upb_MessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { + switch (jsondec_peek(d)) { + case JD_STRING: { + upb_StringView str = jsondec_string(d); + const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); + const upb_EnumValueDef* ev = + upb_EnumDef_FindValueByNameWithSize(e, str.data, str.size); + upb_MessageValue val; + if (ev) { + val.int32_val = upb_EnumValueDef_Number(ev); + } else { + if (d->options & upb_JsonDecode_IgnoreUnknown) { + val.int32_val = 0; + } else { + jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", + UPB_STRINGVIEW_ARGS(str)); + } + } + return val; + } + case JD_NULL: { + if (jsondec_isnullvalue(f)) { + upb_MessageValue val; + jsondec_null(d); + val.int32_val = 0; + return val; + } + } + /* Fallthrough. */ + default: + return jsondec_int(d, f); + } +} + +static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { + bool is_map_key = upb_FieldDef_Number(f) == 1 && + upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); + upb_MessageValue val; + + if (is_map_key) { + upb_StringView str = jsondec_string(d); + if (jsondec_streql(str, "true")) { + val.bool_val = true; + } else if (jsondec_streql(str, "false")) { + val.bool_val = false; + } else { + jsondec_err(d, "Invalid boolean map key"); + } + } else { + switch (jsondec_peek(d)) { + case JD_TRUE: + val.bool_val = true; + jsondec_true(d); + break; + case JD_FALSE: + val.bool_val = false; + jsondec_false(d); + break; + default: + jsondec_err(d, "Expected true or false"); + } + } + + return val; +} + +/* Composite types (array/message/map) ****************************************/ + +static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_MessageValue elem = jsondec_value(d, f); + upb_Array_Append(arr, elem, d->arena); + } + jsondec_arrend(d); +} + +static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { + upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, val; + key = jsondec_value(d, key_f); + jsondec_entrysep(d); + val = jsondec_value(d, val_f); + upb_Map_Set(map, key, val, d->arena); + } + jsondec_objend(d); +} + +static void jsondec_tomsg(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + jsondec_object(d, msg, m); + } else { + jsondec_wellknown(d, msg, m); + } +} + +static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { + const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); + upb_Message* msg = upb_Message_New(m, d->arena); + upb_MessageValue val; + + jsondec_tomsg(d, msg, m); + val.msg_val = msg; + return val; +} + +static void jsondec_field(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_StringView name; + const upb_FieldDef* f; + const upb_FieldDef* preserved; + + name = jsondec_string(d); + jsondec_entrysep(d); + + if (name.size >= 2 && name.data[0] == '[' && + name.data[name.size - 1] == ']') { + f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, + name.size - 2); + if (f && upb_FieldDef_ContainingType(f) != m) { + jsondec_errf( + d, "Extension %s extends message %s, but was seen in message %s", + upb_FieldDef_FullName(f), + upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), + upb_MessageDef_FullName(m)); + } + } else { + f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); + } + + if (!f) { + if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { + jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(name)); + } + jsondec_skipval(d); + return; + } + + if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { + /* JSON "null" indicates a default value, so no need to set anything. */ + jsondec_null(d); + return; + } + + if (upb_FieldDef_RealContainingOneof(f) && + upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { + jsondec_err(d, "More than one field for this oneof."); + } + + preserved = d->debug_field; + d->debug_field = f; + + if (upb_FieldDef_IsMap(f)) { + jsondec_map(d, msg, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsondec_array(d, msg, f); + } else if (upb_FieldDef_IsSubMessage(f)) { + upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; + const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); + jsondec_tomsg(d, submsg, subm); + } else { + upb_MessageValue val = jsondec_value(d, f); + upb_Message_Set(msg, f, val, d->arena); + } + + d->debug_field = preserved; +} + +static void jsondec_object(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + jsondec_objstart(d); + while (jsondec_objnext(d)) { + jsondec_field(d, msg, m); + } + jsondec_objend(d); +} + +static upb_MessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + return jsondec_bool(d, f); + case kUpb_CType_Float: + case kUpb_CType_Double: + return jsondec_double(d, f); + case kUpb_CType_UInt32: + case kUpb_CType_UInt64: + return jsondec_uint(d, f); + case kUpb_CType_Int32: + case kUpb_CType_Int64: + return jsondec_int(d, f); + case kUpb_CType_String: + case kUpb_CType_Bytes: + return jsondec_strfield(d, f); + case kUpb_CType_Enum: + return jsondec_enum(d, f); + case kUpb_CType_Message: + return jsondec_msg(d, f); + default: + UPB_UNREACHABLE(); + } +} + +/* Well-known types ***********************************************************/ + +static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, + const char* after) { + uint64_t val; + const char* p = *ptr; + const char* end = p + digits; + size_t after_len = after ? strlen(after) : 0; + + UPB_ASSERT(digits <= 9); /* int can't overflow. */ + + if (jsondec_buftouint64(d, p, end, &val) != end || + (after_len && memcmp(end, after, after_len) != 0)) { + jsondec_err(d, "Malformed timestamp"); + } + + UPB_ASSERT(val < INT_MAX); + + *ptr = end + after_len; + return (int)val; +} + +static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { + uint64_t nanos = 0; + const char* p = *ptr; + + if (p != end && *p == '.') { + const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); + int digits = (int)(nano_end - p - 1); + int exp_lg10 = 9 - digits; + if (digits > 9) { + jsondec_err(d, "Too many digits for partial seconds"); + } + while (exp_lg10--) nanos *= 10; + *ptr = nano_end; + } + + UPB_ASSERT(nanos < INT_MAX); + + return (int)nanos; +} + +/* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ +int jsondec_epochdays(int y, int m, int d) { + const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ + const uint32_t m_adj = m - 3; /* March-based month. */ + const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; + const uint32_t adjust = carry ? 12 : 0; + const uint32_t y_adj = y + year_base - carry; + const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; + const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; + return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; +} + +static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { + return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; +} + +static void jsondec_timestamp(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + + if (str.size < 20) goto malformed; + + { + /* 1972-01-01T01:00:00 */ + int year = jsondec_tsdigits(d, &ptr, 4, "-"); + int mon = jsondec_tsdigits(d, &ptr, 2, "-"); + int day = jsondec_tsdigits(d, &ptr, 2, "T"); + int hour = jsondec_tsdigits(d, &ptr, 2, ":"); + int min = jsondec_tsdigits(d, &ptr, 2, ":"); + int sec = jsondec_tsdigits(d, &ptr, 2, NULL); + + seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); + } + + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + { + /* [+-]08:00 or Z */ + int ofs_hour = 0; + int ofs_min = 0; + bool neg = false; + + if (ptr == end) goto malformed; + + switch (*ptr++) { + case '-': + neg = true; + /* fallthrough */ + case '+': + if ((end - ptr) != 5) goto malformed; + ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); + ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); + ofs_min = ((ofs_hour * 60) + ofs_min) * 60; + seconds.int64_val += (neg ? ofs_min : -ofs_min); + break; + case 'Z': + if (ptr != end) goto malformed; + break; + default: + goto malformed; + } + } + + if (seconds.int64_val < -62135596800) { + jsondec_err(d, "Timestamp out of range"); + } + + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); + return; + +malformed: + jsondec_err(d, "Malformed timestamp"); +} + +static void jsondec_duration(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue seconds; + upb_MessageValue nanos; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + const int64_t max = (uint64_t)3652500 * 86400; + + /* "3.000000001s", "3s", etc. */ + ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val); + nanos.int32_val = jsondec_nanos(d, &ptr, end); + + if (end - ptr != 1 || *ptr != 's') { + jsondec_err(d, "Malformed duration"); + } + + if (seconds.int64_val < -max || seconds.int64_val > max) { + jsondec_err(d, "Duration out of range"); + } + + if (seconds.int64_val < 0) { + nanos.int32_val = -nanos.int32_val; + } + + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 1), seconds, + d->arena); + upb_Message_Set(msg, upb_MessageDef_FindFieldByNumber(m, 2), nanos, d->arena); +} + +static void jsondec_listvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); + upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; + + jsondec_arrstart(d); + while (jsondec_arrnext(d)) { + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + upb_MessageValue value; + value.msg_val = value_msg; + upb_Array_Append(values, value, d->arena); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_arrend(d); +} + +static void jsondec_struct(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); + upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; + + jsondec_objstart(d); + while (jsondec_objnext(d)) { + upb_MessageValue key, value; + upb_Message* value_msg = upb_Message_New(value_m, d->arena); + key.str_val = jsondec_string(d); + value.msg_val = value_msg; + upb_Map_Set(fields, key, value, d->arena); + jsondec_entrysep(d); + jsondec_wellknownvalue(d, value_msg, value_m); + } + jsondec_objend(d); +} + +static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + upb_MessageValue val; + const upb_FieldDef* f; + upb_Message* submsg; + + switch (jsondec_peek(d)) { + case JD_NUMBER: + /* double number_value = 2; */ + f = upb_MessageDef_FindFieldByNumber(m, 2); + val.double_val = jsondec_number(d); + break; + case JD_STRING: + /* string string_value = 3; */ + f = upb_MessageDef_FindFieldByNumber(m, 3); + val.str_val = jsondec_string(d); + break; + case JD_FALSE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = false; + jsondec_false(d); + break; + case JD_TRUE: + /* bool bool_value = 4; */ + f = upb_MessageDef_FindFieldByNumber(m, 4); + val.bool_val = true; + jsondec_true(d); + break; + case JD_NULL: + /* NullValue null_value = 1; */ + f = upb_MessageDef_FindFieldByNumber(m, 1); + val.int32_val = 0; + jsondec_null(d); + break; + /* Note: these cases return, because upb_Message_Mutable() is enough. */ + case JD_OBJECT: + /* Struct struct_value = 5; */ + f = upb_MessageDef_FindFieldByNumber(m, 5); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + case JD_ARRAY: + /* ListValue list_value = 6; */ + f = upb_MessageDef_FindFieldByNumber(m, 6); + submsg = upb_Message_Mutable(msg, f, d->arena).msg; + jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); + return; + default: + UPB_UNREACHABLE(); + } + + upb_Message_Set(msg, f, val, d->arena); +} + +static upb_StringView jsondec_mask(jsondec* d, const char* buf, + const char* end) { + /* FieldMask fields grow due to inserted '_' characters, so we can't do the + * transform in place. */ + const char* ptr = buf; + upb_StringView ret; + char* out; + + ret.size = end - ptr; + while (ptr < end) { + ret.size += (*ptr >= 'A' && *ptr <= 'Z'); + ptr++; + } + + out = upb_Arena_Malloc(d->arena, ret.size); + ptr = buf; + ret.data = out; + + while (ptr < end) { + char ch = *ptr++; + if (ch >= 'A' && ch <= 'Z') { + *out++ = '_'; + *out++ = ch + 32; + } else if (ch == '_') { + jsondec_err(d, "field mask may not contain '_'"); + } else { + *out++ = ch; + } + } + + return ret; +} + +static void jsondec_fieldmask(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + /* repeated string paths = 1; */ + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; + upb_StringView str = jsondec_string(d); + const char* ptr = str.data; + const char* end = ptr + str.size; + upb_MessageValue val; + + while (ptr < end) { + const char* elem_end = memchr(ptr, ',', end - ptr); + if (elem_end) { + val.str_val = jsondec_mask(d, ptr, elem_end); + ptr = elem_end + 1; + } else { + val.str_val = jsondec_mask(d, ptr, end); + ptr = end; + } + upb_Array_Append(arr, val, d->arena); + } +} + +static void jsondec_anyfield(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { + /* For regular types: {"@type": "[user type]", "f1": <V1>, "f2": <V2>} + * where f1, f2, etc. are the normal fields of this type. */ + jsondec_field(d, msg, m); + } else { + /* For well-known types: {"@type": "[well-known type]", "value": <X>} + * where <X> is whatever encoding the WKT normally uses. */ + upb_StringView str = jsondec_string(d); + jsondec_entrysep(d); + if (!jsondec_streql(str, "value")) { + jsondec_err(d, "Key for well-known type must be 'value'"); + } + jsondec_wellknown(d, msg, m); + } +} + +static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* type_m; + upb_StringView type_url = jsondec_string(d); + const char* end = type_url.data + type_url.size; + const char* ptr = end; + upb_MessageValue val; + + val.str_val = type_url; + upb_Message_Set(msg, type_url_f, val, d->arena); + + /* Find message name after the last '/' */ + while (ptr > type_url.data && *--ptr != '/') { + } + + if (ptr == type_url.data || ptr == end) { + jsondec_err(d, "Type url must have at least one '/' and non-empty host"); + } + + ptr++; + type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); + + if (!type_m) { + jsondec_err(d, "Type was not found"); + } + + return type_m; +} + +static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { + /* string type_url = 1; + * bytes value = 2; */ + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_Message* any_msg; + const upb_MessageDef* any_m = NULL; + const char* pre_type_data = NULL; + const char* pre_type_end = NULL; + upb_MessageValue encoded; + + jsondec_objstart(d); + + /* Scan looking for "@type", which is not necessarily first. */ + while (!any_m && jsondec_objnext(d)) { + const char* start = d->ptr; + upb_StringView name = jsondec_string(d); + jsondec_entrysep(d); + if (jsondec_streql(name, "@type")) { + any_m = jsondec_typeurl(d, msg, m); + if (pre_type_data) { + pre_type_end = start; + while (*pre_type_end != ',') pre_type_end--; + } + } else { + if (!pre_type_data) pre_type_data = start; + jsondec_skipval(d); + } + } + + if (!any_m) { + jsondec_err(d, "Any object didn't contain a '@type' field"); + } + + any_msg = upb_Message_New(any_m, d->arena); + + if (pre_type_data) { + size_t len = pre_type_end - pre_type_data + 1; + char* tmp = upb_Arena_Malloc(d->arena, len); + const char* saved_ptr = d->ptr; + const char* saved_end = d->end; + memcpy(tmp, pre_type_data, len - 1); + tmp[len - 1] = '}'; + d->ptr = tmp; + d->end = tmp + len; + d->is_first = true; + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + d->ptr = saved_ptr; + d->end = saved_end; + } + + while (jsondec_objnext(d)) { + jsondec_anyfield(d, any_msg, any_m); + } + + jsondec_objend(d); + + upb_EncodeStatus status = + upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, + (char**)&encoded.str_val.data, &encoded.str_val.size); + // TODO(b/235839510): We should fail gracefully here on a bad return status. + UPB_ASSERT(status == kUpb_EncodeStatus_Ok); + upb_Message_Set(msg, value_f, encoded, d->arena); +} + +static void jsondec_wrapper(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = jsondec_value(d, value_f); + upb_Message_Set(msg, value_f, val, d->arena); +} + +static void jsondec_wellknown(jsondec* d, upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Any: + jsondec_any(d, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsondec_fieldmask(d, msg, m); + break; + case kUpb_WellKnown_Duration: + jsondec_duration(d, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsondec_timestamp(d, msg, m); + break; + case kUpb_WellKnown_Value: + jsondec_wellknownvalue(d, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsondec_listvalue(d, msg, m); + break; + case kUpb_WellKnown_Struct: + jsondec_struct(d, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsondec_wrapper(d, msg, m); + break; + default: + UPB_UNREACHABLE(); + } +} + +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status) { + jsondec d; + + if (size == 0) return true; + + d.ptr = buf; + d.end = buf + size; + d.arena = arena; + d.symtab = symtab; + d.status = status; + d.options = options; + d.depth = 64; + d.line = 1; + d.line_begin = d.ptr; + d.debug_field = NULL; + d.is_first = false; + + if (UPB_SETJMP(d.err)) return false; + + jsondec_tomsg(&d, msg, m); + return true; +} diff --git a/contrib/libs/grpc/third_party/upb/upb/json_decode.h b/contrib/libs/grpc/third_party/upb/upb/json_decode.h new file mode 100644 index 0000000000..848f4df33c --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/json_decode.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_JSONDECODE_H_ +#define UPB_JSONDECODE_H_ + +#include "upb/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { upb_JsonDecode_IgnoreUnknown = 1 }; + +bool upb_JsonDecode(const char* buf, size_t size, upb_Message* msg, + const upb_MessageDef* m, const upb_DefPool* symtab, + int options, upb_Arena* arena, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_JSONDECODE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/json_encode.c b/contrib/libs/grpc/third_party/upb/upb/json_encode.c new file mode 100644 index 0000000000..e13c0f771d --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/json_encode.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/json_encode.h" + +#include <ctype.h> +#include <float.h> +#include <inttypes.h> +#include <math.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "upb/decode.h" +#include "upb/internal/upb.h" +#include "upb/internal/vsnprintf_compat.h" +#include "upb/reflection.h" + +/* Must be last. */ +#include "upb/port_def.inc" + +typedef struct { + char *buf, *ptr, *end; + size_t overflow; + int indent_depth; + int options; + const upb_DefPool* ext_pool; + jmp_buf err; + upb_Status* status; + upb_Arena* arena; +} jsonenc; + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f); +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first); +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m); + +UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { + upb_Status_SetErrorMessage(e->status, msg); + longjmp(e->err, 1); +} + +UPB_PRINTF(2, 3) +UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { + va_list argp; + va_start(argp, fmt); + upb_Status_VSetErrorFormat(e->status, fmt, argp); + va_end(argp); + longjmp(e->err, 1); +} + +static upb_Arena* jsonenc_arena(jsonenc* e) { + /* Create lazily, since it's only needed for Any */ + if (!e->arena) { + e->arena = upb_Arena_New(); + } + return e->arena; +} + +static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { + size_t have = e->end - e->ptr; + if (UPB_LIKELY(have >= len)) { + memcpy(e->ptr, data, len); + e->ptr += len; + } else { + if (have) { + memcpy(e->ptr, data, have); + e->ptr += have; + } + e->overflow += (len - have); + } +} + +static void jsonenc_putstr(jsonenc* e, const char* str) { + jsonenc_putbytes(e, str, strlen(str)); +} + +UPB_PRINTF(2, 3) +static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { + size_t n; + size_t have = e->end - e->ptr; + va_list args; + + va_start(args, fmt); + n = _upb_vsnprintf(e->ptr, have, fmt, args); + va_end(args); + + if (UPB_LIKELY(have > n)) { + e->ptr += n; + } else { + e->ptr = UPB_PTRADD(e->ptr, have); + e->overflow += (n - have); + } +} + +static void jsonenc_nanos(jsonenc* e, int32_t nanos) { + int digits = 9; + + if (nanos == 0) return; + if (nanos < 0 || nanos >= 1000000000) { + jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); + } + + while (nanos % 1000 == 0) { + nanos /= 1000; + digits -= 3; + } + + jsonenc_printf(e, ".%.*" PRId32, digits, nanos); +} + +static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + int L, N, I, J, K, hour, min, sec; + + if (seconds < -62135596800) { + jsonenc_err(e, + "error formatting timestamp as JSON: minimum acceptable value " + "is 0001-01-01T00:00:00Z"); + } else if (seconds > 253402300799) { + jsonenc_err(e, + "error formatting timestamp as JSON: maximum acceptable value " + "is 9999-12-31T23:59:59Z"); + } + + /* Julian Day -> Y/M/D, Algorithm from: + * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for + * Processing Calendar Dates," Communications of the Association of + * Computing Machines, vol. 11 (1968), p. 657. */ + seconds += 62135596800; // Ensure seconds is positive. + L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; + N = 4 * L / 146097; + L = L - (146097 * N + 3) / 4; + I = 4000 * (L + 1) / 1461001; + L = L - 1461 * I / 4 + 31; + J = 80 * L / 2447; + K = L - 2447 * J / 80; + L = J / 11; + J = J + 2 - 12 * L; + I = 100 * (N - 49) + I + L; + + sec = seconds % 60; + min = (seconds / 60) % 60; + hour = (seconds / 3600) % 24; + + jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "Z\""); +} + +static void jsonenc_duration(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); + int64_t seconds = upb_Message_Get(msg, seconds_f).int64_val; + int32_t nanos = upb_Message_Get(msg, nanos_f).int32_val; + + if (seconds > 315576000000 || seconds < -315576000000 || + (seconds < 0) != (nanos < 0)) { + jsonenc_err(e, "bad duration"); + } + + if (nanos < 0) { + nanos = -nanos; + } + + jsonenc_printf(e, "\"%" PRId64, seconds); + jsonenc_nanos(e, nanos); + jsonenc_putstr(e, "s\""); +} + +static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { + const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); + + if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { + jsonenc_putstr(e, "null"); + } else { + const upb_EnumValueDef* ev = + (e->options & upb_JsonEncode_FormatEnumsAsIntegers) + ? NULL + : upb_EnumDef_FindValueByNumber(e_def, val); + + if (ev) { + jsonenc_printf(e, "\"%s\"", upb_EnumValueDef_Name(ev)); + } else { + jsonenc_printf(e, "%" PRId32, val); + } + } +} + +static void jsonenc_bytes(jsonenc* e, upb_StringView str) { + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const unsigned char* ptr = (unsigned char*)str.data; + const unsigned char* end = UPB_PTRADD(ptr, str.size); + char buf[4]; + + jsonenc_putstr(e, "\""); + + while (end - ptr >= 3) { + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; + buf[3] = base64[ptr[2] & 0x3f]; + jsonenc_putbytes(e, buf, 4); + ptr += 3; + } + + switch (end - ptr) { + case 2: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; + buf[2] = base64[(ptr[1] & 0xf) << 2]; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + case 1: + buf[0] = base64[ptr[0] >> 2]; + buf[1] = base64[((ptr[0] & 0x3) << 4)]; + buf[2] = '='; + buf[3] = '='; + jsonenc_putbytes(e, buf, 4); + break; + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { + const char* ptr = str.data; + const char* end = UPB_PTRADD(ptr, str.size); + + while (ptr < end) { + switch (*ptr) { + case '\n': + jsonenc_putstr(e, "\\n"); + break; + case '\r': + jsonenc_putstr(e, "\\r"); + break; + case '\t': + jsonenc_putstr(e, "\\t"); + break; + case '\"': + jsonenc_putstr(e, "\\\""); + break; + case '\f': + jsonenc_putstr(e, "\\f"); + break; + case '\b': + jsonenc_putstr(e, "\\b"); + break; + case '\\': + jsonenc_putstr(e, "\\\\"); + break; + default: + if ((uint8_t)*ptr < 0x20) { + jsonenc_printf(e, "\\u%04x", (int)(uint8_t)*ptr); + } else { + /* This could be a non-ASCII byte. We rely on the string being valid + * UTF-8. */ + jsonenc_putbytes(e, ptr, 1); + } + break; + } + ptr++; + } +} + +static void jsonenc_string(jsonenc* e, upb_StringView str) { + jsonenc_putstr(e, "\""); + jsonenc_stringbody(e, str); + jsonenc_putstr(e, "\""); +} + +static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { + if (val == INFINITY) { + jsonenc_putstr(e, "\"Infinity\""); + } else if (val == -INFINITY) { + jsonenc_putstr(e, "\"-Infinity\""); + } else if (val != val) { + jsonenc_putstr(e, "\"NaN\""); + } else { + return false; + } + return true; +} + +static void upb_JsonEncode_Double(jsonenc* e, double val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void upb_JsonEncode_Float(jsonenc* e, float val) { + if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; + char buf[32]; + _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); + jsonenc_putstr(e, buf); +} + +static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); + upb_MessageValue val = upb_Message_Get(msg, val_f); + jsonenc_scalar(e, val, val_f); +} + +static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, + upb_StringView type_url) { + /* Find last '/', if any. */ + const char* end = type_url.data + type_url.size; + const char* ptr = end; + const upb_MessageDef* ret; + + if (!e->ext_pool) { + jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); + } + + if (type_url.size == 0) goto badurl; + + while (true) { + if (--ptr == type_url.data) { + /* Type URL must contain at least one '/', with host before. */ + goto badurl; + } + if (*ptr == '/') { + ptr++; + break; + } + } + + ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); + + if (!ret) { + jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); + } + + return ret; + +badurl: + jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, + UPB_STRINGVIEW_ARGS(type_url)); +} + +static void jsonenc_any(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); + upb_StringView type_url = upb_Message_Get(msg, type_url_f).str_val; + upb_StringView value = upb_Message_Get(msg, value_f).str_val; + const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); + const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); + upb_Arena* arena = jsonenc_arena(e); + upb_Message* any = upb_Message_New(any_m, arena); + + if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != + kUpb_DecodeStatus_Ok) { + jsonenc_err(e, "Error decoding message in Any"); + } + + jsonenc_putstr(e, "{\"@type\":"); + jsonenc_string(e, type_url); + + if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { + /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ + jsonenc_msgfields(e, any, any_m, false); + } else { + /* Well-known type: {"@type": "...","value": <well-known encoding>} */ + jsonenc_putstr(e, ",\"value\":"); + jsonenc_msgfield(e, any, any_m); + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { + if (*first) { + *first = false; + } else { + jsonenc_putstr(e, str); + } +} + +static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { + const char* ptr = path.data; + const char* end = ptr + path.size; + + while (ptr < end) { + char ch = *ptr; + + if (ch >= 'A' && ch <= 'Z') { + jsonenc_err(e, "Field mask element may not have upper-case letter."); + } else if (ch == '_') { + if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { + jsonenc_err(e, "Underscore must be followed by a lowercase letter."); + } + ch = *++ptr - 32; + } + + jsonenc_putbytes(e, &ch, 1); + ptr++; + } +} + +static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Array* paths = upb_Message_Get(msg, paths_f).array_val; + bool first = true; + size_t i, n = 0; + + if (paths) n = upb_Array_Size(paths); + + jsonenc_putstr(e, "\""); + + for (i = 0; i < n; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); + } + + jsonenc_putstr(e, "\""); +} + +static void jsonenc_struct(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_Map* fields = upb_Message_Get(msg, fields_f).map_val; + const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); + const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (fields) { + while (upb_MapIterator_Next(fields, &iter)) { + upb_MessageValue key = upb_MapIterator_Key(fields, iter); + upb_MessageValue val = upb_MapIterator_Value(fields, iter); + + jsonenc_putsep(e, ",", &first); + jsonenc_string(e, key.str_val); + jsonenc_putstr(e, ":"); + jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); + const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); + const upb_Array* values = upb_Message_Get(msg, values_f).array_val; + size_t i; + bool first = true; + + jsonenc_putstr(e, "["); + + if (values) { + const size_t size = upb_Array_Size(values); + for (i = 0; i < size; i++) { + upb_MessageValue elem = upb_Array_Get(values, i); + + jsonenc_putsep(e, ",", &first); + jsonenc_value(e, elem.msg_val, values_m); + } + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_value(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + /* TODO(haberman): do we want a reflection method to get oneof case? */ + size_t iter = kUpb_Message_Begin; + const upb_FieldDef* f; + upb_MessageValue val; + + if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { + jsonenc_err(e, "No value set in Value proto"); + } + + switch (upb_FieldDef_Number(f)) { + case 1: + jsonenc_putstr(e, "null"); + break; + case 2: + upb_JsonEncode_Double(e, val.double_val); + break; + case 3: + jsonenc_string(e, val.str_val); + break; + case 4: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case 5: + jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + case 6: + jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + switch (upb_MessageDef_WellKnownType(m)) { + case kUpb_WellKnown_Unspecified: + jsonenc_msg(e, msg, m); + break; + case kUpb_WellKnown_Any: + jsonenc_any(e, msg, m); + break; + case kUpb_WellKnown_FieldMask: + jsonenc_fieldmask(e, msg, m); + break; + case kUpb_WellKnown_Duration: + jsonenc_duration(e, msg, m); + break; + case kUpb_WellKnown_Timestamp: + jsonenc_timestamp(e, msg, m); + break; + case kUpb_WellKnown_DoubleValue: + case kUpb_WellKnown_FloatValue: + case kUpb_WellKnown_Int64Value: + case kUpb_WellKnown_UInt64Value: + case kUpb_WellKnown_Int32Value: + case kUpb_WellKnown_UInt32Value: + case kUpb_WellKnown_StringValue: + case kUpb_WellKnown_BytesValue: + case kUpb_WellKnown_BoolValue: + jsonenc_wrapper(e, msg, m); + break; + case kUpb_WellKnown_Value: + jsonenc_value(e, msg, m); + break; + case kUpb_WellKnown_ListValue: + jsonenc_listvalue(e, msg, m); + break; + case kUpb_WellKnown_Struct: + jsonenc_struct(e, msg, m); + break; + } +} + +static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Float: + upb_JsonEncode_Float(e, val.float_val); + break; + case kUpb_CType_Double: + upb_JsonEncode_Double(e, val.double_val); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_string(e, val.str_val); + break; + case kUpb_CType_Bytes: + jsonenc_bytes(e, val.str_val); + break; + case kUpb_CType_Enum: + jsonenc_enum(val.int32_val, f, e); + break; + case kUpb_CType_Message: + jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); + break; + } +} + +static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, + const upb_FieldDef* f) { + jsonenc_putstr(e, "\""); + + switch (upb_FieldDef_CType(f)) { + case kUpb_CType_Bool: + jsonenc_putstr(e, val.bool_val ? "true" : "false"); + break; + case kUpb_CType_Int32: + jsonenc_printf(e, "%" PRId32, val.int32_val); + break; + case kUpb_CType_UInt32: + jsonenc_printf(e, "%" PRIu32, val.uint32_val); + break; + case kUpb_CType_Int64: + jsonenc_printf(e, "%" PRId64, val.int64_val); + break; + case kUpb_CType_UInt64: + jsonenc_printf(e, "%" PRIu64, val.uint64_val); + break; + case kUpb_CType_String: + jsonenc_stringbody(e, val.str_val); + break; + default: + UPB_UNREACHABLE(); + } + + jsonenc_putstr(e, "\":"); +} + +static void jsonenc_array(jsonenc* e, const upb_Array* arr, + const upb_FieldDef* f) { + size_t i; + size_t size = arr ? upb_Array_Size(arr) : 0; + bool first = true; + + jsonenc_putstr(e, "["); + + for (i = 0; i < size; i++) { + jsonenc_putsep(e, ",", &first); + jsonenc_scalar(e, upb_Array_Get(arr, i), f); + } + + jsonenc_putstr(e, "]"); +} + +static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { + const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); + const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); + const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); + size_t iter = kUpb_Map_Begin; + bool first = true; + + jsonenc_putstr(e, "{"); + + if (map) { + while (upb_MapIterator_Next(map, &iter)) { + jsonenc_putsep(e, ",", &first); + jsonenc_mapkey(e, upb_MapIterator_Key(map, iter), key_f); + jsonenc_scalar(e, upb_MapIterator_Value(map, iter), val_f); + } + } + + jsonenc_putstr(e, "}"); +} + +static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, + upb_MessageValue val, bool* first) { + const char* name; + + jsonenc_putsep(e, ",", first); + + if (upb_FieldDef_IsExtension(f)) { + // TODO: For MessageSet, I would have expected this to print the message + // name here, but Python doesn't appear to do this. We should do more + // research here about what various implementations do. + jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); + } else { + if (e->options & upb_JsonEncode_UseProtoNames) { + name = upb_FieldDef_Name(f); + } else { + name = upb_FieldDef_JsonName(f); + } + jsonenc_printf(e, "\"%s\":", name); + } + + if (upb_FieldDef_IsMap(f)) { + jsonenc_map(e, val.map_val, f); + } else if (upb_FieldDef_IsRepeated(f)) { + jsonenc_array(e, val.array_val, f); + } else { + jsonenc_scalar(e, val, f); + } +} + +static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m, bool first) { + upb_MessageValue val; + const upb_FieldDef* f; + + if (e->options & upb_JsonEncode_EmitDefaults) { + /* Iterate over all fields. */ + int i = 0; + int n = upb_MessageDef_FieldCount(m); + for (i = 0; i < n; i++) { + f = upb_MessageDef_Field(m, i); + if (!upb_FieldDef_HasPresence(f) || upb_Message_Has(msg, f)) { + jsonenc_fieldval(e, f, upb_Message_Get(msg, f), &first); + } + } + } else { + /* Iterate over non-empty fields. */ + size_t iter = kUpb_Message_Begin; + while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { + jsonenc_fieldval(e, f, val, &first); + } + } +} + +static void jsonenc_msg(jsonenc* e, const upb_Message* msg, + const upb_MessageDef* m) { + jsonenc_putstr(e, "{"); + jsonenc_msgfields(e, msg, m, true); + jsonenc_putstr(e, "}"); +} + +static size_t jsonenc_nullz(jsonenc* e, size_t size) { + size_t ret = e->ptr - e->buf + e->overflow; + + if (size > 0) { + if (e->ptr == e->end) e->ptr--; + *e->ptr = '\0'; + } + + return ret; +} + +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status) { + jsonenc e; + + e.buf = buf; + e.ptr = buf; + e.end = UPB_PTRADD(buf, size); + e.overflow = 0; + e.options = options; + e.ext_pool = ext_pool; + e.status = status; + e.arena = NULL; + + if (setjmp(e.err)) return -1; + + jsonenc_msgfield(&e, msg, m); + if (e.arena) upb_Arena_Free(e.arena); + return jsonenc_nullz(&e, size); +} diff --git a/contrib/libs/grpc/third_party/upb/upb/json_encode.h b/contrib/libs/grpc/third_party/upb/upb/json_encode.h new file mode 100644 index 0000000000..6e0cac3fc1 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/json_encode.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_JSONENCODE_H_ +#define UPB_JSONENCODE_H_ + +#include "upb/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* When set, emits 0/default values. TODO(haberman): proto3 only? */ + upb_JsonEncode_EmitDefaults = 1 << 0, + + /* When set, use normal (snake_case) field names instead of JSON (camelCase) + names. */ + upb_JsonEncode_UseProtoNames = 1 << 1, + + /* When set, emits enums as their integer values instead of as their names. */ + upb_JsonEncode_FormatEnumsAsIntegers = 1 << 2 +}; + +/* Encodes the given |msg| to JSON format. The message's reflection is given in + * |m|. The symtab in |symtab| is used to find extensions (if NULL, extensions + * will not be printed). + * + * Output is placed in the given buffer, and always NULL-terminated. The output + * size (excluding NULL) is returned. This means that a return value >= |size| + * implies that the output was truncated. (These are the same semantics as + * snprintf()). */ +size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, + const upb_DefPool* ext_pool, int options, char* buf, + size_t size, upb_Status* status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_JSONENCODE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/map.c b/contrib/libs/grpc/third_party/upb/upb/map.c new file mode 100644 index 0000000000..d92776f546 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/map.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/map.h" + +#include <string.h> + +#include "upb/internal/table.h" +#include "upb/msg.h" +#include "upb/port_def.inc" + +/* Strings/bytes are special-cased in maps. */ +static char _upb_CTypeo_mapsize[12] = { + 0, + 1, /* kUpb_CType_Bool */ + 4, /* kUpb_CType_Float */ + 4, /* kUpb_CType_Int32 */ + 4, /* kUpb_CType_UInt32 */ + 4, /* kUpb_CType_Enum */ + sizeof(void*), /* kUpb_CType_Message */ + 8, /* kUpb_CType_Double */ + 8, /* kUpb_CType_Int64 */ + 8, /* kUpb_CType_UInt64 */ + 0, /* kUpb_CType_String */ + 0, /* kUpb_CType_Bytes */ +}; + +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { + return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], + _upb_CTypeo_mapsize[value_type]); +} + +size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } + +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val) { + return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); +} + +void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } + +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, + map->val_size, arena); +} + +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { + return _upb_Map_Delete(map, &key, map->key_size); +} + +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { + return _upb_map_next(map, iter); +} + +bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + UPB_ASSERT(iter != kUpb_Map_Begin); + i.t = &map->table; + i.index = iter; + return upb_strtable_done(&i); +} + +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); + return ret; +} + +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { + upb_strtable_iter i; + upb_MessageValue ret; + i.t = &map->table; + i.index = iter; + _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); + return ret; +} + +/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue + * value); */ diff --git a/contrib/libs/grpc/third_party/upb/upb/map.h b/contrib/libs/grpc/third_party/upb/upb/map.h new file mode 100644 index 0000000000..8ee0ddd05e --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/map.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_MAP_H_ +#define UPB_MAP_H_ + +#include "google/protobuf/descriptor.upb.h" +#include "upb/message_value.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Creates a new map on the given arena with the given key/value size. */ +upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); + +/* Returns the number of entries in the map. */ +size_t upb_Map_Size(const upb_Map* map); + +/* Stores a value for the given key into |*val| (or the zero value if the key is + * not present). Returns whether the key was present. The |val| pointer may be + * NULL, in which case the function tests whether the given key is present. */ +bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, + upb_MessageValue* val); + +/* Removes all entries in the map. */ +void upb_Map_Clear(upb_Map* map); + +typedef enum { + // LINT.IfChange + kUpb_MapInsertStatus_Inserted = 0, + kUpb_MapInsertStatus_Replaced = 1, + kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h) +} upb_MapInsertStatus; + +/* Sets the given key to the given value, returning whether the key was inserted + * or replaced. If the key was inserted, then any existing iterators will be + * invalidated. */ +upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena); + +/* Sets the given key to the given value. Returns false if memory allocation + * failed. If the key is newly inserted, then any existing iterators will be + * invalidated. */ +UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key, + upb_MessageValue val, upb_Arena* arena) { + return upb_Map_Insert(map, key, val, arena) != + kUpb_MapInsertStatus_OutOfMemory; +} + +/* Deletes this key from the table. Returns true if the key was present. */ +bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); + +/* Map iteration: + * + * size_t iter = kUpb_Map_Begin; + * while (upb_MapIterator_Next(map, &iter)) { + * upb_MessageValue key = upb_MapIterator_Key(map, iter); + * upb_MessageValue val = upb_MapIterator_Value(map, iter); + * + * // If mutating is desired. + * upb_MapIterator_SetValue(map, iter, value2); + * } + */ + +/* Advances to the next entry. Returns false if no more entries are present. */ +bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); + +/* Returns true if the iterator still points to a valid entry, or false if the + * iterator is past the last element. It is an error to call this function with + * kUpb_Map_Begin (you must call next() at least once first). */ +bool upb_MapIterator_Done(const upb_Map* map, size_t iter); + +/* Returns the key and value for this entry of the map. */ +upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); +upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); + +/* Sets the value for this entry. The iterator must not be done, and the + * iterator must not have been initialized const. */ +void upb_MapIterator_SetValue(upb_Map* map, size_t iter, + upb_MessageValue value); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_MAP_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/message_value.h b/contrib/libs/grpc/third_party/upb/upb/message_value.h new file mode 100644 index 0000000000..a08b90fc1e --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/message_value.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_MESSAGE_VALUE_H_ +#define UPB_MESSAGE_VALUE_H_ + +#include "google/protobuf/descriptor.upb.h" +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +// Definitions commn to both upb_Array and upb_Map. + +typedef union { + bool bool_val; + float float_val; + double double_val; + int32_t int32_val; + int64_t int64_val; + uint32_t uint32_val; + uint64_t uint64_val; + const upb_Map* map_val; + const upb_Message* msg_val; + const upb_Array* array_val; + upb_StringView str_val; +} upb_MessageValue; + +typedef union { + upb_Map* map; + upb_Message* msg; + upb_Array* array; +} upb_MutableMessageValue; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_MESSAGE_VALUE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/mini_table.c b/contrib/libs/grpc/third_party/upb/upb/mini_table.c new file mode 100644 index 0000000000..cd53059738 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/mini_table.c @@ -0,0 +1,1147 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/mini_table.h" + +#include <inttypes.h> +#include <setjmp.h> + +#include "upb/msg_internal.h" +#include "upb/upb.h" + +// Must be last. +#include "upb/port_def.inc" + +typedef enum { + kUpb_EncodedType_Double = 0, + kUpb_EncodedType_Float = 1, + kUpb_EncodedType_Fixed32 = 2, + kUpb_EncodedType_Fixed64 = 3, + kUpb_EncodedType_SFixed32 = 4, + kUpb_EncodedType_SFixed64 = 5, + kUpb_EncodedType_Int32 = 6, + kUpb_EncodedType_UInt32 = 7, + kUpb_EncodedType_SInt32 = 8, + kUpb_EncodedType_Int64 = 9, + kUpb_EncodedType_UInt64 = 10, + kUpb_EncodedType_SInt64 = 11, + kUpb_EncodedType_Enum = 12, + kUpb_EncodedType_Bool = 13, + kUpb_EncodedType_Bytes = 14, + kUpb_EncodedType_String = 15, + kUpb_EncodedType_Group = 16, + kUpb_EncodedType_Message = 17, + + kUpb_EncodedType_RepeatedBase = 20, +} upb_EncodedType; + +typedef enum { + kUpb_EncodedFieldModifier_FlipPacked = 1 << 0, + kUpb_EncodedFieldModifier_IsClosedEnum = 1 << 1, + // upb only. + kUpb_EncodedFieldModifier_IsProto3Singular = 1 << 2, + kUpb_EncodedFieldModifier_IsRequired = 1 << 3, +} upb_EncodedFieldModifier; + +enum { + kUpb_EncodedValue_MinField = ' ', + kUpb_EncodedValue_MaxField = 'K', + kUpb_EncodedValue_MinModifier = 'L', + kUpb_EncodedValue_MaxModifier = '[', + kUpb_EncodedValue_End = '^', + kUpb_EncodedValue_MinSkip = '_', + kUpb_EncodedValue_MaxSkip = '~', + kUpb_EncodedValue_OneofSeparator = '~', + kUpb_EncodedValue_FieldSeparator = '|', + kUpb_EncodedValue_MinOneofField = ' ', + kUpb_EncodedValue_MaxOneofField = 'b', + kUpb_EncodedValue_MaxEnumMask = 'A', +}; + +char upb_ToBase92(int8_t ch) { + static const char kUpb_ToBase92[] = { + ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', + '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', + }; + + UPB_ASSERT(0 <= ch && ch < 92); + return kUpb_ToBase92[ch]; +} + +char upb_FromBase92(uint8_t ch) { + static const int8_t kUpb_FromBase92[] = { + 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + }; + + if (' ' > ch || ch > '~') return -1; + return kUpb_FromBase92[ch - ' ']; +} + +bool upb_IsTypePackable(upb_FieldType type) { + // clang-format off + static const unsigned kUnpackableTypes = + (1 << kUpb_FieldType_String) | + (1 << kUpb_FieldType_Bytes) | + (1 << kUpb_FieldType_Message) | + (1 << kUpb_FieldType_Group); + // clang-format on + return (1 << type) & ~kUnpackableTypes; +} + +/** upb_MtDataEncoder *********************************************************/ + +typedef struct { + uint64_t present_values_mask; + uint32_t last_written_value; +} upb_MtDataEncoderInternal_EnumState; + +typedef struct { + uint64_t msg_modifiers; + uint32_t last_field_num; + enum { + kUpb_OneofState_NotStarted, + kUpb_OneofState_StartedOneof, + kUpb_OneofState_EmittedOneofField, + } oneof_state; +} upb_MtDataEncoderInternal_MsgState; + +typedef struct { + char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. + union { + upb_MtDataEncoderInternal_EnumState enum_state; + upb_MtDataEncoderInternal_MsgState msg_state; + } state; +} upb_MtDataEncoderInternal; + +static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( + upb_MtDataEncoder* e, char* buf_start) { + UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); + upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; + ret->buf_start = buf_start; + return ret; +} + +static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); + if (ptr == e->end) return NULL; + *ptr++ = upb_ToBase92(ch); + return ptr; +} + +static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, + uint32_t val, int min, int max) { + int shift = _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min) + 1); + UPB_ASSERT(shift <= 6); + uint32_t mask = (1 << shift) - 1; + do { + uint32_t bits = val & mask; + ptr = upb_MtDataEncoder_Put(e, ptr, bits + upb_FromBase92(min)); + if (!ptr) return NULL; + val >>= shift; + } while (val); + return ptr; +} + +char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, + uint64_t mod) { + if (mod) { + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier); + } + return ptr; +} + +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + in->state.msg_state.msg_modifiers = msg_mod; + in->state.msg_state.last_field_num = 0; + in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; + return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); +} + +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod) { + static const char kUpb_TypeToEncoded[] = { + [kUpb_FieldType_Double] = kUpb_EncodedType_Double, + [kUpb_FieldType_Float] = kUpb_EncodedType_Float, + [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, + [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, + [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, + [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, + [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, + [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, + [kUpb_FieldType_String] = kUpb_EncodedType_String, + [kUpb_FieldType_Group] = kUpb_EncodedType_Group, + [kUpb_FieldType_Message] = kUpb_EncodedType_Message, + [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, + [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, + [kUpb_FieldType_Enum] = kUpb_EncodedType_Enum, + [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, + [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, + [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, + [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, + }; + + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (field_num <= in->state.msg_state.last_field_num) return NULL; + if (in->state.msg_state.last_field_num + 1 != field_num) { + // Put skip. + UPB_ASSERT(field_num > in->state.msg_state.last_field_num); + uint32_t skip = field_num - in->state.msg_state.last_field_num; + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + if (!ptr) return NULL; + } + in->state.msg_state.last_field_num = field_num; + + uint32_t encoded_modifiers = 0; + + // Put field type. + if (type == kUpb_FieldType_Enum && + !(field_mod & kUpb_FieldModifier_IsClosedEnum)) { + type = kUpb_FieldType_Int32; + } + + int encoded_type = kUpb_TypeToEncoded[type]; + if (field_mod & kUpb_FieldModifier_IsRepeated) { + // Repeated fields shift the type number up (unlike other modifiers which + // are bit flags). + encoded_type += kUpb_EncodedType_RepeatedBase; + + if (upb_IsTypePackable(type)) { + bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; + bool default_is_packed = in->state.msg_state.msg_modifiers & + kUpb_MessageModifier_DefaultIsPacked; + if (field_is_packed != default_is_packed) { + encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; + } + } + } + ptr = upb_MtDataEncoder_Put(e, ptr, encoded_type); + if (!ptr) return NULL; + + if (field_mod & kUpb_FieldModifier_IsProto3Singular) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; + } + if (field_mod & kUpb_FieldModifier_IsRequired) { + encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; + } + return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); +} + +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { + ptr = upb_MtDataEncoder_Put(e, ptr, upb_FromBase92(kUpb_EncodedValue_End)); + } else { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); + } + in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; + return ptr; +} + +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { + ptr = upb_MtDataEncoder_Put( + e, ptr, upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); + if (!ptr) return NULL; + } + ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, upb_ToBase92(0), + upb_ToBase92(63)); + in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; + return ptr; +} + +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, NULL); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value = 0; +} + +static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, + char* ptr) { + upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; + ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); + in->state.enum_state.present_values_mask = 0; + in->state.enum_state.last_written_value += 5; + return ptr; +} + +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val) { + // TODO(b/229641772): optimize this encoding. + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + UPB_ASSERT(val >= in->state.enum_state.last_written_value); + uint32_t delta = val - in->state.enum_state.last_written_value; + if (delta >= 5 && in->state.enum_state.present_values_mask) { + ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); + if (!ptr) { + return NULL; + } + delta -= 5; + } + + if (delta >= 5) { + ptr = upb_MtDataEncoder_PutBase92Varint( + e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); + in->state.enum_state.last_written_value += delta; + delta = 0; + } + + UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); + in->state.enum_state.present_values_mask |= 1ULL << delta; + return ptr; +} + +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { + upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); + if (!in->state.enum_state.present_values_mask) return ptr; + return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); +} + +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number) { + int n = table->field_count; + for (int i = 0; i < n; i++) { + if (table->fields[i].number == number) { + return &table->fields[i]; + } + } + return NULL; +} + +/** Data decoder **************************************************************/ + +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_LayoutItemType_OneofCase, // Oneof case. + kUpb_LayoutItemType_OneofField, // Oneof field data. + kUpb_LayoutItemType_Field, // Non-oneof field data. + + kUpb_LayoutItemType_Max = kUpb_LayoutItemType_Field, +} upb_LayoutItemType; + +#define kUpb_LayoutItem_IndexSentinel ((uint16_t)-1) + +typedef struct { + // Index of the corresponding field. When this is a oneof field, the field's + // offset will be the index of the next field in a linked list. + uint16_t field_index; + uint16_t offset; + upb_FieldRep rep; + upb_LayoutItemType type; +} upb_LayoutItem; + +typedef struct { + upb_LayoutItem* data; + size_t size; + size_t capacity; +} upb_LayoutItemVector; + +typedef struct { + const char* end; + upb_MiniTable* table; + upb_MiniTable_Field* fields; + upb_MiniTablePlatform platform; + upb_LayoutItemVector vec; + upb_Arena* arena; + upb_Status* status; + jmp_buf err; +} upb_MtDecoder; + +UPB_PRINTF(2, 3) +UPB_NORETURN static void upb_MtDecoder_ErrorFormat(upb_MtDecoder* d, + const char* fmt, ...) { + va_list argp; + upb_Status_SetErrorMessage(d->status, "Error building mini table: "); + va_start(argp, fmt); + upb_Status_VAppendErrorFormat(d->status, fmt, argp); + va_end(argp); + UPB_LONGJMP(d->err, 1); +} + +static void upb_MtDecoder_CheckOutOfMemory(upb_MtDecoder* d, const void* ptr) { + if (!ptr) upb_MtDecoder_ErrorFormat(d, "Out of memory"); +} + +// In each field's offset, we temporarily store a presence classifier: +enum PresenceClass { + kNoPresence = 0, + kHasbitPresence = 1, + kRequiredPresence = 2, + kOneofBase = 3, + // Negative values refer to a specific oneof with that number. Positive + // values >= kOneofBase indicate that this field is in a oneof, and specify + // the next field in this oneof's linked list. +}; + +static const char* upb_MiniTable_DecodeBase92Varint(upb_MtDecoder* d, + const char* ptr, + char first_ch, uint8_t min, + uint8_t max, + uint32_t* out_val) { + uint32_t val = 0; + uint32_t shift = 0; + const int bits_per_char = + _upb_Log2Ceiling(upb_FromBase92(max) - upb_FromBase92(min)); + char ch = first_ch; + while (1) { + uint32_t bits = upb_FromBase92(ch) - upb_FromBase92(min); + UPB_ASSERT(shift < 32); + val |= bits << shift; + if (ptr == d->end || *ptr < min || max < *ptr) { + *out_val = val; + return ptr; + } + ch = *ptr++; + shift += bits_per_char; + } +} + +static bool upb_MiniTable_HasSub(upb_MiniTable_Field* field, + uint64_t msg_modifiers) { + switch (field->descriptortype) { + case kUpb_FieldType_Message: + case kUpb_FieldType_Group: + case kUpb_FieldType_Enum: + return true; + case kUpb_FieldType_String: + if (!(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { + field->descriptortype = kUpb_FieldType_Bytes; + } + return false; + default: + return false; + } +} + +static bool upb_MtDecoder_FieldIsPackable(upb_MiniTable_Field* field) { + return (field->mode & kUpb_FieldMode_Array) && + upb_IsTypePackable(field->descriptortype); +} + +static void upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field, + upb_FieldType type, uint32_t* sub_count, + uint64_t msg_modifiers) { + field->descriptortype = type; + if (upb_MiniTable_HasSub(field, msg_modifiers)) { + field->submsg_index = sub_count ? (*sub_count)++ : 0; + } else { + field->submsg_index = kUpb_NoSub; + } + + if (upb_MtDecoder_FieldIsPackable(field) && + (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { + field->mode |= kUpb_LabelFlags_IsPacked; + } +} + +static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, + upb_MiniTable_Field* field, + uint64_t msg_modifiers, + uint32_t* sub_count) { + static const char kUpb_EncodedToFieldRep[] = { + [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, + [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_Group] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Message] = kUpb_FieldRep_Pointer, + [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, + [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_Enum] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, + [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, + [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, + }; + + static const char kUpb_EncodedToType[] = { + [kUpb_EncodedType_Double] = kUpb_FieldType_Double, + [kUpb_EncodedType_Float] = kUpb_FieldType_Float, + [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, + [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, + [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, + [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, + [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, + [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, + [kUpb_EncodedType_String] = kUpb_FieldType_String, + [kUpb_EncodedType_Group] = kUpb_FieldType_Group, + [kUpb_EncodedType_Message] = kUpb_FieldType_Message, + [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, + [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, + [kUpb_EncodedType_Enum] = kUpb_FieldType_Enum, + [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, + [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, + [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, + [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, + }; + + int8_t type = upb_FromBase92(ch); + if (ch >= upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { + type -= kUpb_EncodedType_RepeatedBase; + field->mode = kUpb_FieldMode_Array; + field->mode |= kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift; + field->offset = kNoPresence; + } else { + field->mode = kUpb_FieldMode_Scalar; + field->mode |= kUpb_EncodedToFieldRep[type] << kUpb_FieldRep_Shift; + field->offset = kHasbitPresence; + } + if (type >= 18) { + upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", (int)type); + UPB_UNREACHABLE(); + } + upb_MiniTable_SetTypeAndSub(field, kUpb_EncodedToType[type], sub_count, + msg_modifiers); +} + +static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, + uint32_t message_modifiers, + uint32_t field_modifiers, + upb_MiniTable_Field* field) { + if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { + if (!upb_MtDecoder_FieldIsPackable(field)) { + upb_MtDecoder_ErrorFormat( + d, "Cannot flip packed on unpackable field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + field->mode ^= kUpb_LabelFlags_IsPacked; + } + + bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; + bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; + + // Validate. + if ((singular || required) && field->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, "Invalid modifier(s) for repeated field %" PRIu32, field->number); + UPB_UNREACHABLE(); + } + if (singular && required) { + upb_MtDecoder_ErrorFormat( + d, "Field %" PRIu32 " cannot be both singular and required", + field->number); + UPB_UNREACHABLE(); + } + + if (singular) field->offset = kNoPresence; + if (required) { + field->offset = kRequiredPresence; + } +} + +static void upb_MtDecoder_PushItem(upb_MtDecoder* d, upb_LayoutItem item) { + if (d->vec.size == d->vec.capacity) { + size_t new_cap = UPB_MAX(8, d->vec.size * 2); + d->vec.data = realloc(d->vec.data, new_cap * sizeof(*d->vec.data)); + upb_MtDecoder_CheckOutOfMemory(d, d->vec.data); + d->vec.capacity = new_cap; + } + d->vec.data[d->vec.size++] = item; +} + +static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, upb_LayoutItem item) { + if (item.field_index == kUpb_LayoutItem_IndexSentinel) { + upb_MtDecoder_ErrorFormat(d, "Empty oneof"); + UPB_UNREACHABLE(); + } + item.field_index -= kOneofBase; + + // Push oneof data. + item.type = kUpb_LayoutItemType_OneofField; + upb_MtDecoder_PushItem(d, item); + + // Push oneof case. + item.rep = kUpb_FieldRep_4Byte; // Field Number. + item.type = kUpb_LayoutItemType_OneofCase; + upb_MtDecoder_PushItem(d, item); +} + +size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToSize32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToSize64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 16, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(sizeof(upb_StringView) == + UPB_SIZE(kRepToSize32, kRepToSize64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] + : kRepToSize64[rep]; +} + +size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, + upb_MiniTablePlatform platform) { + static const uint8_t kRepToAlign32[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 4, [kUpb_FieldRep_StringView] = 4, + [kUpb_FieldRep_8Byte] = 8, + }; + static const uint8_t kRepToAlign64[] = { + [kUpb_FieldRep_1Byte] = 1, [kUpb_FieldRep_4Byte] = 4, + [kUpb_FieldRep_Pointer] = 8, [kUpb_FieldRep_StringView] = 8, + [kUpb_FieldRep_8Byte] = 8, + }; + UPB_ASSERT(UPB_ALIGN_OF(upb_StringView) == + UPB_SIZE(kRepToAlign32, kRepToAlign64)[kUpb_FieldRep_StringView]); + return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] + : kRepToAlign64[rep]; +} + +static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, + const char* ptr, + char first_ch, + upb_LayoutItem* item) { + uint32_t field_num; + ptr = upb_MiniTable_DecodeBase92Varint( + d, ptr, first_ch, kUpb_EncodedValue_MinOneofField, + kUpb_EncodedValue_MaxOneofField, &field_num); + upb_MiniTable_Field* f = + (void*)upb_MiniTable_FindFieldByNumber(d->table, field_num); + + if (!f) { + upb_MtDecoder_ErrorFormat(d, + "Couldn't add field number %" PRIu32 + " to oneof, no such field number.", + field_num); + UPB_UNREACHABLE(); + } + if (f->offset != kHasbitPresence) { + upb_MtDecoder_ErrorFormat( + d, + "Cannot add repeated, required, or singular field %" PRIu32 + " to oneof.", + field_num); + UPB_UNREACHABLE(); + } + + // Oneof storage must be large enough to accommodate the largest member. + int rep = f->mode >> kUpb_FieldRep_Shift; + if (upb_MtDecoder_SizeOfRep(rep, d->platform) > + upb_MtDecoder_SizeOfRep(item->rep, d->platform)) { + item->rep = rep; + } + // Prepend this field to the linked list. + f->offset = item->field_index; + item->field_index = (f - d->fields) + kOneofBase; + return ptr; +} + +static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, + const char* ptr) { + upb_LayoutItem item = {.rep = 0, + .field_index = kUpb_LayoutItem_IndexSentinel}; + while (ptr < d->end) { + char ch = *ptr++; + if (ch == kUpb_EncodedValue_FieldSeparator) { + // Field separator, no action needed. + } else if (ch == kUpb_EncodedValue_OneofSeparator) { + // End of oneof. + upb_MtDecoder_PushOneof(d, item); + item.field_index = kUpb_LayoutItem_IndexSentinel; // Move to next oneof. + } else { + ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); + } + } + + // Push final oneof. + upb_MtDecoder_PushOneof(d, item); + return ptr; +} + +static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, + const char* ptr, char first_ch, + upb_MiniTable_Field* last_field, + uint64_t* msg_modifiers) { + uint32_t mod; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, first_ch, + kUpb_EncodedValue_MinModifier, + kUpb_EncodedValue_MaxModifier, &mod); + if (last_field) { + upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); + } else { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have message modifiers"); + UPB_UNREACHABLE(); + } + *msg_modifiers = mod; + } + + return ptr; +} + +static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, uint32_t sub_count) { + size_t subs_bytes = sizeof(*d->table->subs) * sub_count; + d->table->subs = upb_Arena_Malloc(d->arena, subs_bytes); + upb_MtDecoder_CheckOutOfMemory(d, d->table->subs); +} + +static void upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, size_t len, + void* fields, size_t field_size, + uint16_t* field_count, uint32_t* sub_count) { + uint64_t msg_modifiers = 0; + uint32_t last_field_number = 0; + upb_MiniTable_Field* last_field = NULL; + bool need_dense_below = d->table != NULL; + + d->end = UPB_PTRADD(ptr, len); + + while (ptr < d->end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxField) { + upb_MiniTable_Field* field = fields; + *field_count += 1; + fields = (char*)fields + field_size; + field->number = ++last_field_number; + last_field = field; + upb_MiniTable_SetField(d, ch, field, msg_modifiers, sub_count); + } else if (kUpb_EncodedValue_MinModifier <= ch && + ch <= kUpb_EncodedValue_MaxModifier) { + ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); + if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { + d->table->ext |= kUpb_ExtMode_Extendable; + } + } else if (ch == kUpb_EncodedValue_End) { + if (!d->table) { + upb_MtDecoder_ErrorFormat(d, "Extensions cannot have oneofs."); + UPB_UNREACHABLE(); + } + ptr = upb_MtDecoder_DecodeOneofs(d, ptr); + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + need_dense_below = false; + } + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + last_field_number += skip; + last_field_number--; // Next field seen will increment. + } + } + + if (need_dense_below) { + d->table->dense_below = d->table->field_count; + } +} + +static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, + size_t len) { + // Buffer length is an upper bound on the number of fields. We will return + // what we don't use. + d->fields = upb_Arena_Malloc(d->arena, sizeof(*d->fields) * len); + upb_MtDecoder_CheckOutOfMemory(d, d->fields); + + uint32_t sub_count = 0; + d->table->field_count = 0; + d->table->fields = d->fields; + upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), + &d->table->field_count, &sub_count); + + upb_Arena_ShrinkLast(d->arena, d->fields, sizeof(*d->fields) * len, + sizeof(*d->fields) * d->table->field_count); + d->table->fields = d->fields; + upb_MtDecoder_AllocateSubs(d, sub_count); +} + +int upb_MtDecoder_CompareFields(const void* _a, const void* _b) { + const upb_LayoutItem* a = _a; + const upb_LayoutItem* b = _b; + // Currently we just sort by: + // 1. rep (smallest fields first) + // 2. type (oneof cases first) + // 2. field_index (smallest numbers first) + // The main goal of this is to reduce space lost to padding. + // Later we may have more subtle reasons to prefer a different ordering. + const int rep_bits = _upb_Log2Ceiling(kUpb_FieldRep_Max); + const int type_bits = _upb_Log2Ceiling(kUpb_LayoutItemType_Max); + const int idx_bits = (sizeof(a->field_index) * 8); + UPB_ASSERT(idx_bits + rep_bits + type_bits < 32); +#define UPB_COMBINE(rep, ty, idx) (((rep << type_bits) | ty) << idx_bits) | idx + uint32_t a_packed = UPB_COMBINE(a->rep, a->type, a->field_index); + uint32_t b_packed = UPB_COMBINE(b->rep, b->type, b->field_index); + assert(a_packed != b_packed); +#undef UPB_COMBINE + return a_packed < b_packed ? -1 : 1; +} + +static bool upb_MtDecoder_SortLayoutItems(upb_MtDecoder* d) { + // Add items for all non-oneof fields (oneofs were already added). + int n = d->table->field_count; + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* f = &d->fields[i]; + if (f->offset >= kOneofBase) continue; + upb_LayoutItem item = {.field_index = i, + .rep = f->mode >> kUpb_FieldRep_Shift, + .type = kUpb_LayoutItemType_Field}; + upb_MtDecoder_PushItem(d, item); + } + + if (d->vec.size) { + qsort(d->vec.data, d->vec.size, sizeof(*d->vec.data), + upb_MtDecoder_CompareFields); + } + + return true; +} + +static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { + return (n + d - 1) / d; +} + +static void upb_MtDecoder_AssignHasbits(upb_MiniTable* ret) { + int n = ret->field_count; + int last_hasbit = 0; // 0 cannot be used. + + // First assign required fields, which must have the lowest hasbits. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kRequiredPresence) { + field->presence = ++last_hasbit; + } else if (field->offset == kNoPresence) { + field->presence = 0; + } + } + ret->required_count = last_hasbit; + + // Next assign non-required hasbit fields. + for (int i = 0; i < n; i++) { + upb_MiniTable_Field* field = (upb_MiniTable_Field*)&ret->fields[i]; + if (field->offset == kHasbitPresence) { + field->presence = ++last_hasbit; + } + } + + ret->size = last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; +} + +size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { + size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); + size_t align = upb_MtDecoder_AlignOfRep(rep, d->platform); + size_t ret = UPB_ALIGN_UP(d->table->size, align); + d->table->size = ret + size; + return ret; +} + +static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { + upb_LayoutItem* end = UPB_PTRADD(d->vec.data, d->vec.size); + + // Compute offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + item->offset = upb_MtDecoder_Place(d, item->rep); + } + + // Assign oneof case offsets. We must do these first, since assigning + // actual offsets will overwrite the links of the linked list. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + if (item->type != kUpb_LayoutItemType_OneofCase) continue; + upb_MiniTable_Field* f = &d->fields[item->field_index]; + while (true) { + f->presence = ~item->offset; + if (f->offset == kUpb_LayoutItem_IndexSentinel) break; + UPB_ASSERT(f->offset - kOneofBase < d->table->field_count); + f = &d->fields[f->offset - kOneofBase]; + } + } + + // Assign offsets. + for (upb_LayoutItem* item = d->vec.data; item < end; item++) { + upb_MiniTable_Field* f = &d->fields[item->field_index]; + switch (item->type) { + case kUpb_LayoutItemType_OneofField: + while (true) { + uint16_t next_offset = f->offset; + f->offset = item->offset; + if (next_offset == kUpb_LayoutItem_IndexSentinel) break; + f = &d->fields[next_offset - kOneofBase]; + } + break; + case kUpb_LayoutItemType_Field: + f->offset = item->offset; + break; + default: + break; + } + } + + // The fasttable parser (supported on 64-bit only) depends on this being a + // multiple of 8 in order to satisfy UPB_MALLOC_ALIGN, which is also 8. + // + // On 32-bit we could potentially make this smaller, but there is no + // compelling reason to optimize this right now. + d->table->size = UPB_ALIGN_UP(d->table->size, 8); +} + +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, + upb_Status* status) { + upb_MtDecoder decoder = { + .platform = platform, + .vec = + { + .data = *buf, + .capacity = *buf_size / sizeof(*decoder.vec.data), + .size = 0, + }, + .arena = arena, + .status = status, + .table = upb_Arena_Malloc(arena, sizeof(*decoder.table)), + }; + + if (UPB_SETJMP(decoder.err)) { + decoder.table = NULL; + goto done; + } + + upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table); + + decoder.table->size = 0; + decoder.table->field_count = 0; + decoder.table->ext = kUpb_ExtMode_NonExtendable; + decoder.table->dense_below = 0; + decoder.table->table_mask = 0; + decoder.table->required_count = 0; + + upb_MtDecoder_ParseMessage(&decoder, data, len); + upb_MtDecoder_AssignHasbits(decoder.table); + upb_MtDecoder_SortLayoutItems(&decoder); + upb_MtDecoder_AssignOffsets(&decoder); + +done: + *buf = decoder.vec.data; + *buf_size = decoder.vec.capacity / sizeof(*decoder.vec.data); + return decoder.table; +} + +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + if (!ret) return NULL; + + ret->size = 0; + ret->field_count = 0; + ret->ext = kUpb_ExtMode_IsMessageSet; + ret->dense_below = 0; + ret->table_mask = 0; + ret->required_count = 0; + return ret; +} + +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena) { + upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret)); + upb_MiniTable_Field* fields = upb_Arena_Malloc(arena, sizeof(*fields) * 2); + if (!ret || !fields) return NULL; + + upb_MiniTable_Sub* subs = NULL; + if (value_is_proto3_enum) value_type = kUpb_FieldType_Int32; + if (value_type == kUpb_FieldType_Message || + value_type == kUpb_FieldType_Group || value_type == kUpb_FieldType_Enum) { + subs = upb_Arena_Malloc(arena, sizeof(*subs)); + if (!subs) return NULL; + } + + size_t field_size = + upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, platform); + + fields[0].number = 1; + fields[1].number = 2; + fields[0].mode = kUpb_FieldMode_Scalar; + fields[1].mode = kUpb_FieldMode_Scalar; + fields[0].presence = 0; + fields[1].presence = 0; + fields[0].offset = 0; + fields[1].offset = field_size; + + upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0); + upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0); + + ret->size = UPB_ALIGN_UP(2 * field_size, 8); + ret->field_count = 2; + ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry; + ret->dense_below = 2; + ret->table_mask = 0; + ret->required_count = 0; + ret->subs = subs; + ret->fields = fields; + return ret; +} + +static bool upb_MiniTable_BuildEnumValue(upb_MtDecoder* d, + upb_MiniTable_Enum* table, + uint32_t val, upb_Arena* arena) { + if (val < 64) { + table->mask |= 1ULL << val; + return true; + } + + int32_t* values = (void*)table->values; + values = upb_Arena_Realloc(arena, values, table->value_count * 4, + (table->value_count + 1) * 4); + upb_MtDecoder_CheckOutOfMemory(d, values); + values[table->value_count++] = (int32_t)val; + table->values = values; + return true; +} + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status) { + upb_MtDecoder d = { + .status = status, + .end = UPB_PTRADD(data, len), + }; + + if (UPB_SETJMP(d.err)) { + return NULL; + } + + upb_MiniTable_Enum* table = upb_Arena_Malloc(arena, sizeof(*table)); + upb_MtDecoder_CheckOutOfMemory(&d, table); + + table->mask = 0; + table->value_count = 0; + table->values = NULL; + + const char* ptr = data; + uint32_t base = 0; + + while (ptr < d.end) { + char ch = *ptr++; + if (ch <= kUpb_EncodedValue_MaxEnumMask) { + uint32_t mask = upb_FromBase92(ch); + for (int i = 0; i < 5; i++, base++, mask >>= 1) { + if (mask & 1) { + if (!upb_MiniTable_BuildEnumValue(&d, table, base, arena)) { + return NULL; + } + } + } + } else if (kUpb_EncodedValue_MinSkip <= ch && + ch <= kUpb_EncodedValue_MaxSkip) { + uint32_t skip; + ptr = upb_MiniTable_DecodeBase92Varint(&d, ptr, ch, + kUpb_EncodedValue_MinSkip, + kUpb_EncodedValue_MaxSkip, &skip); + base += skip; + } else { + upb_Status_SetErrorFormat(status, "Unexpected character: %c", ch); + return NULL; + } + } + + return table; +} + +bool upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + upb_MiniTable_Sub sub, upb_Status* status) { + upb_MtDecoder decoder = { + .arena = NULL, + .status = status, + .table = NULL, + }; + + if (UPB_SETJMP(decoder.err)) { + return false; + } + + uint16_t count = 0; + upb_MtDecoder_Parse(&decoder, data, len, ext, sizeof(*ext), &count, NULL); + ext->field.mode |= kUpb_LabelFlags_IsExtension; + ext->field.offset = 0; + return true; +} + +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status) { + void* buf = NULL; + size_t size = 0; + upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, + &buf, &size, status); + free(buf); + return ret; +} + +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + if (sub->ext & kUpb_ExtMode_IsMapEntry) { + field->mode = + (kUpb_FieldRep_Pointer << kUpb_FieldRep_Shift) | kUpb_FieldMode_Map; + } + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->submsg = sub; +} + +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub) { + UPB_ASSERT((uintptr_t)table->fields <= (uintptr_t)field && + (uintptr_t)field < + (uintptr_t)(table->fields + table->field_count)); + upb_MiniTable_Sub* table_sub = (void*)&table->subs[field->submsg_index]; + table_sub->subenum = sub; +} diff --git a/contrib/libs/grpc/third_party/upb/upb/mini_table.h b/contrib/libs/grpc/third_party/upb/upb/mini_table.h new file mode 100644 index 0000000000..6c41f810eb --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/mini_table.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2009-2022, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_MINI_TABLE_H_ +#define UPB_MINI_TABLE_H_ + +#include "upb/msg_internal.h" + +// Must be last. +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( + const upb_MiniTable* table, uint32_t number); + +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].submsg; +} + +UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, + int32_t val) { + uint32_t uval = (uint32_t)val; + if (uval < 64) return e->mask & (1ULL << uval); + // OPT: binary search long lists? + int n = e->value_count; + for (int i = 0; i < n; i++) { + if (e->values[i] == val) return true; + } + return false; +} + +/** upb_MtDataEncoder *********************************************************/ + +// Functions to encode a string in a format that can be loaded by +// upb_MiniTable_Build(). + +typedef enum { + kUpb_MessageModifier_ValidateUtf8 = 1 << 0, + kUpb_MessageModifier_DefaultIsPacked = 1 << 1, + kUpb_MessageModifier_IsExtendable = 1 << 2, +} kUpb_MessageModifier; + +typedef enum { + kUpb_FieldModifier_IsRepeated = 1 << 0, + kUpb_FieldModifier_IsPacked = 1 << 1, + kUpb_FieldModifier_IsClosedEnum = 1 << 2, + kUpb_FieldModifier_IsProto3Singular = 1 << 3, + kUpb_FieldModifier_IsRequired = 1 << 4, +} kUpb_FieldModifier; + +typedef struct { + char* end; // Limit of the buffer passed as a parameter. + // Aliased to internal-only members in .cc. + char internal[32]; +} upb_MtDataEncoder; + +// If the input buffer has at least this many bytes available, the encoder call +// is guaranteed to succeed (as long as field number order is maintained). +#define kUpb_MtDataEncoder_MinSize 16 + +// Encodes field/oneof information for a given message. The sequence of calls +// should look like: +// +// upb_MtDataEncoder e; +// char buf[256]; +// char* ptr = buf; +// e.end = ptr + sizeof(buf); +// ptr = upb_MtDataEncoder_StartMessage(&e, ptr); +// // Fields *must* be in field number order. +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// ptr = upb_MtDataEncoder_PutField(&e, ptr, ...); +// +// // If oneofs are present. Oneofs must be encoded after regular fields. +// ptr = upb_MiniTable_StartOneof(&e, ptr) +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// ptr = upb_MiniTable_StartOneof(&e, ptr); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// ptr = upb_MiniTable_PutOneofField(&e, ptr, ...); +// +// Oneofs must be encoded after all regular fields. +char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, + uint64_t msg_mod); +char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, + upb_FieldType type, uint32_t field_num, + uint64_t field_mod); +char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr); +char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, + uint32_t field_num); + +// Encodes the set of values for a given enum. The values must be given in +// order (after casting to uint32_t), and repeats are not allowed. +void upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e); +char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, + uint32_t val); +char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr); + +/** upb_MiniTable *************************************************************/ + +typedef enum { + kUpb_MiniTablePlatform_32Bit, + kUpb_MiniTablePlatform_64Bit, + kUpb_MiniTablePlatform_Native = + UPB_SIZE(kUpb_MiniTablePlatform_32Bit, kUpb_MiniTablePlatform_64Bit), +} upb_MiniTablePlatform; + +// Builds a mini table from the data encoded in the buffer [data, len]. If any +// errors occur, returns NULL and sets a status message. In the success case, +// the caller must call upb_MiniTable_SetSub*() for all message or proto2 enum +// fields to link the table to the appropriate sub-tables. +upb_MiniTable* upb_MiniTable_Build(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, upb_Status* status); +void upb_MiniTable_SetSubMessage(upb_MiniTable* table, + upb_MiniTable_Field* field, + const upb_MiniTable* sub); +void upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTable_Field* field, + const upb_MiniTable_Enum* sub); + +bool upb_MiniTable_BuildExtension(const char* data, size_t len, + upb_MiniTable_Extension* ext, + upb_MiniTable_Sub sub, upb_Status* status); + +// Special-case functions for MessageSet layout and map entries. +upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform, + upb_Arena* arena); +upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type, + upb_FieldType value_type, + bool value_is_proto3_enum, + upb_MiniTablePlatform platform, + upb_Arena* arena); + +upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len, + upb_Arena* arena, + upb_Status* status); + +// Like upb_MiniTable_Build(), but the user provides a buffer of layout data so +// it can be reused from call to call, avoiding repeated realloc()/free(). +// +// The caller owns `*buf` both before and after the call, and must free() it +// when it is no longer in use. The function will realloc() `*buf` as +// necessary, updating `*size` accordingly. +upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, + upb_MiniTablePlatform platform, + upb_Arena* arena, void** buf, + size_t* buf_size, upb_Status* status); + +// For testing only. +char upb_ToBase92(int8_t ch); +char upb_FromBase92(uint8_t ch); +bool upb_IsTypePackable(upb_FieldType type); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port_undef.inc" + +#endif /* UPB_MINI_TABLE_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/msg.c b/contrib/libs/grpc/third_party/upb/upb/msg.c index 3734fc5491..036c62199d 100644 --- a/contrib/libs/grpc/third_party/upb/upb/msg.c +++ b/contrib/libs/grpc/third_party/upb/upb/msg.c @@ -27,12 +27,11 @@ #include "upb/msg.h" +#include "upb/internal/table.h" #include "upb/msg_internal.h" #include "upb/port_def.inc" -#include "upb/table_internal.h" -/** upb_Message - * *******************************************************************/ +/** upb_Message ***************************************************************/ static const size_t overhead = sizeof(upb_Message_InternalData); @@ -55,7 +54,7 @@ static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { upb_Message_Internal* in = upb_Message_Getinternal(msg); if (!in->internal) { /* No internal data, allocate from scratch. */ - size_t size = UPB_MAX(128, _upb_Log2Ceilingsize(need + overhead)); + size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead)); upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size); if (!internal) return false; internal->size = size; @@ -64,7 +63,7 @@ static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) { in->internal = internal; } else if (in->internal->ext_begin - in->internal->unknown_end < need) { /* Internal data is too small, reallocate. */ - size_t new_size = _upb_Log2Ceilingsize(in->internal->size + need); + size_t new_size = _upb_Log2CeilingSize(in->internal->size + need); size_t ext_bytes = in->internal->size - in->internal->ext_begin; size_t new_ext_begin = new_size - ext_bytes; upb_Message_InternalData* internal = @@ -154,7 +153,7 @@ void _upb_Message_Clearext(upb_Message* msg, } } -upb_Message_Extension* _upb_Message_Getorcreateext( +upb_Message_Extension* _upb_Message_GetOrCreateExtension( upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) { upb_Message_Extension* ext = (upb_Message_Extension*)_upb_Message_Getext(msg, e); @@ -310,7 +309,7 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, /* Grow s->entries if necessary. */ if (sorted->end > s->cap) { - s->cap = _upb_Log2Ceilingsize(sorted->end); + s->cap = _upb_Log2CeilingSize(sorted->end); s->entries = realloc(s->entries, s->cap * sizeof(*s->entries)); if (!s->entries) return false; } @@ -367,64 +366,3 @@ bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar); return true; } - -/** upb_ExtensionRegistry - * ****************************************************************/ - -struct upb_ExtensionRegistry { - upb_Arena* arena; - upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */ -}; - -#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t)) - -static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) { - memcpy(buf, &l, sizeof(l)); - memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum)); -} - -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { - upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); - if (!r) return NULL; - r->arena = arena; - if (!upb_strtable_init(&r->exts, 8, arena)) return NULL; - return r; -} - -bool _upb_extreg_add(upb_ExtensionRegistry* r, - const upb_MiniTable_Extension** e, size_t count) { - char buf[EXTREG_KEY_SIZE]; - const upb_MiniTable_Extension** start = e; - const upb_MiniTable_Extension** end = UPB_PTRADD(e, count); - for (; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE, - upb_value_constptr(ext), r->arena)) { - goto failure; - } - } - return true; - -failure: - /* Back out the entries previously added. */ - for (end = e, e = start; e < end; e++) { - const upb_MiniTable_Extension* ext = *e; - extreg_key(buf, ext->extendee, ext->field.number); - upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL); - } - return false; -} - -const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, - const upb_MiniTable* l, - uint32_t num) { - char buf[EXTREG_KEY_SIZE]; - upb_value v; - extreg_key(buf, l, num); - if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) { - return upb_value_getconstptr(v); - } else { - return NULL; - } -} diff --git a/contrib/libs/grpc/third_party/upb/upb/msg.h b/contrib/libs/grpc/third_party/upb/upb/msg.h index 99928393ae..5c1e8e8931 100644 --- a/contrib/libs/grpc/third_party/upb/upb/msg.h +++ b/contrib/libs/grpc/third_party/upb/upb/msg.h @@ -38,15 +38,14 @@ #include <stddef.h> +// TODO(b/232091617): Remove this and fix everything that breaks as a result. +#include "upb/extension_registry.h" #include "upb/upb.h" #ifdef __cplusplus extern "C" { #endif -/** upb_Message - * *******************************************************************/ - typedef void upb_Message; /* For users these are opaque. They can be obtained from @@ -65,49 +64,6 @@ const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len); /* Returns the number of extensions present in this message. */ size_t upb_Message_ExtensionCount(const upb_Message* msg); -/** upb_ExtensionRegistry *****************************************************/ - -/* Extension registry: a dynamic data structure that stores a map of: - * (upb_MiniTable, number) -> extension info - * - * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing - * binary format. - * - * upb_ExtensionRegistry is part of the mini-table (msglayout) family of - * objects. Like all mini-table objects, it is suitable for reflection-less - * builds that do not want to expose names into the binary. - * - * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory - * allocation and dynamic initialization: - * * If reflection is being used, then upb_DefPool will construct an appropriate - * upb_ExtensionRegistry automatically. - * * For a mini-table only build, the user must manually construct the - * upb_ExtensionRegistry and populate it with all of the extensions the user - * cares about. - * * A third alternative is to manually unpack relevant extensions after the - * main parse is complete, similar to how Any works. This is perhaps the - * nicest solution from the perspective of reducing dependencies, avoiding - * dynamic memory allocation, and avoiding the need to parse uninteresting - * extensions. The downsides are: - * (1) parse errors are not caught during the main parse - * (2) the CPU hit of parsing comes during access, which could cause an - * undesirable stutter in application performance. - * - * Users cannot directly get or put into this map. Users can only add the - * extensions from a generated module and pass the extension registry to the - * binary decoder. - * - * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use - * reflection do not need to populate a upb_ExtensionRegistry directly. - */ - -struct upb_ExtensionRegistry; -typedef struct upb_ExtensionRegistry upb_ExtensionRegistry; - -/* Creates a upb_ExtensionRegistry in the given arena. The arena must outlive - * any use of the extreg. */ -upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena); - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/contrib/libs/grpc/third_party/upb/upb/msg_internal.h b/contrib/libs/grpc/third_party/upb/upb/msg_internal.h index 88c17108f1..4f5c4797c5 100644 --- a/contrib/libs/grpc/third_party/upb/upb/msg_internal.h +++ b/contrib/libs/grpc/third_party/upb/upb/msg_internal.h @@ -39,8 +39,9 @@ #include <stdlib.h> #include <string.h> +#include "upb/extension_registry.h" +#include "upb/internal/table.h" #include "upb/msg.h" -#include "upb/table_internal.h" #include "upb/upb.h" /* Must be last. */ @@ -50,6 +51,18 @@ extern "C" { #endif +/** upb_*Int* conversion routines ********************************************/ + +UPB_INLINE int32_t _upb_Int32_FromI(int v) { return (int32_t)v; } + +UPB_INLINE int64_t _upb_Int64_FromLL(long long v) { return (int64_t)v; } + +UPB_INLINE uint32_t _upb_UInt32_FromU(unsigned v) { return (uint32_t)v; } + +UPB_INLINE uint64_t _upb_UInt64_FromULL(unsigned long long v) { + return (uint64_t)v; +} + /** upb_MiniTable *************************************************************/ /* upb_MiniTable represents the memory layout of a given upb_MessageDef. The @@ -60,43 +73,40 @@ typedef struct { uint32_t number; uint16_t offset; int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index - uint16_t submsg_index; // undefined if descriptortype != MESSAGE/GROUP/ENUM + uint16_t submsg_index; // kUpb_NoSub if descriptortype != MESSAGE/GROUP/ENUM uint8_t descriptortype; uint8_t mode; /* upb_FieldMode | upb_LabelFlags | - (upb_FieldRep << upb_FieldRep_Shift) */ + (upb_FieldRep << kUpb_FieldRep_Shift) */ } upb_MiniTable_Field; +#define kUpb_NoSub ((uint16_t)-1) + typedef enum { kUpb_FieldMode_Map = 0, kUpb_FieldMode_Array = 1, kUpb_FieldMode_Scalar = 2, - - kUpb_FieldMode_Mask = 3, /* Mask to isolate the mode from upb_FieldRep. */ } upb_FieldMode; +// Mask to isolate the upb_FieldMode from field.mode. +#define kUpb_FieldMode_Mask 3 + /* Extra flags on the mode field. */ -enum upb_LabelFlags { - upb_LabelFlags_IsPacked = 4, - upb_LabelFlags_IsExtension = 8, -}; +typedef enum { + kUpb_LabelFlags_IsPacked = 4, + kUpb_LabelFlags_IsExtension = 8, +} upb_LabelFlags; -/* Representation in the message. Derivable from descriptortype and mode, but - * fast access helps the serializer. */ -enum upb_FieldRep { - upb_FieldRep_1Byte = 0, - upb_FieldRep_4Byte = 1, - upb_FieldRep_8Byte = 2, - upb_FieldRep_StringView = 3, - -#if UINTPTR_MAX == 0xffffffff - upb_FieldRep_Pointer = upb_FieldRep_4Byte, -#else - upb_FieldRep_Pointer = upb_FieldRep_8Byte, -#endif +// Note: we sort by this number when calculating layout order. +typedef enum { + kUpb_FieldRep_1Byte = 0, + kUpb_FieldRep_4Byte = 1, + kUpb_FieldRep_StringView = 2, + kUpb_FieldRep_Pointer = 3, + kUpb_FieldRep_8Byte = 4, - upb_FieldRep_Shift = - 6, /* Bit offset of the rep in upb_MiniTable_Field.mode */ -}; + kUpb_FieldRep_Shift = 5, // Bit offset of the rep in upb_MiniTable_Field.mode + kUpb_FieldRep_Max = kUpb_FieldRep_8Byte, +} upb_FieldRep; UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTable_Field* field) { return (upb_FieldMode)(field->mode & 3); @@ -130,36 +140,28 @@ typedef struct { int value_count; } upb_MiniTable_Enum; -UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, - int32_t val) { - uint32_t uval = (uint32_t)val; - if (uval < 64) return e->mask & (1 << uval); - // OPT: binary search long lists? - int n = e->value_count; - for (int i = 0; i < n; i++) { - if (e->values[i] == val) return true; - } - return false; -} - typedef union { const struct upb_MiniTable* submsg; const upb_MiniTable_Enum* subenum; } upb_MiniTable_Sub; typedef enum { - upb_ExtMode_NonExtendable = 0, // Non-extendable message. - upb_ExtMode_Extendable = 1, // Normal extendable message. - upb_ExtMode_IsMessageSet = 2, // MessageSet message. - upb_ExtMode_IsMessageSet_ITEM = + kUpb_ExtMode_NonExtendable = 0, // Non-extendable message. + kUpb_ExtMode_Extendable = 1, // Normal extendable message. + kUpb_ExtMode_IsMessageSet = 2, // MessageSet message. + kUpb_ExtMode_IsMessageSet_ITEM = 3, // MessageSet item (temporary only, see decode.c) + + // During table building we steal a bit to indicate that the message is a map + // entry. *Only* used during table building! + kUpb_ExtMode_IsMapEntry = 4, } upb_ExtMode; /* MessageSet wire format is: * message MessageSet { * repeated group Item = 1 { * required int32 type_id = 2; - * required string message = 3; + * required bytes message = 3; * } * } */ @@ -213,8 +215,7 @@ UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) { return ((1ULL << n) - 1) << 1; } -/** upb_ExtensionRegistry - * ****************************************************************/ +/** upb_ExtensionRegistry *****************************************************/ /* Adds the given extension info for message type |l| and field number |num| * into the registry. Returns false if this message type and field number were @@ -229,8 +230,7 @@ const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r, const upb_MiniTable* l, uint32_t num); -/** upb_Message - * *******************************************************************/ +/** upb_Message ***************************************************************/ /* Internal members of a upb_Message that track unknown fields and/or * extensions. We can change this without breaking binary compatibility. We put @@ -276,7 +276,7 @@ UPB_INLINE size_t upb_msg_sizeof(const upb_MiniTable* l) { UPB_INLINE upb_Message* _upb_Message_New_inl(const upb_MiniTable* l, upb_Arena* a) { size_t size = upb_msg_sizeof(l); - void* mem = upb_Arena_Malloc(a, size); + void* mem = upb_Arena_Malloc(a, size + sizeof(upb_Message_Internal)); upb_Message* msg; if (UPB_UNLIKELY(!mem)) return NULL; msg = UPB_PTR_AT(mem, sizeof(upb_Message_Internal), upb_Message); @@ -303,8 +303,7 @@ void _upb_Message_DiscardUnknown_shallow(upb_Message* msg); bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len, upb_Arena* arena); -/** upb_Message_Extension - * ***************************************************************/ +/** upb_Message_Extension *****************************************************/ /* The internal representation of an extension is self-describing: it contains * enough information that we can serialize it to binary format without needing @@ -326,7 +325,7 @@ typedef struct { /* Adds the given extension data to the given message. |ext| is copied into the * message instance. This logically replaces any previously-added extension with * this number */ -upb_Message_Extension* _upb_Message_Getorcreateext( +upb_Message_Extension* _upb_Message_GetOrCreateExtension( upb_Message* msg, const upb_MiniTable_Extension* ext, upb_Arena* arena); /* Returns an array of extensions for this message. Note: the array is @@ -472,6 +471,10 @@ UPB_INLINE bool _upb_Array_Resize(upb_Array* arr, size_t size, return true; } +UPB_INLINE void _upb_array_detach(const void* msg, size_t ofs) { + *UPB_PTR_AT(msg, ofs, upb_Array*) = NULL; +} + UPB_INLINE const void* _upb_array_accessor(const void* msg, size_t ofs, size_t* size) { const upb_Array* arr = *UPB_PTR_AT(msg, ofs, const upb_Array*); @@ -665,15 +668,31 @@ UPB_INLINE void* _upb_map_next(const upb_Map* map, size_t* iter) { return (void*)str_tabent(&it); } -UPB_INLINE bool _upb_Map_Set(upb_Map* map, const void* key, size_t key_size, - void* val, size_t val_size, upb_Arena* a) { +typedef enum { + // LINT.IfChange + _kUpb_MapInsertStatus_Inserted = 0, + _kUpb_MapInsertStatus_Replaced = 1, + _kUpb_MapInsertStatus_OutOfMemory = 2, + // LINT.ThenChange(//depot/google3/third_party/upb/upb/map.h) +} _upb_MapInsertStatus; + +UPB_INLINE _upb_MapInsertStatus _upb_Map_Insert(upb_Map* map, const void* key, + size_t key_size, void* val, + size_t val_size, upb_Arena* a) { upb_StringView strkey = _upb_map_tokey(key, key_size); upb_value tabval = {0}; - if (!_upb_map_tovalue(val, val_size, &tabval, a)) return false; + if (!_upb_map_tovalue(val, val_size, &tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); - return upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a); + bool removed = + upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL); + if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) { + return _kUpb_MapInsertStatus_OutOfMemory; + } + return removed ? _kUpb_MapInsertStatus_Replaced + : _kUpb_MapInsertStatus_Inserted; } UPB_INLINE bool _upb_Map_Delete(upb_Map* map, const void* key, @@ -715,7 +734,8 @@ UPB_INLINE bool _upb_msg_map_set(upb_Message* msg, size_t ofs, const void* key, if (!*map) { *map = _upb_Map_New(arena, key_size, val_size); } - return _upb_Map_Set(*map, key, key_size, val, val_size, arena); + return _upb_Map_Insert(*map, key, key_size, val, val_size, arena) != + _kUpb_MapInsertStatus_OutOfMemory; } UPB_INLINE bool _upb_msg_map_delete(upb_Message* msg, size_t ofs, @@ -761,8 +781,7 @@ UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, } } -/** _upb_mapsorter - * *************************************************************/ +/** _upb_mapsorter ************************************************************/ /* _upb_mapsorter sorts maps and provides ordered iteration over the entries. * Since maps can be recursive (map values can be messages which contain other diff --git a/contrib/libs/grpc/third_party/upb/upb/port_def.inc b/contrib/libs/grpc/third_party/upb/upb/port_def.inc index 75d416d1ce..92e4bf2477 100644 --- a/contrib/libs/grpc/third_party/upb/upb/port_def.inc +++ b/contrib/libs/grpc/third_party/upb/upb/port_def.inc @@ -88,9 +88,10 @@ #define UPB_INLINE static #endif +#define UPB_MALLOC_ALIGN 8 #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) +#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) #define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) /* Hints to the compiler about likely/unlikely branches. */ @@ -251,3 +252,11 @@ void __asan_unpoison_memory_region(void const volatile *addr, size_t size); #define UPB_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #endif + +/* Disable proto2 arena behavior (TEMPORARY) **********************************/ + +#ifdef UPB_DISABLE_PROTO2_ENUM_CHECKING +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 1 +#else +#define UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 0 +#endif diff --git a/contrib/libs/grpc/third_party/upb/upb/port_undef.inc b/contrib/libs/grpc/third_party/upb/upb/port_undef.inc index 70956df25d..1dff3d275d 100644 --- a/contrib/libs/grpc/third_party/upb/upb/port_undef.inc +++ b/contrib/libs/grpc/third_party/upb/upb/port_undef.inc @@ -37,6 +37,7 @@ #undef UPB_ALIGN_DOWN #undef UPB_ALIGN_MALLOC #undef UPB_ALIGN_OF +#undef UPB_MALLOC_ALIGN #undef UPB_LIKELY #undef UPB_UNLIKELY #undef UPB_FORCEINLINE @@ -59,3 +60,4 @@ #undef UPB_POISON_MEMORY_REGION #undef UPB_UNPOISON_MEMORY_REGION #undef UPB_ASAN +#undef UPB_TREAT_PROTO2_ENUMS_LIKE_PROTO3 diff --git a/contrib/libs/grpc/third_party/upb/upb/reflection.c b/contrib/libs/grpc/third_party/upb/upb/reflection.c index a3a64d2780..43f884495f 100644 --- a/contrib/libs/grpc/third_party/upb/upb/reflection.c +++ b/contrib/libs/grpc/third_party/upb/upb/reflection.c @@ -29,9 +29,9 @@ #include <string.h> +#include "upb/internal/table.h" #include "upb/msg.h" #include "upb/port_def.inc" -#include "upb/table_internal.h" static size_t get_field_size(const upb_MiniTable_Field* f) { static unsigned char sizes[] = { @@ -58,37 +58,6 @@ static size_t get_field_size(const upb_MiniTable_Field* f) { return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -/* Strings/bytes are special-cased in maps. */ -static char _upb_CTypeo_mapsize[12] = { - 0, - 1, /* kUpb_CType_Bool */ - 4, /* kUpb_CType_Float */ - 4, /* kUpb_CType_Int32 */ - 4, /* kUpb_CType_UInt32 */ - 4, /* kUpb_CType_Enum */ - sizeof(void*), /* kUpb_CType_Message */ - 8, /* kUpb_CType_Double */ - 8, /* kUpb_CType_Int64 */ - 8, /* kUpb_CType_UInt64 */ - 0, /* kUpb_CType_String */ - 0, /* kUpb_CType_Bytes */ -}; - -static const char _upb_CTypeo_sizelg2[12] = { - 0, - 0, /* kUpb_CType_Bool */ - 2, /* kUpb_CType_Float */ - 2, /* kUpb_CType_Int32 */ - 2, /* kUpb_CType_UInt32 */ - 2, /* kUpb_CType_Enum */ - UPB_SIZE(2, 3), /* kUpb_CType_Message */ - 3, /* kUpb_CType_Double */ - 3, /* kUpb_CType_Int64 */ - 3, /* kUpb_CType_UInt64 */ - UPB_SIZE(3, 4), /* kUpb_CType_String */ - UPB_SIZE(3, 4), /* kUpb_CType_Bytes */ -}; - /** upb_Message * *******************************************************************/ @@ -202,7 +171,7 @@ make: bool upb_Message_Set(upb_Message* msg, const upb_FieldDef* f, upb_MessageValue val, upb_Arena* a) { if (upb_FieldDef_IsExtension(f)) { - upb_Message_Extension* ext = _upb_Message_Getorcreateext( + upb_Message_Extension* ext = _upb_Message_GetOrCreateExtension( msg, _upb_FieldDef_ExtensionMiniTable(f), a); if (!ext) return false; memcpy(&ext->data, &val, sizeof(val)); @@ -352,129 +321,3 @@ bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, int maxdepth) { return _upb_Message_DiscardUnknown(msg, m, maxdepth); } - -/** upb_Array *****************************************************************/ - -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { - return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]); -} - -size_t upb_Array_Size(const upb_Array* arr) { return arr->len; } - -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { - upb_MessageValue ret; - const char* data = _upb_array_constptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(&ret, data + (i << lg2), 1 << lg2); - return ret; -} - -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(data + (i << lg2), &val, 1 << lg2); -} - -bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { - if (!upb_Array_Resize(arr, arr->len + 1, arena)) { - return false; - } - upb_Array_Set(arr, arr->len - 1, val); - return true; -} - -void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, - size_t count) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); -} - -bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, - upb_Arena* arena) { - UPB_ASSERT(i <= arr->len); - UPB_ASSERT(count + arr->len >= count); - size_t oldsize = arr->len; - if (!upb_Array_Resize(arr, arr->len + count, arena)) { - return false; - } - upb_Array_Move(arr, i + count, i, oldsize - i); - return true; -} - -/* - * i end arr->len - * |------------|XXXXXXXX|--------| - */ -void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { - size_t end = i + count; - UPB_ASSERT(i <= end); - UPB_ASSERT(end <= arr->len); - upb_Array_Move(arr, i, end, arr->len - end); - arr->len -= count; -} - -bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { - return _upb_Array_Resize(arr, size, arena); -} - -/** upb_Map *******************************************************************/ - -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { - return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type], - _upb_CTypeo_mapsize[value_type]); -} - -size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } - -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val) { - return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); -} - -void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } - -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena) { - return _upb_Map_Set(map, &key, map->key_size, &val, map->val_size, arena); -} - -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) { - return _upb_Map_Delete(map, &key, map->key_size); -} - -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { - return _upb_map_next(map, iter); -} - -bool upb_MapIterator_Done(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - UPB_ASSERT(iter != kUpb_Map_Begin); - i.t = &map->table; - i.index = iter; - return upb_strtable_done(&i); -} - -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); - return ret; -} - -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { - upb_strtable_iter i; - upb_MessageValue ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); - return ret; -} - -/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue - * value); */ diff --git a/contrib/libs/grpc/third_party/upb/upb/reflection.h b/contrib/libs/grpc/third_party/upb/upb/reflection.h index b892f66bfb..6071fba6f5 100644 --- a/contrib/libs/grpc/third_party/upb/upb/reflection.h +++ b/contrib/libs/grpc/third_party/upb/upb/reflection.h @@ -28,7 +28,9 @@ #ifndef UPB_REFLECTION_H_ #define UPB_REFLECTION_H_ +#include "upb/array.h" #include "upb/def.h" +#include "upb/map.h" #include "upb/msg.h" #include "upb/port_def.inc" #include "upb/upb.h" @@ -37,26 +39,6 @@ extern "C" { #endif -typedef union { - bool bool_val; - float float_val; - double double_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - const upb_Map* map_val; - const upb_Message* msg_val; - const upb_Array* array_val; - upb_StringView str_val; -} upb_MessageValue; - -typedef union { - upb_Map* map; - upb_Message* msg; - upb_Array* array; -} upb_MutableMessageValue; - upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f); /** upb_Message @@ -119,98 +101,6 @@ bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, int maxdepth); -/** upb_Array *****************************************************************/ - -/* Creates a new array on the given arena that holds elements of this type. */ -upb_Array* upb_Array_New(upb_Arena* a, upb_CType type); - -/* Returns the size of the array. */ -size_t upb_Array_Size(const upb_Array* arr); - -/* Returns the given element, which must be within the array's current size. */ -upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i); - -/* Sets the given element, which must be within the array's current size. */ -void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val); - -/* Appends an element to the array. Returns false on allocation failure. */ -bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena); - -/* Moves elements within the array using memmove(). Like memmove(), the source - * and destination elements may be overlapping. */ -void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx, - size_t count); - -/* Inserts one or more empty elements into the array. Existing elements are - * shifted right. The new elements have undefined state and must be set with - * `upb_Array_Set()`. - * REQUIRES: `i <= upb_Array_Size(arr)` */ -bool upb_Array_Insert(upb_Array* array, size_t i, size_t count, - upb_Arena* arena); - -/* Deletes one or more elements from the array. Existing elements are shifted - * left. - * REQUIRES: `i + count <= upb_Array_Size(arr)` */ -void upb_Array_Delete(upb_Array* array, size_t i, size_t count); - -/* Changes the size of a vector. New elements are initialized to empty/0. - * Returns false on allocation failure. */ -bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena); - -/** upb_Map *******************************************************************/ - -/* Creates a new map on the given arena with the given key/value size. */ -upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type); - -/* Returns the number of entries in the map. */ -size_t upb_Map_Size(const upb_Map* map); - -/* Stores a value for the given key into |*val| (or the zero value if the key is - * not present). Returns whether the key was present. The |val| pointer may be - * NULL, in which case the function tests whether the given key is present. */ -bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, - upb_MessageValue* val); - -/* Removes all entries in the map. */ -void upb_Map_Clear(upb_Map* map); - -/* Sets the given key to the given value. Returns true if this was a new key in - * the map, or false if an existing key was replaced. */ -bool upb_Map_Set(upb_Map* map, upb_MessageValue key, upb_MessageValue val, - upb_Arena* arena); - -/* Deletes this key from the table. Returns true if the key was present. */ -bool upb_Map_Delete(upb_Map* map, upb_MessageValue key); - -/* Map iteration: - * - * size_t iter = kUpb_Map_Begin; - * while (upb_MapIterator_Next(map, &iter)) { - * upb_MessageValue key = upb_MapIterator_Key(map, iter); - * upb_MessageValue val = upb_MapIterator_Value(map, iter); - * - * // If mutating is desired. - * upb_MapIterator_SetValue(map, iter, value2); - * } - */ - -/* Advances to the next entry. Returns false if no more entries are present. */ -bool upb_MapIterator_Next(const upb_Map* map, size_t* iter); - -/* Returns true if the iterator still points to a valid entry, or false if the - * iterator is past the last element. It is an error to call this function with - * kUpb_Map_Begin (you must call next() at least once first). */ -bool upb_MapIterator_Done(const upb_Map* map, size_t iter); - -/* Returns the key and value for this entry of the map. */ -upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter); -upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter); - -/* Sets the value for this entry. The iterator must not be done, and the - * iterator must not have been initialized const. */ -void upb_MapIterator_SetValue(upb_Map* map, size_t iter, - upb_MessageValue value); - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/contrib/libs/grpc/third_party/upb/upb/status.c b/contrib/libs/grpc/third_party/upb/upb/status.c new file mode 100644 index 0000000000..c00b9c86b2 --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/status.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/status.h" + +#include <errno.h> +#include <float.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "upb/internal/upb.h" + +// Must be last. +#include "upb/port_def.inc" + +void upb_Status_Clear(upb_Status* status) { + if (!status) return; + status->ok = true; + status->msg[0] = '\0'; +} + +bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } + +const char* upb_Status_ErrorMessage(const upb_Status* status) { + return status->msg; +} + +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { + if (!status) return; + status->ok = false; + strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_Status_VSetErrorFormat(status, fmt, args); + va_end(args); +} + +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + if (!status) return; + status->ok = false; + vsnprintf(status->msg, sizeof(status->msg), fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} + +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) { + size_t len; + if (!status) return; + status->ok = false; + len = strlen(status->msg); + vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); + status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; +} diff --git a/contrib/libs/grpc/third_party/upb/upb/status.h b/contrib/libs/grpc/third_party/upb/upb/status.h new file mode 100644 index 0000000000..2c5c2a7f8b --- /dev/null +++ b/contrib/libs/grpc/third_party/upb/upb/status.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_STATUS_H_ +#define UPB_STATUS_H_ + +#include <stdarg.h> +#include <stdbool.h> + +#include "upb/port_def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +#define _kUpb_Status_MaxMessage 127 + +typedef struct { + bool ok; + char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ +} upb_Status; + +const char* upb_Status_ErrorMessage(const upb_Status* status); +bool upb_Status_IsOk(const upb_Status* status); + +/* These are no-op if |status| is NULL. */ +void upb_Status_Clear(upb_Status* status); +void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); +void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) + UPB_PRINTF(2, 3); +void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); +void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, + va_list args) UPB_PRINTF(2, 0); + +#include "upb/port_undef.inc" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_STATUS_H_ */ diff --git a/contrib/libs/grpc/third_party/upb/upb/table.c b/contrib/libs/grpc/third_party/upb/upb/table.c index 33b3a9dc6e..e8e55f7e34 100644 --- a/contrib/libs/grpc/third_party/upb/upb/table.c +++ b/contrib/libs/grpc/third_party/upb/upb/table.c @@ -31,9 +31,9 @@ * Implementation is heavily inspired by Lua's ltable.c. */ -#include <string.h> +#include "upb/internal/table.h" -#include "upb/table_internal.h" +#include <string.h> /* Must be last. */ #include "upb/port_def.inc" @@ -433,14 +433,18 @@ const uint64_t kWyhashSalt[5] = { 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, }; -static uint32_t table_hash(const char* p, size_t n) { - return Wyhash(p, n, 0, kWyhashSalt); +uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { + return Wyhash(p, n, seed, kWyhashSalt); +} + +static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { + return _upb_Hash(p, n, 0); } static uint32_t strhash(upb_tabkey key) { uint32_t len; char* str = upb_tabstr(key, &len); - return table_hash(str, len); + return _upb_Hash_NoSeed(str, len); } static bool streql(upb_tabkey k1, lookupkey_t k2) { @@ -496,20 +500,20 @@ bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, tabkey = strcopy(key, a); if (tabkey == 0) return false; - hash = table_hash(key.str.str, key.str.len); + hash = _upb_Hash_NoSeed(key.str.str, key.str.len); insert(&t->t, key, tabkey, v, hash, &strhash, &streql); return true; } bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, upb_value* v) { - uint32_t hash = table_hash(key, len); + uint32_t hash = _upb_Hash_NoSeed(key, len); return lookup(&t->t, strkey2(key, len), v, hash, &streql); } bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, upb_value* val) { - uint32_t hash = table_hash(key, len); + uint32_t hash = _upb_Hash_NoSeed(key, len); upb_tabkey tabkey; return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql); } diff --git a/contrib/libs/grpc/third_party/upb/upb/text_encode.c b/contrib/libs/grpc/third_party/upb/upb/text_encode.c index 9612375dba..dfb213f2bb 100644 --- a/contrib/libs/grpc/third_party/upb/upb/text_encode.c +++ b/contrib/libs/grpc/third_party/upb/upb/text_encode.c @@ -34,8 +34,9 @@ #include <stdio.h> #include <string.h> +#include "upb/internal/upb.h" +#include "upb/internal/vsnprintf_compat.h" #include "upb/reflection.h" -#include "upb/upb_internal.h" // Must be last. #include "upb/port_def.inc" @@ -76,7 +77,7 @@ static void txtenc_printf(txtenc* e, const char* fmt, ...) { va_list args; va_start(args, fmt); - n = vsnprintf(e->ptr, have, fmt, args); + n = _upb_vsnprintf(e->ptr, have, fmt, args); va_end(args); if (UPB_LIKELY(have > n)) { diff --git a/contrib/libs/grpc/third_party/upb/upb/upb.c b/contrib/libs/grpc/third_party/upb/upb/upb.c index 55730bbe82..08ae964777 100644 --- a/contrib/libs/grpc/third_party/upb/upb/upb.c +++ b/contrib/libs/grpc/third_party/upb/upb/upb.c @@ -25,6 +25,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "upb/internal/upb.h" + #include <errno.h> #include <float.h> #include <stdarg.h> @@ -34,300 +36,12 @@ #include <stdlib.h> #include <string.h> -#include "upb/upb_internal.h" +#include "upb/arena.h" +#include "upb/status.h" // Must be last. #include "upb/port_def.inc" -/* upb_Status *****************************************************************/ - -void upb_Status_Clear(upb_Status* status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; -} - -bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } - -const char* upb_Status_ErrorMessage(const upb_Status* status) { - return status->msg; -} - -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { - if (!status) return; - status->ok = false; - strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} - -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - upb_Status_VSetErrorFormat(status, fmt, args); - va_end(args); -} - -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - if (!status) return; - status->ok = false; - vsnprintf(status->msg, sizeof(status->msg), fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} - -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) { - size_t len; - if (!status) return; - status->ok = false; - len = strlen(status->msg); - vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); - status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; -} - -/* upb_alloc ******************************************************************/ - -static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - UPB_UNUSED(alloc); - UPB_UNUSED(oldsize); - if (size == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, size); - } -} - -static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) { - return (uint32_t*)(cleanup_metadata & ~0x1); -} - -static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { - return cleanup_metadata & 0x1; -} - -static uintptr_t upb_cleanup_metadata(uint32_t* cleanup, - bool has_initial_block) { - return (uintptr_t)cleanup | has_initial_block; -} - -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - -/* upb_Arena ******************************************************************/ - -/* Be conservative and choose 16 in case anyone is using SSE. */ - -struct mem_block { - struct mem_block* next; - uint32_t size; - uint32_t cleanups; - /* Data follows. */ -}; - -typedef struct cleanup_ent { - upb_CleanupFunc* cleanup; - void* ud; -} cleanup_ent; - -static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); - -static upb_Arena* arena_findroot(upb_Arena* a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_Arena* next = a->parent; - a->parent = next->parent; - a = next; - } - return a; -} - -static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr, - size_t size) { - mem_block* block = ptr; - - /* The block is for arena |a|, but should appear in the freelist of |root|. */ - block->next = root->freelist; - block->size = (uint32_t)size; - block->cleanups = 0; - root->freelist = block; - a->last_size = block->size; - if (!root->freelist_tail) root->freelist_tail = block; - - a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); - a->head.end = UPB_PTR_AT(block, size, char); - a->cleanup_metadata = upb_cleanup_metadata( - &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); - - UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); -} - -static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) { - upb_Arena* root = arena_findroot(a); - size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block* block = upb_malloc(root->block_alloc, block_size); - - if (!block) return false; - upb_Arena_addblock(a, root, block, block_size); - return true; -} - -void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) { - if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= size); - return upb_Arena_Malloc(a, size); -} - -static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */ - return upb_Arena_Realloc(a, ptr, oldsize, size); -} - -/* Public Arena API ***********************************************************/ - -upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) { - const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve; - upb_Arena* a; - - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; - } - - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - n -= sizeof(*a); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->freelist = NULL; - a->freelist_tail = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, false); - - upb_Arena_addblock(a, a, mem, n); - - return a; -} - -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { - upb_Arena* a; - - if (n) { - /* Align initial pointer up so that we return properly-aligned pointers. */ - void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, 16); - size_t delta = (uintptr_t)aligned - (uintptr_t)mem; - n = delta <= n ? n - delta : 0; - mem = aligned; - } - - /* Round block size down to alignof(*a) since we will allocate the arena - * itself at the end. */ - n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena)); - - if (UPB_UNLIKELY(n < sizeof(upb_Arena))) { - return arena_initslow(mem, n, alloc); - } - - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena); - - a->head.alloc.func = &upb_Arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->last_size = UPB_MAX(128, n); - a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); - a->freelist = NULL; - a->cleanup_metadata = upb_cleanup_metadata(NULL, true); - - return a; -} - -static void arena_dofree(upb_Arena* a) { - mem_block* block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); - - while (block) { - /* Load first since we are deleting block. */ - mem_block* next = block->next; - - if (block->cleanups > 0) { - cleanup_ent* end = UPB_PTR_AT(block, block->size, void); - cleanup_ent* ptr = end - block->cleanups; - - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); - } - } - - upb_free(a->block_alloc, block); - block = next; - } -} - -void upb_Arena_Free(upb_Arena* a) { - a = arena_findroot(a); - if (--a->refcount == 0) arena_dofree(a); -} - -bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) { - cleanup_ent* ent; - uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); - - if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) { - if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent)); - cleanups = upb_cleanup_pointer(a->cleanup_metadata); - } - - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*cleanups)++; - UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); - - ent->cleanup = func; - ent->ud = ud; - - return true; -} - -bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) { - upb_Arena* r1 = arena_findroot(a1); - upb_Arena* r2 = arena_findroot(a2); - - if (r1 == r2) return true; /* Already fused. */ - - /* Do not fuse initial blocks since we cannot lifetime extend them. */ - if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; - if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; - - /* Only allow fuse with a common allocator */ - if (r1->block_alloc != r2->block_alloc) return false; - - /* We want to join the smaller tree to the larger tree. - * So swap first if they are backwards. */ - if (r1->refcount < r2->refcount) { - upb_Arena* tmp = r1; - r1 = r2; - r2 = tmp; - } - - /* r1 takes over r2's freelist and refcount. */ - r1->refcount += r2->refcount; - if (r2->freelist_tail) { - UPB_ASSERT(r2->freelist_tail->next == NULL); - r2->freelist_tail->next = r1->freelist; - r1->freelist = r2->freelist; - } - r2->parent = r1; - return true; -} - /* Miscellaneous utilities ****************************************************/ static void upb_FixLocale(char* p) { diff --git a/contrib/libs/grpc/third_party/upb/upb/upb.h b/contrib/libs/grpc/third_party/upb/upb/upb.h index 12aecb46cb..7398d09fff 100644 --- a/contrib/libs/grpc/third_party/upb/upb/upb.h +++ b/contrib/libs/grpc/third_party/upb/upb/upb.h @@ -39,34 +39,17 @@ #include <stdint.h> #include <string.h> +// TODO(b/232091617): Remove these and fix everything that breaks as a result. +#include "upb/arena.h" +#include "upb/status.h" + +// Must be last. #include "upb/port_def.inc" #ifdef __cplusplus extern "C" { #endif -/* upb_Status *****************************************************************/ - -#define _kUpb_Status_MaxMessage 127 - -typedef struct { - bool ok; - char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */ -} upb_Status; - -const char* upb_Status_ErrorMessage(const upb_Status* status); -bool upb_Status_IsOk(const upb_Status* status); - -/* These are no-op if |status| is NULL. */ -void upb_Status_Clear(upb_Status* status); -void upb_Status_SetErrorMessage(upb_Status* status, const char* msg); -void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) - UPB_PRINTF(2, 3); -void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); -void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, - va_list args) UPB_PRINTF(2, 0); - /** upb_StringView ************************************************************/ typedef struct { @@ -96,148 +79,6 @@ UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) { #define UPB_STRINGVIEW_FORMAT "%.*s" #define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data -/** upb_alloc *****************************************************************/ - -/* A upb_alloc is a possibly-stateful allocator object. - * - * It could either be an arena allocator (which doesn't require individual - * free() calls) or a regular malloc() (which does). The client must therefore - * free memory unless it knows that the allocator is an arena allocator. */ - -struct upb_alloc; -typedef struct upb_alloc upb_alloc; - -/* A malloc()/free() function. - * If "size" is 0 then the function acts like free(), otherwise it acts like - * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ -typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size); - -struct upb_alloc { - upb_alloc_func* func; -}; - -UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) { - UPB_ASSERT(alloc); - return alloc->func(alloc, NULL, 0, size); -} - -UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize, - size_t size) { - UPB_ASSERT(alloc); - return alloc->func(alloc, ptr, oldsize, size); -} - -UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) { - assert(alloc); - alloc->func(alloc, ptr, 0, 0); -} - -/* The global allocator used by upb. Uses the standard malloc()/free(). */ - -extern upb_alloc upb_alloc_global; - -/* Functions that hard-code the global malloc. - * - * We still get benefit because we can put custom logic into our global - * allocator, like injecting out-of-memory faults in debug/testing builds. */ - -UPB_INLINE void* upb_gmalloc(size_t size) { - return upb_malloc(&upb_alloc_global, size); -} - -UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) { - return upb_realloc(&upb_alloc_global, ptr, oldsize, size); -} - -UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); } - -/* upb_Arena ******************************************************************/ - -/* upb_Arena is a specific allocator implementation that uses arena allocation. - * The user provides an allocator that will be used to allocate the underlying - * arena blocks. Arenas by nature do not require the individual allocations - * to be freed. However the Arena does allow users to register cleanup - * functions that will run when the arena is destroyed. - * - * A upb_Arena is *not* thread-safe. - * - * You could write a thread-safe arena allocator that satisfies the - * upb_alloc interface, but it would not be as efficient for the - * single-threaded case. */ - -typedef void upb_CleanupFunc(void* ud); - -struct upb_Arena; -typedef struct upb_Arena upb_Arena; - -typedef struct { - /* We implement the allocator interface. - * This must be the first member of upb_Arena! - * TODO(haberman): remove once handlers are gone. */ - upb_alloc alloc; - - char *ptr, *end; -} _upb_ArenaHead; - -/* Creates an arena from the given initial block (if any -- n may be 0). - * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this - * is a fixed-size arena and cannot grow. */ -upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc); -void upb_Arena_Free(upb_Arena* a); -bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func); -bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b); -void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size); - -UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; } - -UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) { - _upb_ArenaHead* h = (_upb_ArenaHead*)a; - return (size_t)(h->end - h->ptr); -} - -UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) { - _upb_ArenaHead* h = (_upb_ArenaHead*)a; - void* ret; - size = UPB_ALIGN_MALLOC(size); - - if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) { - return _upb_Arena_SlowMalloc(a, size); - } - - ret = h->ptr; - h->ptr += size; - UPB_UNPOISON_MEMORY_REGION(ret, size); - -#if UPB_ASAN - { - size_t guard_size = 32; - if (_upb_ArenaHas(a) >= guard_size) { - h->ptr += guard_size; - } else { - h->ptr = h->end; - } - } -#endif - - return ret; -} - -UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize, - size_t size) { - void* ret = upb_Arena_Malloc(a, size); - - if (ret && oldsize > 0) { - memcpy(ret, ptr, oldsize); - } - - return ret; -} - -UPB_INLINE upb_Arena* upb_Arena_New(void) { - return upb_Arena_Init(NULL, 0, &upb_alloc_global); -} - /* Constants ******************************************************************/ /* A list of types as they are encoded on-the-wire. */ @@ -316,8 +157,8 @@ UPB_INLINE uint64_t _upb_BigEndian_Swap64(uint64_t val) { if (_upb_IsLittleEndian()) { return val; } else { - return ((uint64_t)_upb_BigEndian_Swap32(val) << 32) | - _upb_BigEndian_Swap32(val >> 32); + return ((uint64_t)_upb_BigEndian_Swap32((uint32_t)val) << 32) | + _upb_BigEndian_Swap32((uint32_t)(val >> 32)); } } @@ -332,7 +173,7 @@ UPB_INLINE int _upb_Log2Ceiling(int x) { #endif } -UPB_INLINE int _upb_Log2Ceilingsize(int x) { return 1 << _upb_Log2Ceiling(x); } +UPB_INLINE int _upb_Log2CeilingSize(int x) { return 1 << _upb_Log2Ceiling(x); } #include "upb/port_undef.inc" |