Fix cord handling in DynamicMessage and oneofs.

This fixes a memory corruption vulnerability for anyone using cord with dynamically built descriptor pools.

PiperOrigin-RevId: 676091224
pull/18371/head
Mike Kruskal 6 months ago committed by Copybara-Service
parent aa5818d2aa
commit 9e8b30c213
  1. 2
      .bazelrc
  2. 2
      ci/common.bazelrc
  3. 2
      python/google/protobuf/internal/descriptor_test.py
  4. 2
      python/google/protobuf/internal/field_mask_test.py
  5. 3
      python/google/protobuf/internal/test_util.py
  6. 6
      python/google/protobuf/internal/unknown_fields_test.py
  7. 43
      src/google/protobuf/compiler/cpp/field.cc
  8. 5
      src/google/protobuf/compiler/cpp/field.h
  9. 2
      src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc
  10. 3
      src/google/protobuf/compiler/cpp/helpers.cc
  11. 10
      src/google/protobuf/compiler/cpp/tracker.cc
  12. 4
      src/google/protobuf/compiler/cpp/unittest.inc
  13. 3
      src/google/protobuf/descriptor.h
  14. 4
      src/google/protobuf/descriptor_unittest.cc
  15. 72
      src/google/protobuf/dynamic_message.cc
  16. 2
      src/google/protobuf/edition_unittest.proto
  17. 216
      src/google/protobuf/generated_message_reflection.cc
  18. 26
      src/google/protobuf/generated_message_tctable_gen.cc
  19. 6
      src/google/protobuf/generated_message_tctable_lite.cc
  20. 24
      src/google/protobuf/lite_unittest.cc
  21. 8
      src/google/protobuf/message.cc
  22. 17
      src/google/protobuf/test_util.h
  23. 12
      src/google/protobuf/test_util.inc
  24. 1
      src/google/protobuf/testdata/text_format_unittest_data.txt
  25. 1
      src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt
  26. 1
      src/google/protobuf/testdata/text_format_unittest_data_pointy.txt
  27. 1
      src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt
  28. 1
      src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
  29. 1
      src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt
  30. 3
      src/google/protobuf/unittest.proto
  31. 2
      src/google/protobuf/unittest_lite.proto
  32. 1
      src/google/protobuf/unittest_proto3_arena.proto
  33. 2
      src/google/protobuf/util/field_mask_util_test.cc
  34. 8
      src/google/protobuf/wire_format.cc

@ -26,6 +26,8 @@ build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
# Workaround for the fact that Bazel links with $CC, not $CXX # Workaround for the fact that Bazel links with $CC, not $CXX
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748 # https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
# Abseil passes nullptr to memcmp with 0 size
build:ubsan --copt=-fno-sanitize=nonnull-attribute
# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel # TODO: migrate all dependencies from WORKSPACE to MODULE.bazel
# https://github.com/protocolbuffers/protobuf/issues/14313 # https://github.com/protocolbuffers/protobuf/issues/14313

@ -31,6 +31,8 @@ build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
# Workaround for the fact that Bazel links with $CC, not $CXX # Workaround for the fact that Bazel links with $CC, not $CXX
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748 # https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
# Abseil passes nullptr to memcmp with 0 size
build:ubsan --copt=-fno-sanitize=nonnull-attribute
# Workaround Bazel 7 remote cache issues. # Workaround Bazel 7 remote cache issues.
# See https://github.com/bazelbuild/bazel/issues/20161 # See https://github.com/bazelbuild/bazel/issues/20161

@ -727,7 +727,7 @@ class GeneratedDescriptorTest(unittest.TestCase):
excepted_dict['new_key'] = 'new' excepted_dict['new_key'] = 'new'
self.assertNotEqual(mapping, excepted_dict) self.assertNotEqual(mapping, excepted_dict)
self.assertRaises(KeyError, mapping.__getitem__, 'key_error') self.assertRaises(KeyError, mapping.__getitem__, 'key_error')
self.assertRaises(KeyError, mapping.__getitem__, len(mapping) + 1) self.assertRaises(KeyError, mapping.__getitem__, len(mapping) * 2)
# TODO: Add __repr__ support for DescriptorMapping. # TODO: Add __repr__ support for DescriptorMapping.
if api_implementation.Type() == 'cpp': if api_implementation.Type() == 'cpp':
self.assertEqual(str(mapping)[0], '<') self.assertEqual(str(mapping)[0], '<')

@ -53,7 +53,7 @@ class FieldMaskTest(unittest.TestCase):
mask = field_mask_pb2.FieldMask() mask = field_mask_pb2.FieldMask()
msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
mask.AllFieldsFromDescriptor(msg_descriptor) mask.AllFieldsFromDescriptor(msg_descriptor)
self.assertEqual(79, len(mask.paths)) self.assertEqual(80, len(mask.paths))
self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
for field in msg_descriptor.fields: for field in msg_descriptor.fields:
self.assertTrue(field.name in mask.paths) self.assertTrue(field.name in mask.paths)

@ -77,6 +77,7 @@ def SetAllNonLazyFields(message):
message.optional_string_piece = u'124' message.optional_string_piece = u'124'
message.optional_cord = u'125' message.optional_cord = u'125'
message.optional_bytes_cord = b'optional bytes cord'
# #
# Repeated fields. # Repeated fields.
@ -247,6 +248,7 @@ def SetAllExtensions(message):
extensions[pb2.optional_string_piece_extension] = u'124' extensions[pb2.optional_string_piece_extension] = u'124'
extensions[pb2.optional_cord_extension] = u'125' extensions[pb2.optional_cord_extension] = u'125'
extensions[pb2.optional_bytes_cord_extension] = b'optional bytes cord'
# #
# Repeated fields. # Repeated fields.
@ -423,6 +425,7 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertTrue(message.HasField('optional_string_piece')) test_case.assertTrue(message.HasField('optional_string_piece'))
test_case.assertTrue(message.HasField('optional_cord')) test_case.assertTrue(message.HasField('optional_cord'))
test_case.assertTrue(message.HasField('optional_bytes_cord'))
test_case.assertEqual(101, message.optional_int32) test_case.assertEqual(101, message.optional_int32)
test_case.assertEqual(102, message.optional_int64) test_case.assertEqual(102, message.optional_int64)

@ -212,7 +212,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
unknown_field_set, unknown_field_set,
(17, 0, 117)) (17, 0, 117))
self.assertEqual(98, len(unknown_field_set)) self.assertEqual(99, len(unknown_field_set))
def testCopyFrom(self): def testCopyFrom(self):
message = unittest_pb2.TestEmptyMessage() message = unittest_pb2.TestEmptyMessage()
@ -250,7 +250,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
self.empty_message.Clear() self.empty_message.Clear()
# All cleared, even unknown fields. # All cleared, even unknown fields.
self.assertEqual(self.empty_message.SerializeToString(), b'') self.assertEqual(self.empty_message.SerializeToString(), b'')
self.assertEqual(len(unknown_field_set), 98) self.assertEqual(len(unknown_field_set), 99)
@unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4), @unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4),
'tracemalloc requires python 3.4+') 'tracemalloc requires python 3.4+')
@ -309,7 +309,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
def testUnknownExtensions(self): def testUnknownExtensions(self):
message = unittest_pb2.TestEmptyMessageWithExtensions() message = unittest_pb2.TestEmptyMessageWithExtensions()
message.ParseFromString(self.all_fields_data) message.ParseFromString(self.all_fields_data)
self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 98) self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 99)
self.assertEqual(message.SerializeToString(), self.all_fields_data) self.assertEqual(message.SerializeToString(), self.all_fields_data)

