Fixed two bugs with proto2 enums:

1. The mask was getting improperly truncated for values 32-63.
2. We were not handling duplicated enum values.
pull/13171/head
Joshua Haberman 3 years ago
parent 9966e6830c
commit 65a85a63c8
  1. 19
      upb/def.c
  2. 20
      upb/util/def_to_proto_test.proto
  3. 14
      upbc/protoc-gen-upb.cc

@ -2397,6 +2397,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;
@ -2427,6 +2433,17 @@ upb_MiniTable_Enum* create_enumlayout(symtab_addctx* ctx,
UPB_ASSERT(p == values + n);
}
// Enums can have duplicate values; we must sort+uniq them.
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 +2527,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);

@ -69,6 +69,26 @@ enum Enum {
NEGATIVE_ONE = -1;
}
enum EnumUpper32Value {
UPPER32_VALUE = 40;
}
enum HasDuplicateValues {
option allow_alias = true;
A = 0;
B = 1;
C = 120;
D = 130;
G = 120;
F = 1;
E = 0;
H = 121;
I = 121;
J = 121;
K = 121;
}
service Service {
rpc Bar(Message) returns (Message);
}

@ -95,6 +95,17 @@ std::vector<const protobuf::EnumDescriptor*> SortedEnums(
return enums;
}
std::vector<int32_t> SortedUniqueEnumNumbers(
const protobuf::EnumDescriptor* e) {
std::vector<int32_t> values;
for (int i = 0; i < e->value_count(); i++) {
values.push_back(e->value(i)->number());
}
std::sort(values.begin(), values.end());
std::unique(values.begin(), values.end());
return values;
}
void AddMessages(const protobuf::Descriptor* message,
std::vector<const protobuf::Descriptor*>* messages) {
messages->push_back(message);
@ -1301,8 +1312,7 @@ int WriteEnums(const protobuf::FileDescriptor* file, Output& output) {
for (const auto* e : this_file_enums) {
uint64_t mask = 0;
absl::flat_hash_set<int32_t> values;
for (int i = 0; i < e->value_count(); i++) {
int32_t number = e->value(i)->number();
for (auto number : SortedUniqueEnumNumbers(e)) {
if (static_cast<uint32_t>(number) < 64) {
mask |= 1 << number;
} else {

Loading…
Cancel
Save