upb: lock down upb_MiniTableEnum

PiperOrigin-RevId: 585733953
pull/14857/head
Eric Salo 1 year ago committed by Copybara-Service
parent 578e07e9bd
commit f6b38b5838
  1. 31
      upb/mini_descriptor/build_enum.c
  2. 19
      upb/mini_table/internal/enum.h
  3. 10
      upb_generator/protoc-gen-upb_minitable.cc

@ -7,8 +7,15 @@
#include "upb/mini_descriptor/build_enum.h"
#include <stddef.h>
#include <stdint.h>
#include "upb/base/status.h"
#include "upb/mem/arena.h"
#include "upb/mini_descriptor/internal/base92.h"
#include "upb/mini_descriptor/internal/decoder.h"
#include "upb/mini_descriptor/internal/wire_constants.h"
#include "upb/mini_table/enum.h"
#include "upb/mini_table/internal/enum.h"
// Must be last.
@ -36,26 +43,27 @@ static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder* d,
d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz);
upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table);
}
d->enum_table->data[d->enum_data_count++] = val;
d->enum_table->UPB_PRIVATE(data)[d->enum_data_count++] = val;
return d->enum_table;
}
static void upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder* d, uint32_t val) {
upb_MiniTableEnum* table = d->enum_table;
d->enum_value_count++;
if (table->value_count || (val > 512 && d->enum_value_count < val / 32)) {
if (table->value_count == 0) {
assert(d->enum_data_count == table->mask_limit / 32);
if (table->UPB_PRIVATE(value_count) ||
(val > 512 && d->enum_value_count < val / 32)) {
if (table->UPB_PRIVATE(value_count) == 0) {
UPB_ASSERT(d->enum_data_count == table->UPB_PRIVATE(mask_limit) / 32);
}
table = _upb_MiniTable_AddEnumDataMember(d, val);
table->value_count++;
table->UPB_PRIVATE(value_count)++;
} else {
uint32_t new_mask_limit = ((val / 32) + 1) * 32;
while (table->mask_limit < new_mask_limit) {
while (table->UPB_PRIVATE(mask_limit) < new_mask_limit) {
table = _upb_MiniTable_AddEnumDataMember(d, 0);
table->mask_limit += 32;
table->UPB_PRIVATE(mask_limit) += 32;
}
table->data[val / 32] |= 1ULL << (val % 32);
table->UPB_PRIVATE(data)[val / 32] |= 1ULL << (val % 32);
}
}
@ -73,11 +81,11 @@ static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum(
upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table);
// Guarantee at least 64 bits of mask without checking mask size.
d->enum_table->mask_limit = 64;
d->enum_table->UPB_PRIVATE(mask_limit) = 64;
d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0);
d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0);
d->enum_table->value_count = 0;
d->enum_table->UPB_PRIVATE(value_count) = 0;
const char* ptr = data;
uint32_t base = 0;
@ -105,7 +113,8 @@ static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum(
}
static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum(
upb_MdEnumDecoder* const decoder, const char* const data, size_t const len) {
upb_MdEnumDecoder* const decoder, const char* const data,
size_t const len) {
if (UPB_SETJMP(decoder->base.err) != 0) return NULL;
return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len);
}

@ -14,9 +14,9 @@
#include "upb/port/def.inc"
struct upb_MiniTableEnum {
uint32_t mask_limit; // Limit enum value that can be tested with mask.
uint32_t value_count; // Number of values after the bitfield.
uint32_t data[]; // Bitmask + enumerated values follow.
uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask.
uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield.
uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow.
};
#ifdef __cplusplus
@ -26,19 +26,22 @@ extern "C" {
UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableEnum_CheckValue)(
const struct upb_MiniTableEnum* e, uint32_t val) {
if (UPB_LIKELY(val < 64)) {
const uint64_t mask = e->data[0] | ((uint64_t)e->data[1] << 32);
const uint64_t mask =
e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32);
const uint64_t bit = 1ULL << val;
return (mask & bit) != 0;
}
if (UPB_LIKELY(val < e->mask_limit)) {
const uint32_t mask = e->data[val / 32];
if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) {
const uint32_t mask = e->UPB_PRIVATE(data)[val / 32];
const uint32_t bit = 1ULL << (val % 32);
return (mask & bit) != 0;
}
// OPT: binary search long lists?
const uint32_t* start = &e->data[e->mask_limit / 32];
const uint32_t* limit = &e->data[e->mask_limit / 32 + e->value_count];
const uint32_t* start =
&e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32];
const uint32_t* limit = &e->UPB_PRIVATE(
data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)];
for (const uint32_t* p = start; p < limit; p++) {
if (*p == val) return true;
}

@ -492,10 +492,11 @@ void WriteMessage(upb::MessageDefPtr message, const DefPoolPair& pools,
void WriteEnum(upb::EnumDefPtr e, Output& output) {
std::string values_init = "{\n";
const upb_MiniTableEnum* mt = e.mini_table();
uint32_t value_count = (mt->mask_limit / 32) + mt->value_count;
uint32_t value_count =
(mt->UPB_PRIVATE(mask_limit) / 32) + mt->UPB_PRIVATE(value_count);
for (uint32_t i = 0; i < value_count; i++) {
absl::StrAppend(&values_init, " 0x", absl::Hex(mt->data[i]),
",\n");
absl::StrAppend(&values_init, " 0x",
absl::Hex(mt->UPB_PRIVATE(data)[i]), ",\n");
}
values_init += " }";
@ -507,7 +508,8 @@ void WriteEnum(upb::EnumDefPtr e, Output& output) {
$3,
};
)cc",
EnumInit(e), mt->mask_limit, mt->value_count, values_init);
EnumInit(e), mt->UPB_PRIVATE(mask_limit), mt->UPB_PRIVATE(value_count),
values_init);
output("\n");
}

Loading…
Cancel
Save