@ -130,7 +130,6 @@ FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* field,
break; break;
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
is_string_ = true; is_string_ = true;
string_type_ = field->options().ctype();
is_inlined_ = IsStringInlined(field, options); is_inlined_ = IsStringInlined(field, options);
is_bytes_ = field->type() == FieldDescriptor::TYPE_BYTES; is_bytes_ = field->type() == FieldDescriptor::TYPE_BYTES;
has_default_constexpr_constructor_ = is_repeated_or_map; has_default_constexpr_constructor_ = is_repeated_or_map;
@ -229,40 +228,6 @@ void FieldGeneratorBase::GenerateCopyConstructorCode(io::Printer* p) const {
} }
namespace { namespace {
// Use internal types instead of ctype or string_type.
enum class StringType {
kView,
kString,
kCord,
kStringPiece,
};
StringType GetStringType(const FieldDescriptor& field) {
ABSL_CHECK_EQ(field.cpp_type(), FieldDescriptor::CPPTYPE_STRING);
if (field.options().has_ctype()) {
switch (field.options().ctype()) {
case FieldOptions::CORD:
return StringType::kCord;
case FieldOptions::STRING_PIECE:
return StringType::kStringPiece;
default:
return StringType::kString;
}
}
const pb::CppFeatures& cpp_features =
CppGenerator::GetResolvedSourceFeatures(field).GetExtension(::pb::cpp);
switch (cpp_features.string_type()) {
case pb::CppFeatures::CORD:
return StringType::kCord;
case pb::CppFeatures::VIEW:
return StringType::kView;
default:
return StringType::kString;
}
}
std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field, std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
const Options& options, const Options& options,
MessageSCCAnalyzer* scc) { MessageSCCAnalyzer* scc) {
@ -279,7 +244,7 @@ std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
return MakeRepeatedMessageGenerator(field, options, scc); return MakeRepeatedMessageGenerator(field, options, scc);
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
if (GetStringType(*field) == StringType::kView) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kView) {
return MakeRepeatedStringViewGenerator(field, options, scc); return MakeRepeatedStringViewGenerator(field, options, scc);
} else { } else {
return MakeRepeatedStringGenerator(field, options, scc); return MakeRepeatedStringGenerator(field, options, scc);
@ -303,10 +268,10 @@ std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
return MakeSinguarEnumGenerator(field, options, scc); return MakeSinguarEnumGenerator(field, options, scc);
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (GetStringType(*field)) { switch (field->cpp_string_type()) {
case StringType::kView: case FieldDescriptor::CppStringType::kView:
return MakeSingularStringViewGenerator(field, options, scc); return MakeSingularStringViewGenerator(field, options, scc);
case StringType::kCord: case FieldDescriptor::CppStringType::kCord:
if (field->type() == FieldDescriptor::TYPE_BYTES) { if (field->type() == FieldDescriptor::TYPE_BYTES) {
if (field->real_containing_oneof()) { if (field->real_containing_oneof()) {
return MakeOneofCordGenerator(field, options, scc); return MakeOneofCordGenerator(field, options, scc);

@ -95,9 +95,6 @@ class FieldGeneratorBase {
// Returns true if the field API uses bytes (void) instead of chars. // Returns true if the field API uses bytes (void) instead of chars.
bool is_bytes() const { return is_bytes_; } bool is_bytes() const { return is_bytes_; }
// Returns the public API string type for string fields.
FieldOptions::CType string_type() const { return string_type_; }
// Returns true if this field is part of a oneof field. // Returns true if this field is part of a oneof field.
bool is_oneof() const { return is_oneof_; } bool is_oneof() const { return is_oneof_; }
@ -217,7 +214,6 @@ class FieldGeneratorBase {
bool is_lazy_ = false; bool is_lazy_ = false;
bool is_weak_ = false; bool is_weak_ = false;
bool is_oneof_ = false; bool is_oneof_ = false;
FieldOptions::CType string_type_ = FieldOptions::STRING;
bool has_default_constexpr_constructor_ = false; bool has_default_constexpr_constructor_ = false;
}; };
@ -269,7 +265,6 @@ class FieldGenerator {
bool is_foreign() const { return impl_->is_foreign(); } bool is_foreign() const { return impl_->is_foreign(); }
bool is_string() const { return impl_->is_string(); } bool is_string() const { return impl_->is_string(); }
bool is_bytes() const { return impl_->is_bytes(); } bool is_bytes() const { return impl_->is_bytes(); }
FieldOptions::CType string_type() const { return impl_->string_type(); }
bool is_oneof() const { return impl_->is_oneof(); } bool is_oneof() const { return impl_->is_oneof(); }
bool is_inlined() const { return impl_->is_inlined(); } bool is_inlined() const { return impl_->is_inlined(); }
bool has_default_constexpr_constructor() const { bool has_default_constexpr_constructor() const {

@ -216,8 +216,6 @@ void SingularStringView::GenerateStaticMembers(io::Printer* p) const {
} }
void SingularStringView::GenerateAccessorDeclarations(io::Printer* p) const { void SingularStringView::GenerateAccessorDeclarations(io::Printer* p) const {
ABSL_CHECK(!field_->options().has_ctype());
auto v1 = p->WithVars(AnnotatedAccessors(field_, {""})); auto v1 = p->WithVars(AnnotatedAccessors(field_, {""}));
auto v2 = p->WithVars( auto v2 = p->WithVars(
AnnotatedAccessors(field_, {"set_"}, AnnotationCollector::kSet)); AnnotatedAccessors(field_, {"set_"}, AnnotationCollector::kSet));

@ -1597,7 +1597,8 @@ MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
switch (field->type()) { switch (field->type()) {
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (field->options().ctype() == FieldOptions::CORD) { if (field->cpp_string_type() ==
FieldDescriptor::CppStringType::kCord) {
result.contains_cord = true; result.contains_cord = true;
} }
break; break;

@ -221,7 +221,8 @@ Getters RepeatedFieldGetters(const FieldDescriptor* field,
Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) { Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) {
std::string member = FieldMemberName(field, ShouldSplit(field, opts)); std::string member = FieldMemberName(field, ShouldSplit(field, opts));
bool is_std_string = field->options().ctype() == FieldOptions::STRING; bool is_std_string =
field->cpp_string_type() == FieldDescriptor::CppStringType::kString;
Getters getters; Getters getters;
if (is_std_string && !field->default_value_string().empty()) { if (is_std_string && !field->default_value_string().empty()) {
@ -241,7 +242,8 @@ Getters StringOneofGetters(const FieldDescriptor* field,
ABSL_CHECK(oneof != nullptr); ABSL_CHECK(oneof != nullptr);
std::string member = FieldMemberName(field, ShouldSplit(field, opts)); std::string member = FieldMemberName(field, ShouldSplit(field, opts));
bool is_std_string = field->options().ctype() == FieldOptions::STRING; bool is_std_string =
field->cpp_string_type() == FieldDescriptor::CppStringType::kString;
std::string field_ptr = member; std::string field_ptr = member;
if (is_std_string) { if (is_std_string) {
@ -258,8 +260,8 @@ Getters StringOneofGetters(const FieldDescriptor* field,
} }
Getters getters; Getters getters;
if (field->default_value_string().empty() || if (field->default_value_string().empty()
field->options().ctype() == FieldOptions::STRING_PIECE) { ) {
getters.base = absl::Substitute("$0 ? $1 : nullptr", has, field_ptr); getters.base = absl::Substitute("$0 ? $1 : nullptr", has, field_ptr);
} else { } else {
getters.base = getters.base =

@ -428,6 +428,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
message1.set_optional_string("abc"); message1.set_optional_string("abc");
message1.mutable_optional_nested_message()->set_bb(1); message1.mutable_optional_nested_message()->set_bb(1);
message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO); message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO);
message1.set_optional_bytes_cord("bytes cord");
message1.add_repeated_int32(1); message1.add_repeated_int32(1);
message1.add_repeated_int32(2); message1.add_repeated_int32(2);
message1.add_repeated_string("a"); message1.add_repeated_string("a");
@ -441,6 +442,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
message2.set_optional_string("def"); message2.set_optional_string("def");
message2.mutable_optional_nested_message()->set_bb(2); message2.mutable_optional_nested_message()->set_bb(2);
message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR); message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR);
message2.set_optional_bytes_cord("bytes cord");
message2.add_repeated_int32(3); message2.add_repeated_int32(3);
message2.add_repeated_string("c"); message2.add_repeated_string("c");
message2.add_repeated_nested_message()->set_bb(9); message2.add_repeated_nested_message()->set_bb(9);
@ -452,6 +454,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
EXPECT_EQ("def", message1.optional_string()); EXPECT_EQ("def", message1.optional_string());
EXPECT_EQ(2, message1.optional_nested_message().bb()); EXPECT_EQ(2, message1.optional_nested_message().bb());
EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum()); EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum());
EXPECT_EQ(absl::Cord("bytes cord"), message1.optional_bytes_cord());
ASSERT_EQ(1, message1.repeated_int32_size()); ASSERT_EQ(1, message1.repeated_int32_size());
EXPECT_EQ(3, message1.repeated_int32(0)); EXPECT_EQ(3, message1.repeated_int32(0));
ASSERT_EQ(1, message1.repeated_string_size()); ASSERT_EQ(1, message1.repeated_string_size());
@ -465,6 +468,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
EXPECT_EQ("abc", message2.optional_string()); EXPECT_EQ("abc", message2.optional_string());
EXPECT_EQ(1, message2.optional_nested_message().bb()); EXPECT_EQ(1, message2.optional_nested_message().bb());
EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum()); EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum());
EXPECT_EQ(absl::Cord("bytes cord"), message2.optional_bytes_cord());
ASSERT_EQ(2, message2.repeated_int32_size()); ASSERT_EQ(2, message2.repeated_int32_size());
EXPECT_EQ(1, message2.repeated_int32(0)); EXPECT_EQ(1, message2.repeated_int32(0));
EXPECT_EQ(2, message2.repeated_int32(1)); EXPECT_EQ(2, message2.repeated_int32(1));

@ -2954,7 +2954,8 @@ PROTOBUF_EXPORT bool HasHasbit(const FieldDescriptor* field);
template <typename FieldDesc = FieldDescriptor, template <typename FieldDesc = FieldDescriptor,
typename FieldOpts = FieldOptions> typename FieldOpts = FieldOptions>
typename FieldOpts::CType EffectiveStringCType(const FieldDesc* field) { typename FieldOpts::CType EffectiveStringCType(const FieldDesc* field) {
// TODO Replace this function with FieldDescriptor::string_type; // TODO Replace this function with
// FieldDescriptor::cpp_string_type;
switch (field->cpp_string_type()) { switch (field->cpp_string_type()) {
case FieldDescriptor::CppStringType::kCord: case FieldDescriptor::CppStringType::kCord:
return FieldOpts::CORD; return FieldOpts::CORD;

@ -7571,7 +7571,7 @@ TEST_F(FeaturesTest, Proto2Features) {
name: "cord" name: "cord"
number: 8 number: 8
label: LABEL_OPTIONAL label: LABEL_OPTIONAL
type: TYPE_STRING type: TYPE_BYTES
options { ctype: CORD } options { ctype: CORD }
} }
field { field {
@ -7656,6 +7656,8 @@ TEST_F(FeaturesTest, Proto2Features) {
EXPECT_EQ(message->FindFieldByName("str")->cpp_string_type(), EXPECT_EQ(message->FindFieldByName("str")->cpp_string_type(),
FieldDescriptor::CppStringType::kString); FieldDescriptor::CppStringType::kString);
EXPECT_EQ(message->FindFieldByName("cord")->cpp_string_type(),
FieldDescriptor::CppStringType::kCord);
// Check round-trip consistency. // Check round-trip consistency.
FileDescriptorProto proto; FileDescriptorProto proto;

@ -117,9 +117,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
} }
case FD::CPPTYPE_STRING: case FD::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: return sizeof(RepeatedField<absl::Cord>);
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return sizeof(RepeatedPtrField<std::string>); return sizeof(RepeatedPtrField<std::string>);
} }
break; break;
@ -147,9 +149,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
return sizeof(Message*); return sizeof(Message*);
case FD::CPPTYPE_STRING: case FD::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: return sizeof(absl::Cord);
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return sizeof(ArenaStringPtr); return sizeof(ArenaStringPtr);
} }
break; break;
@ -399,9 +403,31 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
break; break;
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: if (!field->is_repeated()) {
if (field->has_default_value()) {
new (field_ptr) absl::Cord(field->default_value_string());
} else {
new (field_ptr) absl::Cord;
}
if (arena != nullptr) {
// Cord does not support arena so here we need to notify arena
// to remove the data it allocated on the heap by calling its
// destructor.
arena->OwnDestructor(static_cast<absl::Cord*>(field_ptr));
}
} else {
new (field_ptr) RepeatedField<absl::Cord>(arena);
if (arena != nullptr) {
// Needs to destroy Cord elements.
arena->OwnDestructor(
static_cast<RepeatedField<absl::Cord>*>(field_ptr));
}
}
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
if (!field->is_repeated()) { if (!field->is_repeated()) {
ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr(); ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
asp->InitDefault(); asp->InitDefault();
@ -491,9 +517,12 @@ DynamicMessage::~DynamicMessage() {
if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) { if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) {
field_ptr = MutableOneofFieldRaw(field); field_ptr = MutableOneofFieldRaw(field);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: { delete *reinterpret_cast<absl::Cord**>(field_ptr);
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString: {
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
break; break;
} }
@ -525,9 +554,13 @@ DynamicMessage::~DynamicMessage() {
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: reinterpret_cast<RepeatedField<absl::Cord>*>(field_ptr)
->~RepeatedField<absl::Cord>();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
reinterpret_cast<RepeatedPtrField<std::string>*>(field_ptr) reinterpret_cast<RepeatedPtrField<std::string>*>(field_ptr)
->~RepeatedPtrField<std::string>(); ->~RepeatedPtrField<std::string>();
break; break;
@ -545,9 +578,12 @@ DynamicMessage::~DynamicMessage() {
} }
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: { reinterpret_cast<absl::Cord*>(field_ptr)->~Cord();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString: {
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
break; break;
} }

@ -91,6 +91,7 @@ message TestAllTypes {
string optional_string_piece = 24 [ctype=STRING_PIECE]; string optional_string_piece = 24 [ctype=STRING_PIECE];
string optional_cord = 25 [ctype=CORD]; string optional_cord = 25 [ctype=CORD];
bytes optional_bytes_cord = 86 [ctype=CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
protobuf_unittest_import.PublicImportMessage protobuf_unittest_import.PublicImportMessage
@ -266,6 +267,7 @@ extend TestAllExtensions {
// TODO: ctype=CORD is not supported for extension. Add // TODO: ctype=CORD is not supported for extension. Add
// ctype=CORD option back after it is supported. // ctype=CORD option back after it is supported.
string optional_cord_extension = 25; string optional_cord_extension = 25;
bytes optional_bytes_cord_extension = 86;
protobuf_unittest_import.PublicImportMessage protobuf_unittest_import.PublicImportMessage
optional_public_import_message_extension = 26; optional_public_import_message_extension = 26;

@ -403,9 +403,13 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: total_size += GetRaw<RepeatedField<absl::Cord>>(message, field)
.SpaceUsedExcludingSelfLong();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
total_size += total_size +=
GetRaw<RepeatedPtrField<std::string> >(message, field) GetRaw<RepeatedPtrField<std::string> >(message, field)
.SpaceUsedExcludingSelfLong(); .SpaceUsedExcludingSelfLong();
@ -444,8 +448,8 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
break; break;
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
total_size += GetField<absl::Cord*>(message, field) total_size += GetField<absl::Cord*>(message, field)
->EstimatedMemoryUsage(); ->EstimatedMemoryUsage();
@ -457,8 +461,8 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
sizeof(absl::Cord); sizeof(absl::Cord);
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
const std::string* ptr = const std::string* ptr =
&GetField<InlinedStringField>(message, field).GetNoArena(); &GetField<InlinedStringField>(message, field).GetNoArena();
@ -554,15 +558,14 @@ struct OneofFieldMover {
to->SetString(from->GetString()); to->SetString(from->GetString());
break; break;
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
to->SetCord(from->GetCord()); to->SetCord(from->GetCord());
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString:
to->SetArenaStringPtr(from->GetArenaStringPtr()); to->SetArenaStringPtr(from->GetArenaStringPtr());
break; break;
}
} }
break; break;
default: default:
@ -625,9 +628,19 @@ template <bool unsafe_shallow_swap>
void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs, void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs,
Message* rhs, Message* rhs,
const FieldDescriptor* field) { const FieldDescriptor* field) {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: case FieldDescriptor::CppStringType::kCord: {
case FieldOptions::STRING: { auto* lhs_cord = r->MutableRaw<RepeatedField<absl::Cord>>(lhs, field);
auto* rhs_cord = r->MutableRaw<RepeatedField<absl::Cord>>(rhs, field);
if (unsafe_shallow_swap) {
lhs_cord->InternalSwap(rhs_cord);
} else {
lhs_cord->Swap(rhs_cord);
}
break;
}
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString: {
auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field); auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field);
auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field); auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field);
if (unsafe_shallow_swap) { if (unsafe_shallow_swap) {
@ -691,14 +704,14 @@ template <bool unsafe_shallow_swap>
void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs, void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
Message* rhs, Message* rhs,
const FieldDescriptor* field) { const FieldDescriptor* field) {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
// Always shallow swap for Cord. // Always shallow swap for Cord.
std::swap(*r->MutableRaw<absl::Cord>(lhs, field), std::swap(*r->MutableRaw<absl::Cord>(lhs, field),
*r->MutableRaw<absl::Cord>(rhs, field)); *r->MutableRaw<absl::Cord>(rhs, field));
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
if (r->IsInlined(field)) { if (r->IsInlined(field)) {
SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs, SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
field); field);
@ -1162,7 +1175,9 @@ void Reflection::SwapFieldsImpl(
// may depend on the information in has bits. // may depend on the information in has bits.
if (!field->is_repeated()) { if (!field->is_repeated()) {
SwapHasBit(message1, message2, field); SwapHasBit(message1, message2, field);
if (field->options().ctype() == FieldOptions::STRING && if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
field->cpp_string_type() ==
FieldDescriptor::CppStringType::kString &&
IsInlined(field)) { IsInlined(field)) {
ABSL_DCHECK(!unsafe_shallow_swap || ABSL_DCHECK(!unsafe_shallow_swap ||
message1->GetArena() == message2->GetArena()); message1->GetArena() == message2->GetArena());
@ -1276,9 +1291,10 @@ void Reflection::InternalSwap(Message* lhs, Message* rhs) const {
int inlined_string_count = 0; int inlined_string_count = 0;
for (int i = 0; i < descriptor_->field_count(); i++) { for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i); const FieldDescriptor* field = descriptor_->field(i);
if (field->cpp_type() != FieldDescriptor::CPPTYPE_STRING) continue;
if (field->is_extension() || field->is_repeated() || if (field->is_extension() || field->is_repeated() ||
schema_.InRealOneof(field) || schema_.InRealOneof(field) ||
field->options().ctype() != FieldOptions::STRING || field->cpp_string_type() != FieldDescriptor::CppStringType::kString ||
!IsInlined(field)) { !IsInlined(field)) {
continue; continue;
} }
@ -1330,6 +1346,10 @@ int Reflection::FieldSize(const Message& message,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
return GetRaw<RepeatedField<absl::Cord> >(message, field).size();
}
ABSL_FALLTHROUGH_INTENDED;
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
if (IsMapFieldInApi(field)) { if (IsMapFieldInApi(field)) {
const internal::MapFieldBase& map = const internal::MapFieldBase& map =
@ -1388,8 +1408,8 @@ void Reflection::ClearField(Message* message,
break; break;
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (field->has_default_value()) { if (field->has_default_value()) {
*MutableRaw<absl::Cord>(message, field) = *MutableRaw<absl::Cord>(message, field) =
field->default_value_string(); field->default_value_string();
@ -1397,8 +1417,8 @@ void Reflection::ClearField(Message* message,
MutableRaw<absl::Cord>(message, field)->Clear(); MutableRaw<absl::Cord>(message, field)->Clear();
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
// Currently, string with default value can't be inlined. So we // Currently, string with default value can't be inlined. So we
// don't have to handle default value here. // don't have to handle default value here.
@ -1445,9 +1465,12 @@ void Reflection::ClearField(Message* message,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: MutableRaw<RepeatedField<absl::Cord>>(message, field)->Clear();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
MutableRaw<RepeatedPtrField<std::string> >(message, field)->Clear(); MutableRaw<RepeatedPtrField<std::string> >(message, field)->Clear();
break; break;
} }
@ -1495,9 +1518,12 @@ void Reflection::RemoveLast(Message* message,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: MutableRaw<RepeatedField<absl::Cord>>(message, field)->RemoveLast();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
MutableRaw<RepeatedPtrField<std::string> >(message, field) MutableRaw<RepeatedPtrField<std::string> >(message, field)
->RemoveLast(); ->RemoveLast();
break; break;
@ -1589,6 +1615,12 @@ void Reflection::SwapElements(Message* message, const FieldDescriptor* field,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
MutableRaw<RepeatedField<absl::Cord> >(message, field)
->SwapElements(index1, index2);
break;
}
ABSL_FALLTHROUGH_INTENDED;
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
if (IsMapFieldInApi(field)) { if (IsMapFieldInApi(field)) {
MutableRaw<MapFieldBase>(message, field) MutableRaw<MapFieldBase>(message, field)
@ -1795,15 +1827,15 @@ std::string Reflection::GetString(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return std::string(field->default_value_string()); return std::string(field->default_value_string());
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
return std::string(*GetField<absl::Cord*>(message, field)); return std::string(*GetField<absl::Cord*>(message, field));
} else { } else {
return std::string(GetField<absl::Cord>(message, field)); return std::string(GetField<absl::Cord>(message, field));
} }
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena(); return GetField<InlinedStringField>(message, field).GetNoArena();
} else { } else {
@ -1812,6 +1844,7 @@ std::string Reflection::GetString(const Message& message,
: str.Get(); : str.Get();
} }
} }
internal::Unreachable();
} }
} }
@ -1827,8 +1860,8 @@ const std::string& Reflection::GetStringReference(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return internal::DefaultValueStringAsString(field); return internal::DefaultValueStringAsString(field);
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
absl::CopyCordToString(*GetField<absl::Cord*>(message, field), absl::CopyCordToString(*GetField<absl::Cord*>(message, field),
scratch); scratch);
@ -1836,8 +1869,8 @@ const std::string& Reflection::GetStringReference(const Message& message,
absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch); absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch);
} }
return *scratch; return *scratch;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena(); return GetField<InlinedStringField>(message, field).GetNoArena();
} else { } else {
@ -1846,6 +1879,7 @@ const std::string& Reflection::GetStringReference(const Message& message,
: str.Get(); : str.Get();
} }
} }
internal::Unreachable();
} }
} }
@ -1859,15 +1893,15 @@ absl::Cord Reflection::GetCord(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return absl::Cord(field->default_value_string()); return absl::Cord(field->default_value_string());
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
return *GetField<absl::Cord*>(message, field); return *GetField<absl::Cord*>(message, field);
} else { } else {
return GetField<absl::Cord>(message, field); return GetField<absl::Cord>(message, field);
} }
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
return absl::Cord( return absl::Cord(
GetField<InlinedStringField>(message, field).GetNoArena()); GetField<InlinedStringField>(message, field).GetNoArena());
@ -1877,9 +1911,7 @@ absl::Cord Reflection::GetCord(const Message& message,
: str.Get()); : str.Get());
} }
} }
internal::Unreachable();
ABSL_LOG(FATAL) << "Can't get here.";
return absl::Cord(); // Make compiler happy.
} }
} }
@ -1896,8 +1928,8 @@ absl::string_view Reflection::GetStringView(const Message& message,
return field->default_value_string(); return field->default_value_string();
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: { case FieldDescriptor::CppStringType::kCord: {
const auto& cord = schema_.InRealOneof(field) const auto& cord = schema_.InRealOneof(field)
? *GetField<absl::Cord*>(message, field) ? *GetField<absl::Cord*>(message, field)
: GetField<absl::Cord>(message, field); : GetField<absl::Cord>(message, field);
@ -1917,8 +1949,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
return MutableExtensionSet(message)->SetString( return MutableExtensionSet(message)->SetString(
field->number(), field->type(), std::move(value), field); field->number(), field->type(), std::move(value), field);
} else { } else {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
if (!HasOneofField(*message, field)) { if (!HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof()); ClearOneof(message, field->containing_oneof());
@ -1930,8 +1962,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
} }
*MutableField<absl::Cord>(message, field) = value; *MutableField<absl::Cord>(message, field) = value;
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
if (IsInlined(field)) { if (IsInlined(field)) {
const uint32_t index = schema_.InlinedStringIndex(field); const uint32_t index = schema_.InlinedStringIndex(field);
ABSL_DCHECK_GT(index, 0u); ABSL_DCHECK_GT(index, 0u);
@ -1969,8 +2001,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
MutableExtensionSet(message)->MutableString( MutableExtensionSet(message)->MutableString(
field->number(), field->type(), field)); field->number(), field->type(), field));
} else { } else {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
if (!HasOneofField(*message, field)) { if (!HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof()); ClearOneof(message, field->containing_oneof());
@ -1982,8 +2014,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
*MutableField<absl::Cord>(message, field) = value; *MutableField<absl::Cord>(message, field) = value;
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
// Oneof string fields are never set as a default instance. // Oneof string fields are never set as a default instance.
// We just need to pass some arbitrary default string to make it work. // We just need to pass some arbitrary default string to make it work.
// This allows us to not have the real default accessible from // This allows us to not have the real default accessible from
@ -2019,11 +2051,14 @@ std::string Reflection::GetRepeatedString(const Message& message,
if (field->is_extension()) { if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index); return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: return std::string(GetRepeatedField<absl::Cord>(message, field, index));
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetRepeatedPtrField<std::string>(message, field, index); return GetRepeatedPtrField<std::string>(message, field, index);
} }
internal::Unreachable();
} }
} }
@ -2035,11 +2070,16 @@ const std::string& Reflection::GetRepeatedStringReference(
if (field->is_extension()) { if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index); return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: absl::CopyCordToString(
GetRepeatedField<absl::Cord>(message, field, index), scratch);
return *scratch;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetRepeatedPtrField<std::string>(message, field, index); return GetRepeatedPtrField<std::string>(message, field, index);
} }
internal::Unreachable();
} }
} }
@ -2054,11 +2094,16 @@ absl::string_view Reflection::GetRepeatedStringView(
return GetExtensionSet(message).GetRepeatedString(field->number(), index); return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kCord: {
default: auto& cord = GetRepeatedField<absl::Cord>(message, field, index);
return scratch.CopyFromCord(cord);
}
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetRepeatedPtrField<std::string>(message, field, index); return GetRepeatedPtrField<std::string>(message, field, index);
} }
internal::Unreachable();
} }
@ -2070,9 +2115,12 @@ void Reflection::SetRepeatedString(Message* message,
MutableExtensionSet(message)->SetRepeatedString(field->number(), index, MutableExtensionSet(message)->SetRepeatedString(field->number(), index,
std::move(value)); std::move(value));
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: SetRepeatedField<absl::Cord>(message, field, index, absl::Cord(value));
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
MutableRepeatedField<std::string>(message, field, index) MutableRepeatedField<std::string>(message, field, index)
->assign(std::move(value)); ->assign(std::move(value));
break; break;
@ -2088,9 +2136,12 @@ void Reflection::AddString(Message* message, const FieldDescriptor* field,
MutableExtensionSet(message)->AddString(field->number(), field->type(), MutableExtensionSet(message)->AddString(field->number(), field->type(),
std::move(value), field); std::move(value), field);
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: AddField<absl::Cord>(message, field, absl::Cord(value));
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
AddField<std::string>(message, field)->assign(std::move(value)); AddField<std::string>(message, field)->assign(std::move(value));
break; break;
} }
@ -2618,7 +2669,8 @@ const void* Reflection::GetRawRepeatedField(const Message& message,
ReportReflectionUsageTypeError(descriptor_, field, "GetRawRepeatedField", ReportReflectionUsageTypeError(descriptor_, field, "GetRawRepeatedField",
cpptype); cpptype);
if (ctype >= 0) if (ctype >= 0)
ABSL_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch"; ABSL_CHECK_EQ(internal::cpp::EffectiveStringCType(field), ctype)
<< "subtype mismatch";
if (desc != nullptr) if (desc != nullptr)
ABSL_CHECK_EQ(field->message_type(), desc) << "wrong submessage type"; ABSL_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
if (field->is_extension()) { if (field->is_extension()) {
@ -2744,7 +2796,7 @@ static Type* AllocIfDefault(const FieldDescriptor* field, Type*& ptr,
// be e.g. char). // be e.g. char).
if (field->cpp_type() < FieldDescriptor::CPPTYPE_STRING || if (field->cpp_type() < FieldDescriptor::CPPTYPE_STRING ||
(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD)) { field->cpp_string_type() == FieldDescriptor::CppStringType::kCord)) {
ptr = ptr =
reinterpret_cast<Type*>(Arena::Create<RepeatedField<int32_t>>(arena)); reinterpret_cast<Type*>(Arena::Create<RepeatedField<int32_t>>(arena));
} else { } else {
@ -2923,11 +2975,11 @@ bool Reflection::HasFieldSingular(const Message& message,
// (which uses HasField()) needs to be consistent with this. // (which uses HasField()) needs to be consistent with this.
switch (field->cpp_type()) { switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
return !GetField<const absl::Cord>(message, field).empty(); return !GetField<const absl::Cord>(message, field).empty();
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
if (IsInlined(field)) { if (IsInlined(field)) {
return !GetField<InlinedStringField>(message, field) return !GetField<InlinedStringField>(message, field)
.GetNoArena() .GetNoArena()
@ -2937,7 +2989,7 @@ bool Reflection::HasFieldSingular(const Message& message,
return GetField<ArenaStringPtr>(message, field).Get().size() > 0; return GetField<ArenaStringPtr>(message, field).Get().size() > 0;
} }
} }
return false; internal::Unreachable();
case FieldDescriptor::CPPTYPE_BOOL: case FieldDescriptor::CPPTYPE_BOOL:
return GetRaw<bool>(message, field) != false; return GetRaw<bool>(message, field) != false;
case FieldDescriptor::CPPTYPE_INT32: case FieldDescriptor::CPPTYPE_INT32:
@ -3039,12 +3091,12 @@ void Reflection::ClearOneof(Message* message,
if (message->GetArena() == nullptr) { if (message->GetArena() == nullptr) {
switch (field->cpp_type()) { switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
delete *MutableRaw<absl::Cord*>(message, field); delete *MutableRaw<absl::Cord*>(message, field);
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
// Oneof string fields are never set as a default instance. // Oneof string fields are never set as a default instance.
// We just need to pass some arbitrary default string to make it // We just need to pass some arbitrary default string to make it
// work. This allows us to not have the real default accessible // work. This allows us to not have the real default accessible

@ -167,10 +167,10 @@ TailCallTableInfo::FastFieldInfo::Field MakeFastFieldEntry(
: field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \ : field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \
: PROTOBUF_PICK_FUNCTION(fn##S)) : PROTOBUF_PICK_FUNCTION(fn##S))
#define PROTOBUF_PICK_STRING_FUNCTION(fn) \ #define PROTOBUF_PICK_STRING_FUNCTION(fn) \
(field->options().ctype() == FieldOptions::CORD \ (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord \
? PROTOBUF_PICK_FUNCTION(fn##cS) \ ? PROTOBUF_PICK_FUNCTION(fn##cS) \
: options.is_string_inlined ? PROTOBUF_PICK_FUNCTION(fn##iS) \ : options.is_string_inlined ? PROTOBUF_PICK_FUNCTION(fn##iS) \
: PROTOBUF_PICK_REPEATABLE_FUNCTION(fn)) : PROTOBUF_PICK_REPEATABLE_FUNCTION(fn))
const FieldDescriptor* field = entry.field; const FieldDescriptor* field = entry.field;
@ -303,10 +303,12 @@ bool IsFieldEligibleForFastParsing(
switch (field->type()) { switch (field->type()) {
// Some bytes fields can be handled on fast path. // Some bytes fields can be handled on fast path.
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: case FieldDescriptor::TYPE_BYTES: {
if (field->options().ctype() == FieldOptions::STRING) { auto ctype = field->cpp_string_type();
if (ctype == FieldDescriptor::CppStringType::kString ||
ctype == FieldDescriptor::CppStringType::kView) {
// strings are fine... // strings are fine...
} else if (field->options().ctype() == FieldOptions::CORD) { } else if (ctype == FieldDescriptor::CppStringType::kCord) {
// Cords are worth putting into the fast table, if they're not repeated // Cords are worth putting into the fast table, if they're not repeated
if (field->is_repeated()) return false; if (field->is_repeated()) return false;
} else { } else {
@ -320,6 +322,7 @@ bool IsFieldEligibleForFastParsing(
aux_idx = entry.inlined_string_idx; aux_idx = entry.inlined_string_idx;
} }
break; break;
}
case FieldDescriptor::TYPE_ENUM: { case FieldDescriptor::TYPE_ENUM: {
uint8_t rmax_value; uint8_t rmax_value;
@ -758,12 +761,13 @@ uint16_t MakeTypeCardForField(
// Fill in extra information about string and bytes field representations. // Fill in extra information about string and bytes field representations.
if (field->type() == FieldDescriptor::TYPE_BYTES || if (field->type() == FieldDescriptor::TYPE_BYTES ||
field->type() == FieldDescriptor::TYPE_STRING) { field->type() == FieldDescriptor::TYPE_STRING) {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
// `Cord` is always used, even for repeated fields. // `Cord` is always used, even for repeated fields.
type_card |= fl::kRepCord; type_card |= fl::kRepCord;
break; break;
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
if (field->is_repeated()) { if (field->is_repeated()) {
// A repeated string field uses RepeatedPtrField<std::string> // A repeated string field uses RepeatedPtrField<std::string>
// (unless it has a ctype option; see above). // (unless it has a ctype option; see above).
@ -773,8 +777,6 @@ uint16_t MakeTypeCardForField(
type_card |= fl::kRepAString; type_card |= fl::kRepAString;
} }
break; break;
default:
Unreachable();
} }
} }

@ -1647,6 +1647,12 @@ bool TcParser::ChangeOneof(const TcParseTableBase* table,
field.Destroy(); field.Destroy();
break; break;
} }
case field_layout::kRepCord: {
if (msg->GetArena() == nullptr) {
delete RefAt<absl::Cord*>(msg, current_entry->offset);
}
break;
}
case field_layout::kRepSString: case field_layout::kRepSString:
case field_layout::kRepIString: case field_layout::kRepIString:
default: default:

@ -960,6 +960,18 @@ TYPED_TEST(LiteTest, AllLite43) {
EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream)); EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
EXPECT_EQ(17, message2.oneof_int32()); EXPECT_EQ(17, message2.oneof_int32());
} }
// Bytes [ctype = CORD]
{
protobuf_unittest::TestOneofParsingLite message2;
message2.set_oneof_bytes_cord("bytes cord");
io::CodedInputStream input_stream(
reinterpret_cast<const ::uint8_t*>(serialized.data()),
serialized.size());
EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
EXPECT_EQ(17, message2.oneof_int32());
}
} }
// Verify that we can successfully parse fields of various types within oneof // Verify that we can successfully parse fields of various types within oneof
@ -1046,6 +1058,18 @@ TYPED_TEST(LiteTest, AllLite44) {
} }
} }
// Bytes [ctype = CORD]
{
protobuf_unittest::TestOneofParsingLite original;
original.set_oneof_bytes_cord("bytes cord");
std::string serialized;
EXPECT_TRUE(original.SerializeToString(&serialized));
protobuf_unittest::TestOneofParsingLite parsed;
EXPECT_TRUE(parsed.MergeFromString(serialized));
EXPECT_EQ("bytes cord", std::string(parsed.oneof_bytes_cord()));
EXPECT_TRUE(parsed.MergeFromString(serialized));
}
std::cout << "PASS" << std::endl; std::cout << "PASS" << std::endl;
} }

@ -477,9 +477,11 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
HANDLE_PRIMITIVE_TYPE(ENUM, int32_t) HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
#undef HANDLE_PRIMITIVE_TYPE #undef HANDLE_PRIMITIVE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: ABSL_LOG(FATAL) << "Repeated cords are not supported.";
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetSingleton<internal::RepeatedPtrFieldStringAccessor>(); return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
} }
break; break;

@ -224,6 +224,8 @@ inline void TestUtil::ReflectionTester::SetAllFieldsViaReflection(
reflection->SetString(message, F("optional_string_piece"), "124"); reflection->SetString(message, F("optional_string_piece"), "124");
reflection->SetString(message, F("optional_cord"), "125"); reflection->SetString(message, F("optional_cord"), "125");
reflection->SetString(message, F("optional_bytes_cord"),
"optional bytes cord");
sub_message = sub_message =
reflection->MutableMessage(message, F("optional_public_import_message")); reflection->MutableMessage(message, F("optional_public_import_message"));
@ -492,6 +494,7 @@ inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_TRUE(reflection->HasField(message, F("optional_string_piece"))); EXPECT_TRUE(reflection->HasField(message, F("optional_string_piece")));
EXPECT_TRUE(reflection->HasField(message, F("optional_cord"))); EXPECT_TRUE(reflection->HasField(message, F("optional_cord")));
EXPECT_TRUE(reflection->HasField(message, F("optional_bytes_cord")));
EXPECT_EQ(101, reflection->GetInt32(message, F("optional_int32"))); EXPECT_EQ(101, reflection->GetInt32(message, F("optional_int32")));
EXPECT_EQ(102, reflection->GetInt64(message, F("optional_int64"))); EXPECT_EQ(102, reflection->GetInt64(message, F("optional_int64")));
@ -553,6 +556,14 @@ inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"), EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"),
&scratch)); &scratch));
EXPECT_EQ("optional bytes cord",
reflection->GetString(message, F("optional_bytes_cord")));
EXPECT_EQ("optional bytes cord",
reflection->GetStringReference(message, F("optional_bytes_cord"),
&scratch));
EXPECT_EQ("optional bytes cord",
reflection->GetCord(message, F("optional_bytes_cord")));
EXPECT_TRUE(reflection->HasField(message, F("oneof_bytes"))); EXPECT_TRUE(reflection->HasField(message, F("oneof_bytes")));
EXPECT_EQ("604", reflection->GetString(message, F("oneof_bytes"))); EXPECT_EQ("604", reflection->GetString(message, F("oneof_bytes")));
@ -913,6 +924,7 @@ inline void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_FALSE(reflection->HasField(message, F("optional_string_piece"))); EXPECT_FALSE(reflection->HasField(message, F("optional_string_piece")));
EXPECT_FALSE(reflection->HasField(message, F("optional_cord"))); EXPECT_FALSE(reflection->HasField(message, F("optional_cord")));
EXPECT_FALSE(reflection->HasField(message, F("optional_bytes_cord")));
// Optional fields without defaults are set to zero or something like it. // Optional fields without defaults are set to zero or something like it.
EXPECT_EQ(0, reflection->GetInt32(message, F("optional_int32"))); EXPECT_EQ(0, reflection->GetInt32(message, F("optional_int32")));
@ -979,6 +991,11 @@ inline void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ("", reflection->GetStringReference(message, F("optional_cord"), EXPECT_EQ("", reflection->GetStringReference(message, F("optional_cord"),
&scratch)); &scratch));
EXPECT_EQ("", reflection->GetString(message, F("optional_bytes_cord")));
EXPECT_EQ("", reflection->GetStringReference(
message, F("optional_bytes_cord"), &scratch));
EXPECT_EQ("", reflection->GetCord(message, F("optional_bytes_cord")));
// Repeated fields are empty. // Repeated fields are empty.
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int32"))); EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int32")));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int64"))); EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int64")));

