Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix packed reflection handling bug in edition 2023. #18405

Merged
merged 1 commit into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions compatibility/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,3 @@ java_runtime_conformance(
name = "java_conformance_main",
gencode_version = "main",
)

# Generates a build_test named "conformance_v3.25.0"
java_runtime_conformance(
name = "java_conformance_v3.25.0",
gencode_version = "3.25.0",
)
125 changes: 106 additions & 19 deletions java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.protobuf.DescriptorProtos.FeatureSetDefaults;
import com.google.protobuf.DescriptorProtos.FeatureSetDefaults.FeatureSetEditionDefault;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
import com.google.protobuf.DescriptorProtos.FieldOptions;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileOptions;
import com.google.protobuf.DescriptorProtos.MethodDescriptorProto;
Expand Down Expand Up @@ -53,7 +54,6 @@
import protobuf_unittest.UnittestProto.TestReservedFields;
import protobuf_unittest.UnittestProto.TestService;
import protobuf_unittest.UnittestRetention;
import proto3_unittest.UnittestProto3;
import protobuf_unittest.UnittestProto3Extensions.Proto3FileExtensions;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -1256,32 +1256,106 @@ public void testLegacyGroupTransform() {
}

@Test
public void testLegacyInferRequired() {
FieldDescriptor field = UnittestProto.TestRequired.getDescriptor().findFieldByName("a");
public void testLegacyInferRequired() throws Exception {
FileDescriptor file =
FileDescriptor.buildFrom(
FileDescriptorProto.newBuilder()
.setName("some/filename/some.proto")
.setSyntax("proto2")
.addMessageType(
DescriptorProto.newBuilder()
.setName("Foo")
.addField(
FieldDescriptorProto.newBuilder()
.setName("a")
.setNumber(1)
.setType(FieldDescriptorProto.Type.TYPE_INT32)
.setLabel(FieldDescriptorProto.Label.LABEL_REQUIRED)
.build())
.build())
.build(),
new FileDescriptor[0]);
FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("a");
assertThat(field.features.getFieldPresence())
.isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.LEGACY_REQUIRED);
}

@Test
public void testLegacyInferGroup() {
FieldDescriptor field =
UnittestProto.TestAllTypes.getDescriptor().findFieldByName("optionalgroup");
public void testLegacyInferGroup() throws Exception {
FileDescriptor file =
FileDescriptor.buildFrom(
FileDescriptorProto.newBuilder()
.setName("some/filename/some.proto")
.setSyntax("proto2")
.addMessageType(
DescriptorProto.newBuilder()
.setName("Foo")
.addNestedType(
DescriptorProto.newBuilder().setName("OptionalGroup").build())
.addField(
FieldDescriptorProto.newBuilder()
.setName("optionalgroup")
.setNumber(1)
.setType(FieldDescriptorProto.Type.TYPE_GROUP)
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Foo.OptionalGroup")
.build())
.build())
.build(),
new FileDescriptor[0]);
FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("optionalgroup");
assertThat(field.features.getMessageEncoding())
.isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.DELIMITED);
}

@Test
public void testLegacyInferProto2Packed() {
FieldDescriptor field =
UnittestProto.TestPackedTypes.getDescriptor().findFieldByName("packed_int32");
public void testLegacyInferProto2Packed() throws Exception {
FileDescriptor file =
FileDescriptor.buildFrom(
FileDescriptorProto.newBuilder()
.setName("some/filename/some.proto")
.setSyntax("proto2")
.addMessageType(
DescriptorProto.newBuilder()
.setName("Foo")
.addField(
FieldDescriptorProto.newBuilder()
.setName("a")
.setNumber(1)
.setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
.setType(FieldDescriptorProto.Type.TYPE_INT32)
.setOptions(FieldOptions.newBuilder().setPacked(true).build())
.build())
.build())
.build(),
new FileDescriptor[0]);
FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("a");
assertThat(field.features.getRepeatedFieldEncoding())
.isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED);
}

@Test
public void testLegacyInferProto3Expanded() {
FieldDescriptor field =
UnittestProto3.TestUnpackedTypes.getDescriptor().findFieldByName("repeated_int32");
public void testLegacyInferProto3Expanded() throws Exception {
FileDescriptor file =
FileDescriptor.buildFrom(
FileDescriptorProto.newBuilder()
.setName("some/filename/some.proto")
.setSyntax("proto3")
.addMessageType(
DescriptorProto.newBuilder()
.setName("Foo")
.addField(
FieldDescriptorProto.newBuilder()
.setName("a")
.setNumber(1)
.setType(FieldDescriptorProto.Type.TYPE_INT32)
.setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
.setOptions(FieldOptions.newBuilder().setPacked(false).build())
.build())
.build())
.build(),
new FileDescriptor[0]);
FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("a");
assertThat(field.features.getRepeatedFieldEncoding())
.isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED);
}
Expand All @@ -1302,9 +1376,16 @@ public void testLegacyInferProto2Utf8Validation() throws Exception {
}

