Fix issues involving const_cast and repeated fields in reflection.

The motivation is to fix correctness issues seen in split repeated fields.

PiperOrigin-RevId: 543779129
pull/13153/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 195bdd0488
commit ee5cf35c1a
  1. 47
      src/google/protobuf/generated_message_reflection.cc
  2. 16
      src/google/protobuf/message.h
  3. 8
      src/google/protobuf/reflection.h

@ -59,6 +59,7 @@
#include "google/protobuf/inlined_string_field.h"
#include "google/protobuf/map_field.h"
#include "google/protobuf/map_field_inl.h"
#include "google/protobuf/raw_ptr.h"
#include "google/protobuf/repeated_field.h"
#include "google/protobuf/unknown_field_set.h"
@ -2561,7 +2562,9 @@ const void* Reflection::GetRawRepeatedField(const Message& message,
int ctype,
const Descriptor* desc) const {
USAGE_CHECK_REPEATED("GetRawRepeatedField");
if (field->cpp_type() != cpptype)
if (field->cpp_type() != cpptype &&
(field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM ||
cpptype != FieldDescriptor::CPPTYPE_INT32))
ReportReflectionUsageTypeError(descriptor_, field, "GetRawRepeatedField",
cpptype);
if (ctype >= 0)
@ -2569,13 +2572,8 @@ const void* Reflection::GetRawRepeatedField(const Message& message,
if (desc != nullptr)
ABSL_CHECK_EQ(field->message_type(), desc) << "wrong submessage type";
if (field->is_extension()) {
// Should use extension_set::GetRawRepeatedField. However, the required
// parameter "default repeated value" is not very easy to get here.
// Map is not supported in extensions, it is acceptable to use
// extension_set::MutableRawRepeatedField which does not change the message.
return MutableExtensionSet(const_cast<Message*>(&message))
->MutableRawRepeatedField(field->number(), field->type(),
field->is_packed(), field);
return GetExtensionSet(message).GetRawRepeatedField(
field->number(), internal::DefaultRawPtr());
} else {
// Trigger transform for MapField
if (IsMapFieldInApi(field)) {
@ -3007,8 +3005,8 @@ void Reflection::ClearOneof(Message* message,
template <> \
const RepeatedField<TYPE>& Reflection::GetRepeatedFieldInternal<TYPE>( \
const Message& message, const FieldDescriptor* field) const { \
return *static_cast<RepeatedField<TYPE>*>(MutableRawRepeatedField( \
const_cast<Message*>(&message), field, CPPTYPE, CTYPE, nullptr)); \
return *static_cast<const RepeatedField<TYPE>*>( \
GetRawRepeatedField(message, field, CPPTYPE, CTYPE, nullptr)); \
} \
\
template <> \
@ -3029,6 +3027,14 @@ HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
#undef HANDLE_TYPE
const void* Reflection::GetRawRepeatedString(const Message& message,
const FieldDescriptor* field,
bool is_string) const {
(void)is_string; // Parameter is used by Google-internal code.
return GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_STRING,
FieldOptions::STRING, nullptr);
}
void* Reflection::MutableRawRepeatedString(Message* message,
const FieldDescriptor* field,
bool is_string) const {
@ -3114,6 +3120,27 @@ MessageFactory* Reflection::GetMessageFactory() const {
return message_factory_;
}
const void* Reflection::RepeatedFieldData(
const Message& message, const FieldDescriptor* field,
FieldDescriptor::CppType cpp_type, const Descriptor* message_type) const {
ABSL_CHECK(field->is_repeated());
ABSL_CHECK(field->cpp_type() == cpp_type ||
(field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM &&
cpp_type == FieldDescriptor::CPPTYPE_INT32))
<< "The type parameter T in RepeatedFieldRef<T> API doesn't match "
<< "the actual field type (for enums T should be the generated enum "
<< "type or int32_t).";
if (message_type != nullptr) {
ABSL_CHECK_EQ(message_type, field->message_type());
}
if (field->is_extension()) {
return GetExtensionSet(message).GetRawRepeatedField(
field->number(), internal::DefaultRawPtr());
} else {
return &GetRawNonOneof<char>(message, field);
}
}
void* Reflection::RepeatedFieldData(Message* message,
const FieldDescriptor* field,
FieldDescriptor::CppType cpp_type,

@ -1031,8 +1031,11 @@ class PROTOBUF_EXPORT Reflection final {
// "message_type" should be set to its descriptor. Otherwise "message_type"
// should be set to nullptr. Implementations of this method should check
// whether "cpp_type"/"message_type" is consistent with the actual type of the
// field. We use 1 routine rather than 2 (const vs mutable) because it is
// protected and it doesn't change the message.
// field.
const void* RepeatedFieldData(const Message& message,
const FieldDescriptor* field,
FieldDescriptor::CppType cpp_type,
const Descriptor* message_type) const;
void* RepeatedFieldData(Message* message, const FieldDescriptor* field,
FieldDescriptor::CppType cpp_type,
const Descriptor* message_type) const;
@ -1136,8 +1139,9 @@ class PROTOBUF_EXPORT Reflection final {
// call MutableRawRepeatedField directly here because we don't have access to
// FieldOptions::* which are defined in descriptor.pb.h. Including that
// file here is not possible because it would cause a circular include cycle.
// We use 1 routine rather than 2 (const vs mutable) because it is private
// and mutable a repeated string field doesn't change the message.
const void* GetRawRepeatedString(const Message& message,
const FieldDescriptor* field,
bool is_string) const;
void* MutableRawRepeatedString(Message* message, const FieldDescriptor* field,
bool is_string) const;
@ -1493,8 +1497,8 @@ template <>
inline const RepeatedPtrField<std::string>&
Reflection::GetRepeatedPtrFieldInternal<std::string>(
const Message& message, const FieldDescriptor* field) const {
return *static_cast<RepeatedPtrField<std::string>*>(
MutableRawRepeatedString(const_cast<Message*>(&message), field, true));
return *static_cast<const RepeatedPtrField<std::string>*>(
GetRawRepeatedString(message, field, true));
}
template <>

@ -91,9 +91,8 @@ class RepeatedFieldRef<
friend class Reflection;
RepeatedFieldRef(const Message& message, const FieldDescriptor* field) {
const Reflection* reflection = message.GetReflection();
data_ = reflection->RepeatedFieldData(const_cast<Message*>(&message), field,
internal::RefTypeTraits<T>::cpp_type,
nullptr);
data_ = reflection->RepeatedFieldData(
message, field, internal::RefTypeTraits<T>::cpp_type, nullptr);
accessor_ = reflection->RepeatedFieldAccessor(field);
}
@ -200,8 +199,7 @@ class RepeatedFieldRef<
RepeatedFieldRef(const Message& message, const FieldDescriptor* field) {
const Reflection* reflection = message.GetReflection();
data_ = reflection->RepeatedFieldData(
const_cast<Message*>(&message), field,
internal::RefTypeTraits<T>::cpp_type,
message, field, internal::RefTypeTraits<T>::cpp_type,
internal::RefTypeTraits<T>::GetMessageFieldDescriptor());
accessor_ = reflection->RepeatedFieldAccessor(field);
default_instance_ =

Loading…
Cancel
Save