@ -140,6 +140,7 @@ inline void TestUtil::SetOptionalFields(UNITTEST::TestAllTypes* message) {
message, message->GetDescriptor()->FindFieldByName("optional_cord"), message, message->GetDescriptor()->FindFieldByName("optional_cord"),
"125"); "125");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS #endif // !PROTOBUF_TEST_NO_DESCRIPTORS
message->set_optional_bytes_cord("optional bytes cord");
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -355,6 +356,7 @@ inline void TestUtil::ExpectAllFieldsSet(
EXPECT_TRUE(message.has_optional_string_piece()); EXPECT_TRUE(message.has_optional_string_piece());
EXPECT_TRUE(message.has_optional_cord()); EXPECT_TRUE(message.has_optional_cord());
#endif #endif
EXPECT_TRUE(message.has_optional_bytes_cord());
EXPECT_EQ(101, message.optional_int32()); EXPECT_EQ(101, message.optional_int32());
EXPECT_EQ(102, message.optional_int64()); EXPECT_EQ(102, message.optional_int64());
@ -384,6 +386,7 @@ inline void TestUtil::ExpectAllFieldsSet(
EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.optional_foreign_enum()); EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.optional_foreign_enum());
EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.optional_import_enum()); EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.optional_import_enum());
EXPECT_EQ("optional bytes cord", message.optional_bytes_cord());
// ----------------------------------------------------------------- // -----------------------------------------------------------------
@ -557,6 +560,7 @@ inline void TestUtil::ExpectClear(const UNITTEST::TestAllTypes& message) {
EXPECT_FALSE(message.has_optional_string_piece()); EXPECT_FALSE(message.has_optional_string_piece());
EXPECT_FALSE(message.has_optional_cord()); EXPECT_FALSE(message.has_optional_cord());
EXPECT_FALSE(message.has_optional_bytes_cord());
// Optional fields without defaults are set to zero or something like it. // Optional fields without defaults are set to zero or something like it.
EXPECT_EQ(0, message.optional_int32()); EXPECT_EQ(0, message.optional_int32());
@ -597,6 +601,7 @@ inline void TestUtil::ExpectClear(const UNITTEST::TestAllTypes& message) {
EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.optional_foreign_enum()); EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.optional_foreign_enum());
EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.optional_import_enum()); EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.optional_import_enum());
EXPECT_EQ("", message.optional_bytes_cord());
// Repeated fields are empty. // Repeated fields are empty.
EXPECT_EQ(0, message.repeated_int32_size()); EXPECT_EQ(0, message.repeated_int32_size());
@ -978,6 +983,8 @@ inline void TestUtil::SetAllExtensions(UNITTEST::TestAllExtensions* message) {
message->SetExtension(UNITTEST::optional_string_piece_extension, "124"); message->SetExtension(UNITTEST::optional_string_piece_extension, "124");
message->SetExtension(UNITTEST::optional_cord_extension, "125"); message->SetExtension(UNITTEST::optional_cord_extension, "125");
message->SetExtension(UNITTEST::optional_bytes_cord_extension,
"optional bytes cord");
message->MutableExtension(UNITTEST::optional_public_import_message_extension) message->MutableExtension(UNITTEST::optional_public_import_message_extension)
->set_e(126); ->set_e(126);
@ -1207,6 +1214,7 @@ inline void TestUtil::ExpectAllExtensionsSet(
EXPECT_TRUE(message.HasExtension(UNITTEST::optional_string_piece_extension)); EXPECT_TRUE(message.HasExtension(UNITTEST::optional_string_piece_extension));
EXPECT_TRUE(message.HasExtension(UNITTEST::optional_cord_extension)); EXPECT_TRUE(message.HasExtension(UNITTEST::optional_cord_extension));
EXPECT_TRUE(message.HasExtension(UNITTEST::optional_bytes_cord_extension));
EXPECT_EQ(101, message.GetExtension(UNITTEST::optional_int32_extension)); EXPECT_EQ(101, message.GetExtension(UNITTEST::optional_int32_extension));
EXPECT_EQ(102, message.GetExtension(UNITTEST::optional_int64_extension)); EXPECT_EQ(102, message.GetExtension(UNITTEST::optional_int64_extension));
@ -1245,6 +1253,8 @@ inline void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ("124", EXPECT_EQ("124",
message.GetExtension(UNITTEST::optional_string_piece_extension)); message.GetExtension(UNITTEST::optional_string_piece_extension));
EXPECT_EQ("125", message.GetExtension(UNITTEST::optional_cord_extension)); EXPECT_EQ("125", message.GetExtension(UNITTEST::optional_cord_extension));
EXPECT_EQ("optional bytes cord",
message.GetExtension(UNITTEST::optional_bytes_cord_extension));
EXPECT_EQ( EXPECT_EQ(
126, 126,
message.GetExtension(UNITTEST::optional_public_import_message_extension) message.GetExtension(UNITTEST::optional_public_import_message_extension)
@ -1493,6 +1503,7 @@ inline void TestUtil::ExpectExtensionsClear(
EXPECT_FALSE(message.HasExtension(UNITTEST::optional_string_piece_extension)); EXPECT_FALSE(message.HasExtension(UNITTEST::optional_string_piece_extension));
EXPECT_FALSE(message.HasExtension(UNITTEST::optional_cord_extension)); EXPECT_FALSE(message.HasExtension(UNITTEST::optional_cord_extension));
EXPECT_FALSE(message.HasExtension(UNITTEST::optional_bytes_cord_extension));
// Optional fields without defaults are set to zero or something like it. // Optional fields without defaults are set to zero or something like it.
EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_int32_extension)); EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_int32_extension));
@ -1560,6 +1571,7 @@ inline void TestUtil::ExpectExtensionsClear(
EXPECT_EQ("", EXPECT_EQ("",
message.GetExtension(UNITTEST::optional_string_piece_extension)); message.GetExtension(UNITTEST::optional_string_piece_extension));
EXPECT_EQ("", message.GetExtension(UNITTEST::optional_cord_extension)); EXPECT_EQ("", message.GetExtension(UNITTEST::optional_cord_extension));
EXPECT_EQ("", message.GetExtension(UNITTEST::optional_bytes_cord_extension));
// Repeated fields are empty. // Repeated fields are empty.
EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_int32_extension)); EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_int32_extension));