@Test
public void testProto2Defaults() {
FieldDescriptor proto2Field = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
DescriptorProtos.FeatureSet features = proto2Field.features;
public void testProto2Defaults() throws Exception {
FileDescriptor proto2File =
FileDescriptor.buildFrom(
FileDescriptorProto.newBuilder()
.setName("some/filename/some.proto")
.setPackage("protobuf_unittest")
.setSyntax("proto2")
.build(),
new FileDescriptor[0]);
DescriptorProtos.FeatureSet features = proto2File.features;
assertThat(features.getFieldPresence())
.isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.EXPLICIT);
assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.CLOSED);
Expand All @@ -1323,10 +1404,16 @@ public void testProto2Defaults() {
}

@Test
public void testProto3Defaults() {
FieldDescriptor proto3Field =
UnittestProto3.TestAllTypes.getDescriptor().findFieldByName("optional_int32");
DescriptorProtos.FeatureSet features = proto3Field.features;
public void testProto3Defaults() throws Exception {
FileDescriptor proto3File =
FileDescriptor.buildFrom(
FileDescriptorProto.newBuilder()
.setName("some/filename/some.proto")
.setPackage("proto3_unittest")
.setSyntax("proto3")
.build(),
new FileDescriptor[0]);
DescriptorProtos.FeatureSet features = proto3File.features;
assertThat(features.getFieldPresence())
.isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.IMPLICIT);
assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.OPEN);
Expand Down
6 changes: 6 additions & 0 deletions python/descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,11 @@ static PyObject* PyUpb_FieldDescriptor_GetIsExtension(
return PyBool_FromLong(upb_FieldDef_IsExtension(self->def));
}

static PyObject* PyUpb_FieldDescriptor_GetIsPacked(PyUpb_DescriptorBase* self,
void* closure) {
return PyBool_FromLong(upb_FieldDef_IsPacked(self->def));
}

