Fix C# parsing of delimited fields.
Instead of using the message's corresponding field to denote the end of the stream, just abort it on *any* end group tag. If this is an invalid tag, the caller will handle the failure. PiperOrigin-RevId: 622859234pull/16435/head
parent
cb93f9aa6e
commit
77ae24b39d
|
@ -33,8 +33,3 @@ Recommended.Editions_Proto3.ValueRejectInfNumberValue.JsonOutput
|
|||
Recommended.Editions_Proto3.ValueRejectNanNumberValue.JsonOutput
|
||||
Required.Editions_Proto2.ProtobufInput.UnknownOrdering.ProtobufOutput
|
||||
Required.Editions_Proto3.ProtobufInput.UnknownOrdering.ProtobufOutput
|
||||
|
||||
# TODO C# doesn't handle delimited parsing well.
|
||||
Required.Editions.ProtobufInput.ValidDelimitedExtension.NotGroupLike.ProtobufOutput
|
||||
Required.Editions.ProtobufInput.ValidDelimitedField.NotGroupLike.JsonOutput
|
||||
Required.Editions.ProtobufInput.ValidDelimitedField.NotGroupLike.ProtobufOutput
|
||||
|
|
|
@ -192,44 +192,6 @@ std::string GetEnumValueName(absl::string_view enum_name,
|
|||
return result;
|
||||
}
|
||||
|
||||
uint GetGroupEndTag(const Descriptor* descriptor) {
|
||||
const Descriptor* containing_type = descriptor->containing_type();
|
||||
if (containing_type != nullptr) {
|
||||
const FieldDescriptor* field;
|
||||
for (int i = 0; i < containing_type->field_count(); i++) {
|
||||
field = containing_type->field(i);
|
||||
if (field->type() == FieldDescriptor::Type::TYPE_GROUP &&
|
||||
field->message_type() == descriptor) {
|
||||
return internal::WireFormatLite::MakeTag(
|
||||
field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < containing_type->extension_count(); i++) {
|
||||
field = containing_type->extension(i);
|
||||
if (field->type() == FieldDescriptor::Type::TYPE_GROUP &&
|
||||
field->message_type() == descriptor) {
|
||||
return internal::WireFormatLite::MakeTag(
|
||||
field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const FileDescriptor* containing_file = descriptor->file();
|
||||
if (containing_file != nullptr) {
|
||||
const FieldDescriptor* field;
|
||||
for (int i = 0; i < containing_file->extension_count(); i++) {
|
||||
field = containing_file->extension(i);
|
||||
if (field->type() == FieldDescriptor::Type::TYPE_GROUP &&
|
||||
field->message_type() == descriptor) {
|
||||
return internal::WireFormatLite::MakeTag(
|
||||
field->number(), internal::WireFormatLite::WIRETYPE_END_GROUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string GetFullExtensionName(const FieldDescriptor* descriptor) {
|
||||
if (descriptor->extension_scope()) {
|
||||
return absl::StrCat(GetClassName(descriptor->extension_scope()),
|
||||
|
|
|
@ -85,9 +85,6 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) {
|
|||
return descriptor->options().map_entry();
|
||||
}
|
||||
|
||||
// Checks if this descriptor is for a group and gets its end tag or 0 if it's not a group
|
||||
uint GetGroupEndTag(const Descriptor* descriptor);
|
||||
|
||||
// Determines whether we're generating code for the proto representation of
|
||||
// descriptors etc, for use in the runtime. This is the only type which is
|
||||
// allowed to use proto2 syntax, and it generates internal classes.
|
||||
|
|
|
@ -43,7 +43,6 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
|
|||
: SourceGeneratorBase(options),
|
||||
descriptor_(descriptor),
|
||||
has_bit_field_count_(0),
|
||||
end_tag_(GetGroupEndTag(descriptor)),
|
||||
has_extension_ranges_(descriptor->extension_range_count() > 0) {
|
||||
// fields by number
|
||||
for (int i = 0; i < descriptor_->field_count(); i++) {
|
||||
|
@ -668,18 +667,17 @@ void MessageGenerator::GenerateMainParseLoop(io::Printer* printer,
|
|||
absl::flat_hash_map<absl::string_view, std::string> vars;
|
||||
vars["maybe_ref_input"] = use_parse_context ? "ref input" : "input";
|
||||
|
||||
printer->Print(
|
||||
"uint tag;\n"
|
||||
"while ((tag = input.ReadTag()) != 0) {\n"
|
||||
" switch(tag) {\n");
|
||||
printer->Emit(R"csharp(
|
||||
uint tag;
|
||||
while ((tag = input.ReadTag()) != 0) {
|
||||
if ((tag & 7) == 4) {
|
||||
// Abort on any end group tag.
|
||||
return;
|
||||
}
|
||||
switch(tag) {
|
||||
)csharp");
|
||||
printer->Indent();
|
||||
printer->Indent();
|
||||
if (end_tag_ != 0) {
|
||||
printer->Print(
|
||||
"case $end_tag$:\n"
|
||||
" return;\n",
|
||||
"end_tag", absl::StrCat(end_tag_));
|
||||
}
|
||||
if (has_extension_ranges_) {
|
||||
printer->Print(vars,
|
||||
"default:\n"
|
||||
|
|
|
@ -39,7 +39,6 @@ class MessageGenerator : public SourceGeneratorBase {
|
|||
const Descriptor* descriptor_;
|
||||
std::vector<const FieldDescriptor*> fields_by_number_;
|
||||
int has_bit_field_count_;
|
||||
uint end_tag_;
|
||||
bool has_extension_ranges_;
|
||||
|
||||
void GenerateMessageSerializationMethods(io::Printer* printer);
|
||||
|
|
Loading…
Reference in New Issue