@ -126,6 +126,7 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_uint32: 601 oneof_uint32: 601
oneof_nested_message { oneof_nested_message {
bb: 602 bb: 602

@ -129,4 +129,5 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_bytes: "604" oneof_bytes: "604"

@ -129,6 +129,7 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_uint32: 601 oneof_uint32: 601
oneof_nested_message < oneof_nested_message <
bb: 602 bb: 602

@ -129,4 +129,5 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_bytes: "604" oneof_bytes: "604"

@ -129,6 +129,7 @@
[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO [protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
[protobuf_unittest.default_string_piece_extension]: "424" [protobuf_unittest.default_string_piece_extension]: "424"
[protobuf_unittest.default_cord_extension]: "425" [protobuf_unittest.default_cord_extension]: "425"
[protobuf_unittest.optional_bytes_cord_extension]: "optional bytes cord"
[protobuf_unittest.oneof_uint32_extension]: 601 [protobuf_unittest.oneof_uint32_extension]: 601
[protobuf_unittest.oneof_nested_message_extension] { [protobuf_unittest.oneof_nested_message_extension] {
bb: 602 bb: 602

@ -129,6 +129,7 @@
[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO [protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
[protobuf_unittest.default_string_piece_extension]: "424" [protobuf_unittest.default_string_piece_extension]: "424"
[protobuf_unittest.default_cord_extension]: "425" [protobuf_unittest.default_cord_extension]: "425"
[protobuf_unittest.optional_bytes_cord_extension]: "optional bytes cord"
[protobuf_unittest.oneof_uint32_extension]: 601 [protobuf_unittest.oneof_uint32_extension]: 601
[protobuf_unittest.oneof_nested_message_extension] < [protobuf_unittest.oneof_nested_message_extension] <
bb: 602 bb: 602

@ -96,6 +96,7 @@ message TestAllTypes {
string optional_cord = 25 [ string optional_cord = 25 [
ctype = CORD ctype = CORD
]; ];
bytes optional_bytes_cord = 86 [ctype=CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
protobuf_unittest_import.PublicImportMessage optional_public_import_message = 26; protobuf_unittest_import.PublicImportMessage optional_public_import_message = 26;
@ -368,6 +369,8 @@ extend TestAllExtensions {
// TODO: ctype=CORD is not supported for extension. Add // TODO: ctype=CORD is not supported for extension. Add
// ctype=CORD option back after it is supported. // ctype=CORD option back after it is supported.
string optional_cord_extension = 25; string optional_cord_extension = 25;
bytes optional_bytes_cord_extension = 86;
protobuf_unittest_import.PublicImportMessage protobuf_unittest_import.PublicImportMessage
optional_public_import_message_extension = 26; optional_public_import_message_extension = 26;
TestAllTypes.NestedMessage optional_lazy_message_extension = 27 [ TestAllTypes.NestedMessage optional_lazy_message_extension = 27 [

@ -72,6 +72,7 @@ message TestAllTypesLite {
string optional_string_piece = 24 [ctype = STRING_PIECE]; string optional_string_piece = 24 [ctype = STRING_PIECE];
string optional_cord = 25 [ctype = CORD]; string optional_cord = 25 [ctype = CORD];
bytes optional_bytes_cord = 86 [ctype = CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
protobuf_unittest_import.PublicImportMessageLite protobuf_unittest_import.PublicImportMessageLite
@ -261,6 +262,7 @@ extend TestAllExtensionsLite {
// TODO: ctype=CORD is not supported for extension. Add // TODO: ctype=CORD is not supported for extension. Add
// ctype=CORD option back after it is supported. // ctype=CORD option back after it is supported.
string optional_cord_extension_lite = 25; string optional_cord_extension_lite = 25;
bytes optional_bytes_cord_extension_lite = 86;
protobuf_unittest_import.PublicImportMessageLite protobuf_unittest_import.PublicImportMessageLite
optional_public_import_message_extension_lite = 26; optional_public_import_message_extension_lite = 26;
TestAllTypesLite.NestedMessage optional_lazy_message_extension_lite = 27 TestAllTypesLite.NestedMessage optional_lazy_message_extension_lite = 27

@ -67,6 +67,7 @@ message TestAllTypes {
string optional_string_piece = 24 [ctype=STRING_PIECE]; string optional_string_piece = 24 [ctype=STRING_PIECE];
string optional_cord = 25 [ctype=CORD]; string optional_cord = 25 [ctype=CORD];
bytes optional_bytes_cord = 86 [ctype=CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
protobuf_unittest_import.PublicImportMessage protobuf_unittest_import.PublicImportMessage

@ -202,7 +202,7 @@ TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) {
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask));
mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(); mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>();
EXPECT_EQ(79, mask.paths_size()); EXPECT_EQ(80, mask.paths_size());
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask));
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask));
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask));

@ -562,7 +562,7 @@ bool WireFormat::ParseAndMergeField(
} }
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
absl::Cord value; absl::Cord value;
if (!WireFormatLite::ReadBytes(input, &value)) return false; if (!WireFormatLite::ReadBytes(input, &value)) return false;
message_reflection->SetString(message, field, value); message_reflection->SetString(message, field, value);
@ -1005,7 +1005,7 @@ const char* WireFormat::_InternalParseAndMergeField(
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
int size = ReadSize(&ptr); int size = ReadSize(&ptr);
if (ptr == nullptr) return nullptr; if (ptr == nullptr) return nullptr;
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
absl::Cord value; absl::Cord value;
ptr = ctx->ReadCord(ptr, size, &value); ptr = ctx->ReadCord(ptr, size, &value);
if (ptr == nullptr) return nullptr; if (ptr == nullptr) return nullptr;
@ -1428,7 +1428,7 @@ uint8_t* WireFormat::InternalSerializeField(const FieldDescriptor* field,
} }
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
absl::Cord value = message_reflection->GetCord(message, field); absl::Cord value = message_reflection->GetCord(message, field);
target = stream->WriteString(field->number(), value, target); target = stream->WriteString(field->number(), value, target);
break; break;
@ -1748,7 +1748,7 @@ size_t WireFormat::FieldDataOnlyByteSize(const FieldDescriptor* field,
// instead of copying. // instead of copying.
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
for (size_t j = 0; j < count; j++) { for (size_t j = 0; j < count; j++) {
absl::Cord value = message_reflection->GetCord(message, field); absl::Cord value = message_reflection->GetCord(message, field);
data_size += WireFormatLite::StringSize(value); data_size += WireFormatLite::StringSize(value);

Loading…
Cancel
Save