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: 622859234
pull/16435/head
Mike Kruskal 2024-04-08 08:52:11 -07:00 committed by Copybara-Service
parent cb93f9aa6e
commit 77ae24b39d
5 changed files with 9 additions and 58 deletions

View File

@ -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

View File

@ -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()),

View File

@ -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.

View File

@ -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"

View File

@ -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);