diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index 99bcd6c683d6b..351a636967a6e 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc @@ -5295,7 +5295,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { $WeakDescriptorSelfPin$; $annotate_bytesize$; // @@protoc_insertion_point(message_set_byte_size_start:$full_name$) - ::size_t total_size = this_.$extensions$.MessageSetByteSize(); + ::size_t total_size = this_.$extensions$.MessageSetByteSize(&this_); if (this_.$have_unknown_fields$) { total_size += ::_pbi::ComputeUnknownMessageSetItemsSize( this_.$unknown_fields$); @@ -5353,7 +5353,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { [&] { if (descriptor_->extension_range_count() == 0) return; p->Emit(R"cc( - total_size += this_.$extensions$.ByteSize(); + total_size += this_.$extensions$.ByteSize(&this_); )cc"); }}, {"prefetch", diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index a210ede95158b..79a1cc1554258 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -2852,7 +2852,7 @@ ::size_t FileDescriptorSet::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -6008,7 +6008,7 @@ ::size_t ExtensionRangeOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ExtensionRangeOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -9582,7 +9582,7 @@ ::size_t FileOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -10185,7 +10185,7 @@ ::size_t MessageOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -11474,7 +11474,7 @@ ::size_t FieldOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -11956,7 +11956,7 @@ ::size_t OneofOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -12397,7 +12397,7 @@ ::size_t EnumOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -12867,7 +12867,7 @@ ::size_t EnumValueOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -13304,7 +13304,7 @@ ::size_t ServiceOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -13752,7 +13752,7 @@ ::size_t MethodOptions::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -15102,7 +15102,7 @@ ::size_t FeatureSet::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.FeatureSet) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused @@ -16702,7 +16702,7 @@ ::size_t SourceCodeInfo::ByteSizeLong() const { #endif // PROTOBUF_CUSTOM_VTABLE // @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo) ::size_t total_size = 0; - total_size += this_._impl_._extensions_.ByteSize(); + total_size += this_._impl_._extensions_.ByteSize(&this_); ::uint32_t cached_has_bits = 0; // Prevent compiler warnings about cached_has_bits being unused diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 495cac8350a29..55d59f8b13600 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -375,11 +374,18 @@ void* ExtensionSet::MutableRawRepeatedField(int number) { // ------------------------------------------------------------------- // Enums -size_t ExtensionSet::GetMessageByteSizeLong(int number) const { +size_t ExtensionSet::GetMessageByteSizeLong(const MessageLite* extendee, + int number) const { const Extension* extension = FindOrNull(number); ABSL_CHECK(extension != nullptr) << "not present"; ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, MESSAGE); - return extension->is_lazy ? extension->ptr.lazymessage_value->ByteSizeLong() + ABSL_DCHECK(!extension->is_lazy || + GetOrFindPrototypeForLazyMessage(*extension, extendee, number) != + nullptr); + return extension->is_lazy ? extension->ptr.lazymessage_value->ByteSizeLong( + GetOrFindPrototypeForLazyMessage( + *extension, extendee, number), + arena_) : extension->ptr.message_value->ByteSizeLong(); } @@ -946,8 +952,8 @@ void ExtensionSet::InternalExtensionMergeFrom(Arena* arena, Arena* other_arena) { DebugAssertArenaMatches(arena); Extension* dst_extension; - bool is_new = MaybeNewExtension(arena, number, other_extension.descriptor, - &dst_extension); + bool is_new = MaybeNewExtension( + arena, number, other_extension.descriptor_or_prototype, &dst_extension); if (is_new) { InternalExtensionMergeFromIntoUninitializedExtension( arena, *dst_extension, extendee, number, other_extension, other_arena); @@ -1009,9 +1015,12 @@ void ExtensionSet::InternalExtensionMergeFrom(Arena* arena, ABSL_DCHECK(!dst_extension->is_repeated); if (other_extension.is_lazy) { if (dst_extension->is_lazy) { + const MessageLite* prototype = GetOrFindPrototypeForLazyMessage( + other_extension, extendee, number); + ABSL_DCHECK_NE(prototype, nullptr); dst_extension->ptr.lazymessage_value->MergeFrom( - GetPrototypeForLazyMessage(extendee, number), - *other_extension.ptr.lazymessage_value, arena, other_arena); + prototype, *other_extension.ptr.lazymessage_value, arena, + other_arena); } else { dst_extension->ptr.message_value->CheckTypeAndMergeFrom( other_extension.ptr.lazymessage_value->GetMessage( @@ -1236,11 +1245,11 @@ uint8_t* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray( return target; } -size_t ExtensionSet::ByteSize() const { +size_t ExtensionSet::ByteSize(const MessageLite* extendee) const { size_t total_size = 0; ForEach( - [&total_size](int number, const Extension& ext) { - total_size += ext.ByteSize(number); + [&](int number, const Extension& ext) { + total_size += ext.ByteSize(extendee, number, arena_); }, Prefetch{}); return total_size; @@ -1250,12 +1259,15 @@ size_t ExtensionSet::ByteSize() const { // Defined in extension_set_heavy.cc. // int ExtensionSet::SpaceUsedExcludingSelf() const -bool ExtensionSet::MaybeNewExtension(Arena* arena, int number, - const FieldDescriptor* descriptor, - Extension** result) { - bool extension_is_new = false; - std::tie(*result, extension_is_new) = Insert(arena, number); - (*result)->descriptor = descriptor; +bool ExtensionSet::MaybeNewExtension( + Arena* arena, int number, + Extension::DescriptorOrPrototype descriptor_or_prototype, + Extension** result_ptr) { + auto [result, extension_is_new] = Insert(arena, number); + *result_ptr = result; + if (extension_is_new) { + result->descriptor_or_prototype = descriptor_or_prototype; + } return extension_is_new; } @@ -1327,7 +1339,8 @@ void ExtensionSet::Extension::Clear() { } } -size_t ExtensionSet::Extension::ByteSize(int number) const { +size_t ExtensionSet::Extension::ByteSize(const MessageLite* extendee, + int number, Arena* arena) const { size_t result = 0; if (is_repeated) { @@ -1443,7 +1456,10 @@ size_t ExtensionSet::Extension::ByteSize(int number) const { #undef HANDLE_TYPE case WireFormatLite::TYPE_MESSAGE: { result += WireFormatLite::LengthDelimitedSize( - is_lazy ? ptr.lazymessage_value->ByteSizeLong() + is_lazy ? ptr.lazymessage_value->ByteSizeLong( + ExtensionSet::GetOrFindPrototypeForLazyMessage( + *this, extendee, number), + arena) : ptr.message_value->ByteSizeLong()); break; } @@ -1554,7 +1570,7 @@ bool ExtensionSet::Extension::IsInitialized(const ExtensionSet* ext_set, if (!is_lazy) return ptr.message_value->IsInitialized(); const MessageLite* prototype = - ext_set->GetPrototypeForLazyMessage(extendee, number); + ext_set->GetOrFindPrototypeForLazyMessage(*this, extendee, number); ABSL_DCHECK_NE(prototype, nullptr) << "extendee: " << extendee->GetTypeName() << "; number: " << number; return ptr.lazymessage_value->IsInitialized(prototype, arena); @@ -1857,7 +1873,9 @@ uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray( case WireFormatLite::TYPE_MESSAGE: if (is_lazy) { const auto* prototype = - extension_set->GetPrototypeForLazyMessage(extendee, number); + extension_set->GetOrFindPrototypeForLazyMessage(*this, extendee, + number); + ABSL_DCHECK_NE(prototype, nullptr); target = ptr.lazymessage_value->WriteMessageToArray(prototype, number, target, stream); } else { @@ -1871,7 +1889,8 @@ uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray( return target; } -const MessageLite* ExtensionSet::GetPrototypeForLazyMessage( +template +const MessageLite* ExtensionSet::FindPrototypeForLazyMessageImpl( const MessageLite* extendee, int number) { GeneratedExtensionFinder finder(extendee); bool was_packed_on_wire = false; @@ -1881,9 +1900,32 @@ const MessageLite* ExtensionSet::GetPrototypeForLazyMessage( &extension_info, &was_packed_on_wire)) { return nullptr; } + if constexpr (mustBeGenerated) { + if (extension_info.lazy_eager_verify_func == nullptr) { + return nullptr; + } + } return extension_info.message_info.prototype; } +const MessageLite* ExtensionSet::FindPrototypeForLazyMessage( + const MessageLite* extendee, int number) { + return FindPrototypeForLazyMessageImpl(extendee, + number); +} + +const MessageLite* +ExtensionSet::FindPrototypeFromGeneratedFactoryForLazyMessage( + const MessageLite* extendee, int number) { + return FindPrototypeForLazyMessageImpl(extendee, + number); +} + +template const MessageLite* ExtensionSet::FindPrototypeForLazyMessageImpl( + const MessageLite*, int); +template const MessageLite* +ExtensionSet::FindPrototypeForLazyMessageImpl(const MessageLite*, int); + uint8_t* ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray( const MessageLite* extendee, const ExtensionSet* extension_set, int number, @@ -1906,8 +1948,9 @@ ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray( WireFormatLite::kMessageSetTypeIdNumber, number, target); // Write message. if (is_lazy) { - const auto* prototype = - extension_set->GetPrototypeForLazyMessage(extendee, number); + const auto* prototype = extension_set->GetOrFindPrototypeForLazyMessage( + *this, extendee, number); + ABSL_DCHECK_NE(prototype, nullptr); target = ptr.lazymessage_value->WriteMessageToArray( prototype, WireFormatLite::kMessageSetMessageNumber, target, stream); } else { @@ -1922,11 +1965,12 @@ ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray( return target; } -size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const { +size_t ExtensionSet::Extension::MessageSetItemByteSize( + const MessageLite* extendee, int number, Arena* arena) const { if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { // Not a valid MessageSet extension, but compute the byte size for it the // normal way. - return ByteSize(number); + return ByteSize(extendee, number, arena); } if (is_cleared) return 0; @@ -1938,17 +1982,20 @@ size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const { // message our_size += WireFormatLite::LengthDelimitedSize( - is_lazy ? ptr.lazymessage_value->ByteSizeLong() + is_lazy ? ptr.lazymessage_value->ByteSizeLong( + ExtensionSet::GetOrFindPrototypeForLazyMessage( + *this, extendee, number), + arena) : ptr.message_value->ByteSizeLong()); return our_size; } -size_t ExtensionSet::MessageSetByteSize() const { +size_t ExtensionSet::MessageSetByteSize(const MessageLite* extendee) const { size_t total_size = 0; ForEach( - [&total_size](int number, const Extension& ext) { - total_size += ext.MessageSetItemByteSize(number); + [&](int number, const Extension& ext) { + total_size += ext.MessageSetItemByteSize(extendee, number, arena_); }, Prefetch{}); return total_size; diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index 6af36a5421683..5275ec7581fb4 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -598,10 +598,10 @@ class PROTOBUF_EXPORT ExtensionSet { const MessageLite* extendee, uint8_t* target) const; // Returns the total serialized size of all the extensions. - size_t ByteSize() const; - + size_t ByteSize(const MessageLite* extendee) const; // Like ByteSize() but uses MessageSet format. - size_t MessageSetByteSize() const; + size_t MessageSetByteSize(const MessageLite* extendee) const; + // Returns (an estimate of) the total number of bytes used for storing the // extensions in memory, excluding sizeof(*this). If the ExtensionSet is @@ -657,7 +657,7 @@ class PROTOBUF_EXPORT ExtensionSet { static bool FieldTypeIsPointer(FieldType type); - size_t GetMessageByteSizeLong(int number) const; + size_t GetMessageByteSizeLong(const MessageLite* extendee, int number) const; uint8_t* InternalSerializeMessage(int number, const MessageLite* prototype, uint8_t* target, io::EpsCopyOutputStream* stream) const; @@ -708,7 +708,8 @@ class PROTOBUF_EXPORT ExtensionSet { Arena* arena) const = 0; virtual bool IsEagerSerializeSafe(const MessageLite* prototype, Arena* arena) const = 0; - virtual size_t ByteSizeLong() const = 0; + virtual size_t ByteSizeLong(const MessageLite* prototype, + Arena* arena) const = 0; virtual size_t SpaceUsedLong() const = 0; virtual std::variant UnparsedSizeOrMessage() @@ -765,8 +766,71 @@ class PROTOBUF_EXPORT ExtensionSet { uint8_t* InternalSerializeMessageSetItemWithCachedSizesToArray( const MessageLite* extendee, const ExtensionSet* extension_set, int number, uint8_t* target, io::EpsCopyOutputStream* stream) const; - size_t ByteSize(int number) const; - size_t MessageSetItemByteSize(int number) const; + size_t ByteSize(const MessageLite* extendee, int number, + Arena* arena) const; + size_t MessageSetItemByteSize(const MessageLite* extendee, int number, + Arena* arena) const; + + + // A tagged pointer that can hold either a FieldDescriptor* or + // const MessageLite*. The LSB is used for tagging. Mimicks + // LazyFIeld::UnparsedPayload. + struct DescriptorOrPrototype { + private: + enum Tag : uintptr_t { + kTagFieldDescriptor = 0, + kTagPrototype = 1, + kTagBits = 1, + kRemoveMask = ~kTagBits, + }; + + public: + // Sets the value to a FieldDescriptor*. + void Set(const FieldDescriptor* desc) { + ABSL_DCHECK_EQ(reinterpret_cast(desc) & kTagBits, 0u) + << "FieldDescriptor pointer is not sufficiently aligned."; + value = reinterpret_cast(desc) | kTagFieldDescriptor; + } + // Sets the value to an ExtensionInfo*. We store a pointer to the info. + void Set(const MessageLite* prototype) { + ABSL_DCHECK_EQ(reinterpret_cast(prototype) & kTagBits, 0u) + << "MessageLite pointer is not sufficiently aligned."; + value = reinterpret_cast(prototype) | kTagPrototype; + } + + // Returns true if the held type is FieldDescriptor*. + bool IsFieldDescriptor() const { return tag() == kTagFieldDescriptor; } + + // Returns true if the held type is ExtensionInfo*. + bool IsPrototype() const { return tag() == kTagPrototype; } + + // Returns the FieldDescriptor* per tag type. It can still return nullptr. + const FieldDescriptor* GetFieldDescriptor() const { + if (IsFieldDescriptor()) { + return AsFieldDescriptor(); + } else { + return nullptr; + } + } + + // Requires: IsPrototype() is true. + const MessageLite* AsPrototype() const { + ABSL_DCHECK(IsPrototype()); + return reinterpret_cast(value & kRemoveMask); + } + + private: + // Requires: IsFieldDescriptor() is true. + const FieldDescriptor* AsFieldDescriptor() const { + ABSL_DCHECK(IsFieldDescriptor()); + return reinterpret_cast(value & kRemoveMask); + } + + Tag tag() const { return static_cast(value & kTagBits); } + + uintptr_t value; + }; + void Clear(); int GetSize() const; void Free(); @@ -903,7 +967,10 @@ class PROTOBUF_EXPORT ExtensionSet { // The descriptor for this extension, if one exists and is known. May be // nullptr. Must not be nullptr if the descriptor for the extension does // not live in the same pool as the descriptor for the containing type. - const FieldDescriptor* descriptor; + // + // For lazy message extensions, this will store the prototype of the + // message type. + DescriptorOrPrototype descriptor_or_prototype; }; // The Extension struct is small enough to be passed by value so we use it @@ -931,9 +998,8 @@ class PROTOBUF_EXPORT ExtensionSet { const Extension* FindOrNullInLargeMap(int key) const; Extension* FindOrNullInLargeMap(int key); - // Inserts a new (key, Extension) into the ExtensionSet (and returns true), or - // finds the already-existing Extension for that key (returns false). - // The Extension* will point to the new-or-found Extension. + // Returns a pair of where the bool is true if the + // extension was newly inserted. std::pair Insert(Arena* arena, int key); // Same as insert for the large map. std::pair InternalInsertIntoLargeMap(int key); @@ -1101,6 +1167,15 @@ class PROTOBUF_EXPORT ExtensionSet { void InternalExtensionMergeFromIntoUninitializedExtension( Arena* arena, Extension& dst_extension, const MessageLite* extendee, int number, const Extension& other_extension, Arena* other_arena); + // Returns the prototype for a LazyMessage from the extension. If it's null, + // find one from the extension registry. + static const MessageLite* GetOrFindPrototypeForLazyMessage( + const Extension& ext, const MessageLite* extendee, int number) { + ABSL_DCHECK(ext.is_lazy); + auto* prototype = ext.descriptor_or_prototype.AsPrototype(); + if (prototype != nullptr) return prototype; + return FindPrototypeForLazyMessage(extendee, number); + } inline static bool is_packable(WireFormatLite::WireType type) { switch (type) { @@ -1152,9 +1227,17 @@ class PROTOBUF_EXPORT ExtensionSet { return expected_wire_type == wire_type; } + template + static const MessageLite* FindPrototypeForLazyMessageImpl( + const MessageLite* extendee, int number); // Find the prototype for a LazyMessage from the extension registry. Returns // null if the extension is not found. - static const MessageLite* GetPrototypeForLazyMessage( + static const MessageLite* FindPrototypeForLazyMessage( + const MessageLite* extendee, int number); + // Same as above, but returns null if the prototype is not from generated + // factory. Use this if the caller wants to cache the result because only + // generated prototypes have lifetime guarantees. + static const MessageLite* FindPrototypeFromGeneratedFactoryForLazyMessage( const MessageLite* extendee, int number); // Returns true if extension is present and lazy. @@ -1167,7 +1250,17 @@ class PROTOBUF_EXPORT ExtensionSet { // Gets the extension with the given number, creating it if it does not // already exist. Returns true if the extension did not already exist. bool MaybeNewExtension(Arena* arena, int number, - const FieldDescriptor* descriptor, Extension** result); + const FieldDescriptor* descriptor, + Extension** result_ptr) { + Extension::DescriptorOrPrototype descriptor_or_prototype; + descriptor_or_prototype.Set(descriptor); + return MaybeNewExtension(arena, number, descriptor_or_prototype, + result_ptr); + } + bool MaybeNewExtension( + Arena* arena, int number, + Extension::DescriptorOrPrototype descriptor_or_prototype, + Extension** result_ptr); // Gets the repeated extension for the given descriptor, creating it if // it does not exist. diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 7845c9da99721..9da703eee59db 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -63,10 +63,12 @@ void ExtensionSet::AppendToList( // lazily-initialized, so they might not even be constructed until // AppendToList() is called. - if (ext.descriptor == nullptr) { + const auto* field_descriptor = + ext.descriptor_or_prototype.GetFieldDescriptor(); + if (field_descriptor == nullptr) { output->push_back(pool->FindExtensionByNumber(extendee, number)); } else { - output->push_back(ext.descriptor); + output->push_back(field_descriptor); } } }, @@ -418,7 +420,7 @@ size_t ExtensionSet::Extension::SpaceUsedExcludingSelfLong() const { uint8_t* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( const MessageLite* extendee, uint8_t* target) const { io::EpsCopyOutputStream stream( - target, MessageSetByteSize(), + target, MessageSetByteSize(extendee), io::CodedOutputStream::IsDefaultSerializationDeterministic()); return InternalSerializeMessageSetWithCachedSizesToArray(extendee, target, &stream); diff --git a/src/google/protobuf/reflection_visit_field_info.h b/src/google/protobuf/reflection_visit_field_info.h index f12f6a3f8c7a0..eac1c98f2b33c 100644 --- a/src/google/protobuf/reflection_visit_field_info.h +++ b/src/google/protobuf/reflection_visit_field_info.h @@ -225,8 +225,10 @@ struct DynamicExtensionInfoHelper { ext.is_cleared = true; return ext.ptr.lazymessage_value->Clear(); } - static size_t ByteSizeLongLazyMessage(const Extension& ext) { - return ext.ptr.lazymessage_value->ByteSizeLong(); + static size_t ByteSizeLongLazyMessage(const Extension& ext, + const Message* prototype, + Arena* arena) { + return ext.ptr.lazymessage_value->ByteSizeLong(prototype, arena); } }; @@ -674,7 +676,8 @@ struct LazyMessageDynamicExtensionInfo } void Clear() { DynamicExtensionInfoHelper::ClearLazyMessage(ext); } size_t FieldByteSize() const { - return DynamicExtensionInfoHelper::ByteSizeLongLazyMessage(ext); + return DynamicExtensionInfoHelper::ByteSizeLongLazyMessage(ext, &prototype, + arena); } ExtensionT& ext; diff --git a/src/google/protobuf/reflection_visit_fields.h b/src/google/protobuf/reflection_visit_fields.h index 7a1d2f1b5692f..55a3057b249a7 100644 --- a/src/google/protobuf/reflection_visit_fields.h +++ b/src/google/protobuf/reflection_visit_fields.h @@ -384,9 +384,10 @@ void ReflectionVisit::VisitFields(MessageT& message, CallbackFn&& func, PROTOBUF_HANDLE_CASE(GROUP, Group); case FieldDescriptor::TYPE_MESSAGE: { const FieldDescriptor* field = - ext.descriptor != nullptr - ? ext.descriptor - : pool->FindExtensionByNumber(extendee, number); + ext.descriptor_or_prototype.GetFieldDescriptor(); + if (field == nullptr) { + field = pool->FindExtensionByNumber(extendee, number); + } ABSL_DCHECK_EQ(field->number(), number); bool is_mset = field->containing_type()->options().message_set_wire_format(); diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 2aeedd0f782c8..77d6287d8ade2 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -49,6 +49,7 @@ namespace internal { static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field, const MapValueConstRef& value); + // =================================================================== bool UnknownFieldSetFieldSkipper::SkipField(io::CodedInputStream* input, @@ -1689,7 +1690,7 @@ size_t WireFormat::FieldDataOnlyByteSize(const FieldDescriptor* field, if (field->is_extension()) { data_size += WireFormatLite::LengthDelimitedSize( message_reflection->GetExtensionSet(message).GetMessageByteSizeLong( - field->number())); + &message, field->number())); break; } data_size += WireFormatLite::MessageSize(