Skip to content

Commit 624d65d

Browse files
Fail building descriptors if ctype is used for fields other than string or bytes.
Instead of silently ignoring `[ctype = XXX]` for non string or bytes fields, this CL starts failing to build descriptors to call out the issue. This may cause failures to existing proto schemas but fixing them should be straightforward. PiperOrigin-RevId: 602441330
1 parent b25013b commit 624d65d

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

src/google/protobuf/descriptor.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7721,6 +7721,29 @@ void DescriptorBuilder::ValidateOptions(const FieldDescriptor* field,
77217721

77227722
ValidateFieldFeatures(field, proto);
77237723

7724+
// The following check is temporarily OSS only till we fix all affected
7725+
// google3 TAP tests.
7726+
if (field->options().has_ctype()) {
7727+
if (field->cpp_type() != FieldDescriptor::CPPTYPE_STRING) {
7728+
AddError(
7729+
field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE,
7730+
absl::StrFormat(
7731+
"Field %s specifies ctype, but is not a string nor bytes field.",
7732+
field->full_name())
7733+
.c_str());
7734+
}
7735+
if (field->options().ctype() == FieldOptions::CORD) {
7736+
if (field->is_extension()) {
7737+
AddError(field->full_name(), proto,
7738+
DescriptorPool::ErrorCollector::TYPE,
7739+
absl::StrFormat("Extension %s specifies ctype=CORD which is "
7740+
"not supported for extensions.",
7741+
field->full_name())
7742+
.c_str());
7743+
}
7744+
}
7745+
}
7746+
77247747
// Only message type fields may be lazy.
77257748
if (field->options().lazy() || field->options().unverified_lazy()) {
77267749
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {

src/google/protobuf/descriptor_unittest.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2943,6 +2943,26 @@ TEST_F(MiscTest, DefaultValues) {
29432943
EXPECT_EQ(enum_value_a, message->field(22)->default_value_enum());
29442944
}
29452945

2946+
TEST_F(MiscTest, InvalidFieldOptions) {
2947+
FileDescriptorProto file_proto;
2948+
file_proto.set_name("foo.proto");
2949+
2950+
DescriptorProto* message_proto = AddMessage(&file_proto, "TestMessage");
2951+
AddField(message_proto, "foo", 1, FieldDescriptorProto::LABEL_OPTIONAL,
2952+
FieldDescriptorProto::TYPE_INT32);
2953+
FieldDescriptorProto* bar_proto =
2954+
AddField(message_proto, "bar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
2955+
FieldDescriptorProto::TYPE_INT32);
2956+
2957+
FieldOptions* options = bar_proto->mutable_options();
2958+
options->set_ctype(FieldOptions::CORD);
2959+
2960+
// Expects it to fail as int32 fields cannot have ctype.
2961+
DescriptorPool pool;
2962+
const FileDescriptor* file = pool.BuildFile(file_proto);
2963+
EXPECT_EQ(file, nullptr);
2964+
}
2965+
29462966
TEST_F(MiscTest, FieldOptions) {
29472967
// Try setting field options.
29482968

@@ -2954,7 +2974,7 @@ TEST_F(MiscTest, FieldOptions) {
29542974
FieldDescriptorProto::TYPE_INT32);
29552975
FieldDescriptorProto* bar_proto =
29562976
AddField(message_proto, "bar", 2, FieldDescriptorProto::LABEL_OPTIONAL,
2957-
FieldDescriptorProto::TYPE_INT32);
2977+
FieldDescriptorProto::TYPE_BYTES);
29582978

29592979
FieldOptions* options = bar_proto->mutable_options();
29602980
options->set_ctype(FieldOptions::CORD);

0 commit comments

Comments
 (0)