static PyObject* PyUpb_FieldDescriptor_GetNumber(PyUpb_DescriptorBase* self,
void* closure) {
return PyLong_FromLong(upb_FieldDef_Number(self->def));
Expand Down Expand Up @@ -1164,6 +1169,7 @@ static PyGetSetDef PyUpb_FieldDescriptor_Getters[] = {
"Default Value"},
{"has_default_value", (getter)PyUpb_FieldDescriptor_HasDefaultValue},
{"is_extension", (getter)PyUpb_FieldDescriptor_GetIsExtension, NULL, "ID"},
{"is_packed", (getter)PyUpb_FieldDescriptor_GetIsPacked, NULL, "Is Packed"},
// TODO
//{ "id", (getter)GetID, NULL, "ID"},
{"message_type", (getter)PyUpb_FieldDescriptor_GetMessageType, NULL,
Expand Down
7 changes: 4 additions & 3 deletions python/google/protobuf/internal/descriptor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@
from google.protobuf import symbol_database
from google.protobuf import text_format
from google.protobuf.internal import api_implementation
from google.protobuf.internal import test_proto2_pb2
from google.protobuf.internal import test_util
from google.protobuf.internal import testing_refleaks

from google.protobuf.internal import _parameterized
from google.protobuf import unittest_legacy_features_pb2
from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_features_pb2
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_legacy_features_pb2
from google.protobuf import unittest_pb2
from google.protobuf import unittest_proto3_pb2
from google.protobuf import unittest_proto3_extensions_pb2
from google.protobuf import unittest_proto3_pb2


TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """
Expand Down Expand Up @@ -1325,7 +1326,7 @@ def testLegacyInferProto3Expanded(self):
)

def testProto2Defaults(self):
features = unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name[
features = test_proto2_pb2.TestProto2.DESCRIPTOR.fields_by_name[
'optional_int32'
]._GetFeatures()
fs = descriptor_pb2.FeatureSet
Expand Down
22 changes: 12 additions & 10 deletions python/google/protobuf/internal/message_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1408,18 +1408,20 @@ def testDel(self):
del msg.repeated_nested_message

def testAssignInvalidEnum(self):
"""Assigning an invalid enum number is not allowed in proto2."""
"""Assigning an invalid enum number is not allowed for closed enums."""
m = unittest_pb2.TestAllTypes()

# Proto2 can not assign unknown enum.
with self.assertRaises(ValueError) as _:
m.optional_nested_enum = 1234567
self.assertRaises(ValueError, m.repeated_nested_enum.append, 1234567)
# Assignment is a different code path than append for the C++ impl.
m.repeated_nested_enum.append(2)
m.repeated_nested_enum[0] = 2
with self.assertRaises(ValueError):
m.repeated_nested_enum[0] = 123456
# TODO Enable these once upb's behavior is made conformant.
if api_implementation.Type() != 'upb':
# Can not assign unknown enum to closed enums.
with self.assertRaises(ValueError) as _:
m.optional_nested_enum = 1234567
self.assertRaises(ValueError, m.repeated_nested_enum.append, 1234567)
# Assignment is a different code path than append for the C++ impl.
m.repeated_nested_enum.append(2)
m.repeated_nested_enum[0] = 2
with self.assertRaises(ValueError):
m.repeated_nested_enum[0] = 123456

# Unknown enum value can be parsed but is ignored.
m2 = unittest_proto3_arena_pb2.TestAllTypes()
Expand Down
4 changes: 2 additions & 2 deletions python/google/protobuf/internal/reflection_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3259,13 +3259,13 @@ def testPackedOptions(self):
proto.optional_int32 = 1
proto.optional_double = 3.0
for field_descriptor, _ in proto.ListFields():
self.assertEqual(False, field_descriptor.GetOptions().packed)
self.assertEqual(False, field_descriptor.is_packed)

proto = unittest_pb2.TestPackedTypes()
proto.packed_int32.append(1)
proto.packed_double.append(3.0)
for field_descriptor, _ in proto.ListFields():
self.assertEqual(True, field_descriptor.GetOptions().packed)
self.assertEqual(True, field_descriptor.is_packed)
self.assertEqual(descriptor.FieldDescriptor.LABEL_REPEATED,
field_descriptor.label)

Expand Down
5 changes: 5 additions & 0 deletions python/google/protobuf/pyext/descriptor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,10 @@ static PyObject* IsExtension(PyBaseDescriptor *self, void *closure) {
return PyBool_FromLong(_GetDescriptor(self)->is_extension());
}

static PyObject* IsPacked(PyBaseDescriptor* self, void* closure) {
return PyBool_FromLong(_GetDescriptor(self)->is_packed());
}

static PyObject* HasDefaultValue(PyBaseDescriptor *self, void *closure) {
return PyBool_FromLong(_GetDescriptor(self)->has_default_value());
}
Expand Down Expand Up @@ -1050,6 +1054,7 @@ static PyGetSetDef Getters[] = {
{"default_value", (getter)GetDefaultValue, nullptr, "Default Value"},
{"has_default_value", (getter)HasDefaultValue},
{"is_extension", (getter)IsExtension, nullptr, "ID"},
{"is_packed", (getter)IsPacked, nullptr, "Is Packed"},
{"id", (getter)GetID, nullptr, "ID"},
{"_cdescriptor", (getter)GetCDescriptor, nullptr, "HAACK REMOVE ME"},

Expand Down
2 changes: 2 additions & 0 deletions src/google/protobuf/compiler/cpp/file_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ TEST(FileTest, TopologicallyOrderedDescriptors) {
"TestUnpackedTypes",
"TestUnpackedExtensions",
"TestReservedFields",
"TestRequiredOpenEnum",
"TestRequiredOneof.NestedMessage",
"TestRequiredNoMaskMulti",
"TestRequiredEnumNoMask",
Expand Down Expand Up @@ -111,6 +112,7 @@ TEST(FileTest, TopologicallyOrderedDescriptors) {
"RedactedFields.MapUnredactedStringEntry",
"RedactedFields.MapRedactedStringEntry",
"OptionalGroup_extension",
"OpenEnumMessage",
"OneString",
"OneBytes",
"MoreString",
Expand Down
12 changes: 8 additions & 4 deletions src/google/protobuf/descriptor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3558,8 +3558,10 @@ void Descriptor::DebugString(int depth, std::string* contents,
if (reserved_name_count() > 0) {
absl::SubstituteAndAppend(contents, "$0 reserved ", prefix);
for (int i = 0; i < reserved_name_count(); i++) {
absl::SubstituteAndAppend(contents, "\"$0\", ",
absl::CEscape(reserved_name(i)));
absl::SubstituteAndAppend(
contents,
file()->edition() < Edition::EDITION_2023 ? "\"$0\", " : "$0, ",
absl::CEscape(reserved_name(i)));
}
contents->replace(contents->size() - 2, 2, ";\n");
}
Expand Down Expand Up @@ -3778,8 +3780,10 @@ void EnumDescriptor::DebugString(
if (reserved_name_count() > 0) {
absl::SubstituteAndAppend(contents, "$0 reserved ", prefix);
for (int i = 0; i < reserved_name_count(); i++) {
absl::SubstituteAndAppend(contents, "\"$0\", ",
absl::CEscape(reserved_name(i)));
absl::SubstituteAndAppend(
contents,
file()->edition() < Edition::EDITION_2023 ? "\"$0\", " : "$0, ",
absl::CEscape(reserved_name(i)));
}
contents->replace(contents->size() - 2, 2, ";\n");
}
Expand Down
Loading
Loading