• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 // Author: kenton@google.com (Kenton Varda)
9 //  Based on original Protocol Buffers design by
10 //  Sanjay Ghemawat, Jeff Dean, and others.
11 
12 #include "google/protobuf/message.h"
13 
14 #include <atomic>
15 #include <cstddef>
16 #include <cstdint>
17 #include <cstring>
18 #include <new>  // IWYU pragma: keep for operator new().
19 #include <queue>
20 #include <string>
21 #include <vector>
22 
23 #include "absl/base/call_once.h"
24 #include "absl/base/optimization.h"
25 #include "absl/container/flat_hash_map.h"
26 #include "absl/container/flat_hash_set.h"
27 #include "absl/hash/hash.h"
28 #include "absl/log/absl_check.h"
29 #include "absl/log/absl_log.h"
30 #include "absl/strings/str_join.h"
31 #include "absl/strings/string_view.h"
32 #include "absl/synchronization/mutex.h"
33 #include "absl/types/optional.h"
34 #include "google/protobuf/descriptor.h"
35 #include "google/protobuf/descriptor.pb.h"
36 #include "google/protobuf/dynamic_message.h"
37 #include "google/protobuf/generated_message_reflection.h"
38 #include "google/protobuf/generated_message_tctable_impl.h"
39 #include "google/protobuf/generated_message_util.h"
40 #include "google/protobuf/io/coded_stream.h"
41 #include "google/protobuf/map_field.h"
42 #include "google/protobuf/message_lite.h"
43 #include "google/protobuf/parse_context.h"
44 #include "google/protobuf/port.h"
45 #include "google/protobuf/reflection_internal.h"
46 #include "google/protobuf/reflection_ops.h"
47 #include "google/protobuf/reflection_visit_fields.h"
48 #include "google/protobuf/unknown_field_set.h"
49 #include "google/protobuf/wire_format.h"
50 
51 
52 // Must be included last.
53 #include "google/protobuf/port_def.inc"
54 
55 namespace google {
56 namespace protobuf {
57 namespace internal {
58 
59 // TODO make this factorized better. This should not have to hop
60 // to reflection. Currently uses GeneratedMessageReflection and thus is
61 // defined in generated_message_reflection.cc
62 void RegisterFileLevelMetadata(const DescriptorTable* descriptor_table);
63 
64 }  // namespace internal
65 
66 using internal::ReflectionOps;
67 using internal::WireFormat;
68 
MergeImpl(MessageLite & to,const MessageLite & from)69 void Message::MergeImpl(MessageLite& to, const MessageLite& from) {
70   ReflectionOps::Merge(DownCastMessage<Message>(from),
71                        DownCastMessage<Message>(&to));
72 }
73 
ClearImpl()74 void Message::ClearImpl() {
75   ReflectionOps::Clear(DownCastMessage<Message>(this));
76 }
77 
ByteSizeLongImpl(const MessageLite & msg)78 size_t Message::ByteSizeLongImpl(const MessageLite& msg) {
79   auto& _this = DownCastMessage<Message>(msg);
80   size_t size = WireFormat::ByteSize(_this);
81   _this.AccessCachedSize().Set(internal::ToCachedSize(size));
82   return size;
83 }
84 
_InternalSerializeImpl(const MessageLite & msg,uint8_t * target,io::EpsCopyOutputStream * stream)85 uint8_t* Message::_InternalSerializeImpl(const MessageLite& msg,
86                                          uint8_t* target,
87                                          io::EpsCopyOutputStream* stream) {
88   return WireFormat::_InternalSerialize(DownCastMessage<Message>(msg), target,
89                                         stream);
90 }
91 
MergeFrom(const Message & from)92 void Message::MergeFrom(const Message& from) {
93   auto* class_to = GetClassData();
94   auto* class_from = from.GetClassData();
95   if (class_to == nullptr || class_to != class_from) {
96     ReflectionOps::Merge(from, this);
97   } else {
98     class_to->full().merge_to_from(*this, from);
99   }
100 }
101 
CopyFrom(const Message & from)102 void Message::CopyFrom(const Message& from) {
103   if (&from == this) return;
104 
105   auto* class_to = GetClassData();
106   auto* class_from = from.GetClassData();
107 
108   if (class_from != nullptr && class_from == class_to) {
109     // Fail if "from" is a descendant of "to" as such copy is not allowed.
110     ABSL_DCHECK(!internal::IsDescendant(*this, from))
111         << "Source of CopyFrom cannot be a descendant of the target.";
112     Clear();
113     class_to->full().merge_to_from(*this, from);
114   } else {
115     const Descriptor* descriptor = GetDescriptor();
116     ABSL_CHECK_EQ(from.GetDescriptor(), descriptor)
117         << ": Tried to copy from a message with a different type. "
118            "to: "
119         << descriptor->full_name()
120         << ", "
121            "from: "
122         << from.GetDescriptor()->full_name();
123     ReflectionOps::Copy(from, this);
124   }
125 }
126 
127 #if !defined(PROTOBUF_CUSTOM_VTABLE)
Clear()128 void Message::Clear() { ReflectionOps::Clear(this); }
129 #endif  // !PROTOBUF_CUSTOM_VTABLE
130 
IsInitializedImpl(const MessageLite & msg)131 bool Message::IsInitializedImpl(const MessageLite& msg) {
132   return ReflectionOps::IsInitialized(DownCastMessage<Message>(msg));
133 }
134 
FindInitializationErrors(std::vector<std::string> * errors) const135 void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
136   return ReflectionOps::FindInitializationErrors(*this, "", errors);
137 }
138 
InitializationErrorString() const139 std::string Message::InitializationErrorString() const {
140   std::vector<std::string> errors;
141   FindInitializationErrors(&errors);
142   return absl::StrJoin(errors, ", ");
143 }
144 
CheckInitialized() const145 void Message::CheckInitialized() const {
146   ABSL_CHECK(IsInitialized())
147       << "Message of type \"" << GetDescriptor()->full_name()
148       << "\" is missing required fields: " << InitializationErrorString();
149 }
150 
DiscardUnknownFields()151 void Message::DiscardUnknownFields() {
152   return ReflectionOps::DiscardUnknownFields(this);
153 }
154 
GetMetadata() const155 Metadata Message::GetMetadata() const {
156   return GetMetadataImpl(GetClassData()->full());
157 }
158 
GetMetadataImpl(const internal::ClassDataFull & data)159 Metadata Message::GetMetadataImpl(const internal::ClassDataFull& data) {
160   auto* table = data.descriptor_table;
161   // Only codegen types provide a table. DynamicMessage does not provide a table
162   // and instead eagerly initializes the descriptor/reflection members.
163   if (ABSL_PREDICT_TRUE(table != nullptr)) {
164     if (ABSL_PREDICT_FALSE(data.get_metadata_tracker != nullptr)) {
165       data.get_metadata_tracker();
166     }
167     absl::call_once(*table->once, [table] {
168       internal::AssignDescriptorsOnceInnerCall(table);
169     });
170   }
171   return {data.descriptor, data.reflection};
172 }
173 
174 #if !defined(PROTOBUF_CUSTOM_VTABLE)
_InternalSerialize(uint8_t * target,io::EpsCopyOutputStream * stream) const175 uint8_t* Message::_InternalSerialize(uint8_t* target,
176                                      io::EpsCopyOutputStream* stream) const {
177   return WireFormat::_InternalSerialize(*this, target, stream);
178 }
179 
ByteSizeLong() const180 size_t Message::ByteSizeLong() const {
181   size_t size = WireFormat::ByteSize(*this);
182   AccessCachedSize().Set(internal::ToCachedSize(size));
183   return size;
184 }
185 #endif  // !PROTOBUF_CUSTOM_VTABLE
186 
ComputeUnknownFieldsSize(size_t total_size,const internal::CachedSize * cached_size) const187 size_t Message::ComputeUnknownFieldsSize(
188     size_t total_size, const internal::CachedSize* cached_size) const {
189   total_size += WireFormat::ComputeUnknownFieldsSize(
190       _internal_metadata_.unknown_fields<UnknownFieldSet>(
191           UnknownFieldSet::default_instance));
192   cached_size->Set(internal::ToCachedSize(total_size));
193   return total_size;
194 }
195 
MaybeComputeUnknownFieldsSize(size_t total_size,const internal::CachedSize * cached_size) const196 size_t Message::MaybeComputeUnknownFieldsSize(
197     size_t total_size, const internal::CachedSize* cached_size) const {
198   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
199     return ComputeUnknownFieldsSize(total_size, cached_size);
200   }
201   cached_size->Set(internal::ToCachedSize(total_size));
202   return total_size;
203 }
204 
SpaceUsedLong() const205 size_t Message::SpaceUsedLong() const {
206   return GetClassData()->full().descriptor_methods->space_used_long(*this);
207 }
208 
GetTypeNameImpl(const internal::ClassData * data)209 absl::string_view Message::GetTypeNameImpl(const internal::ClassData* data) {
210   return GetMetadataImpl(data->full()).descriptor->full_name();
211 }
212 
InitializationErrorStringImpl(const MessageLite & msg)213 static std::string InitializationErrorStringImpl(const MessageLite& msg) {
214   return DownCastMessage<Message>(msg).InitializationErrorString();
215 }
216 
GetTcParseTableImpl(const MessageLite & msg)217 const internal::TcParseTableBase* Message::GetTcParseTableImpl(
218     const MessageLite& msg) {
219   return DownCastMessage<Message>(msg).GetReflection()->GetTcParseTable();
220 }
221 
SpaceUsedLongImpl(const MessageLite & msg_lite)222 size_t Message::SpaceUsedLongImpl(const MessageLite& msg_lite) {
223   auto& msg = DownCastMessage<Message>(msg_lite);
224   return msg.GetReflection()->SpaceUsedLong(msg);
225 }
226 
DebugStringImpl(const MessageLite & msg)227 static std::string DebugStringImpl(const MessageLite& msg) {
228   return DownCastMessage<Message>(msg).DebugString();
229 }
230 
231 PROTOBUF_CONSTINIT const internal::DescriptorMethods
232     Message::kDescriptorMethods = {
233         GetTypeNameImpl,     InitializationErrorStringImpl,
234         GetTcParseTableImpl, SpaceUsedLongImpl,
235         DebugStringImpl,
236 };
237 
238 namespace internal {
CreateSplitMessageGeneric(Arena * arena,const void * default_split,size_t size,const void * message,const void * default_message)239 void* CreateSplitMessageGeneric(Arena* arena, const void* default_split,
240                                 size_t size, const void* message,
241                                 const void* default_message) {
242   ABSL_DCHECK_NE(message, default_message);
243   void* split =
244       (arena == nullptr) ? ::operator new(size) : arena->AllocateAligned(size);
245   memcpy(split, default_split, size);
246   return split;
247 }
248 }  // namespace internal
249 
250 // =============================================================================
251 // MessageFactory
252 
253 MessageFactory::~MessageFactory() = default;
254 
255 namespace {
256 
257 class GeneratedMessageFactory final : public MessageFactory {
258  public:
259   static GeneratedMessageFactory* singleton();
260 
261   void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
262   void RegisterType(const Descriptor* descriptor, const Message* prototype);
263 
264   const Message* TryGetPrototype(const Descriptor* type);
265 
266   // implements MessageFactory ---------------------------------------
267   const Message* GetPrototype(const Descriptor* type) override;
268 
269  private:
GeneratedMessageFactory()270   GeneratedMessageFactory() {
271     dropped_defaults_factory_.SetDelegateToGeneratedFactory(true);
272   }
273 
FindInTypeMap(const Descriptor * type)274   absl::optional<const Message*> FindInTypeMap(const Descriptor* type)
275       ABSL_SHARED_LOCKS_REQUIRED(mutex_)
276   {
277     auto it = type_map_.find(type);
278     if (it == type_map_.end()) return absl::nullopt;
279     return it->second.get();
280   }
281 
FindInFileMap(absl::string_view name)282   const google::protobuf::internal::DescriptorTable* FindInFileMap(
283       absl::string_view name) {
284     auto it = files_.find(name);
285     if (it == files_.end()) return nullptr;
286     return *it;
287   }
288 
289   struct DescriptorByNameHash {
290     using is_transparent = void;
operator ()google::protobuf::__anon5d6256a00211::GeneratedMessageFactory::DescriptorByNameHash291     size_t operator()(const google::protobuf::internal::DescriptorTable* t) const {
292       return absl::HashOf(absl::string_view{t->filename});
293     }
294 
operator ()google::protobuf::__anon5d6256a00211::GeneratedMessageFactory::DescriptorByNameHash295     size_t operator()(absl::string_view name) const {
296       return absl::HashOf(name);
297     }
298   };
299   struct DescriptorByNameEq {
300     using is_transparent = void;
operator ()google::protobuf::__anon5d6256a00211::GeneratedMessageFactory::DescriptorByNameEq301     bool operator()(const google::protobuf::internal::DescriptorTable* lhs,
302                     const google::protobuf::internal::DescriptorTable* rhs) const {
303       return lhs == rhs || (*this)(lhs->filename, rhs->filename);
304     }
operator ()google::protobuf::__anon5d6256a00211::GeneratedMessageFactory::DescriptorByNameEq305     bool operator()(absl::string_view lhs,
306                     const google::protobuf::internal::DescriptorTable* rhs) const {
307       return (*this)(lhs, rhs->filename);
308     }
operator ()google::protobuf::__anon5d6256a00211::GeneratedMessageFactory::DescriptorByNameEq309     bool operator()(const google::protobuf::internal::DescriptorTable* lhs,
310                     absl::string_view rhs) const {
311       return (*this)(lhs->filename, rhs);
312     }
operator ()google::protobuf::__anon5d6256a00211::GeneratedMessageFactory::DescriptorByNameEq313     bool operator()(absl::string_view lhs, absl::string_view rhs) const {
314       return lhs == rhs;
315     }
316   };
317 
318   // Only written at static init time, so does not require locking.
319   absl::flat_hash_set<const google::protobuf::internal::DescriptorTable*,
320                       DescriptorByNameHash, DescriptorByNameEq>
321       files_;
322   DynamicMessageFactory dropped_defaults_factory_;
323 
324   absl::Mutex mutex_;
325   class MessagePtr {
326    public:
MessagePtr()327     MessagePtr() : value_() {}
MessagePtr(const Message * msg)328     explicit MessagePtr(const Message* msg) : value_(msg) {}
get() const329     const Message* get() const { return value_; }
set(const Message * msg)330     void set(const Message* msg) { value_ = msg; }
331 
332    private:
333     const Message* value_;
334   };
335   absl::flat_hash_map<const Descriptor*, MessagePtr> type_map_
336       ABSL_GUARDED_BY(mutex_);
337 };
338 
singleton()339 GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
340   static auto instance =
341       internal::OnShutdownDelete(new GeneratedMessageFactory);
342   return instance;
343 }
344 
RegisterFile(const google::protobuf::internal::DescriptorTable * table)345 void GeneratedMessageFactory::RegisterFile(
346     const google::protobuf::internal::DescriptorTable* table) {
347   if (!files_.insert(table).second) {
348     ABSL_LOG(FATAL) << "File is already registered: " << table->filename;
349   }
350 }
351 
RegisterType(const Descriptor * descriptor,const Message * prototype)352 void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
353                                            const Message* prototype) {
354   ABSL_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
355       << "Tried to register a non-generated type with the generated "
356          "type registry.";
357 
358   // This should only be called as a result of calling a file registration
359   // function during GetPrototype(), in which case we already have locked
360   // the mutex.
361   mutex_.AssertHeld();
362   if (!type_map_.try_emplace(descriptor, prototype).second) {
363     ABSL_DLOG(FATAL) << "Type is already registered: "
364                      << descriptor->full_name();
365   }
366 }
367 
368 
GetPrototype(const Descriptor * type)369 const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
370   const Message* result = TryGetPrototype(type);
371   if (result == nullptr &&
372       type->file()->pool() == DescriptorPool::generated_pool()) {
373     // We registered this descriptor with a null pointer.
374     // In this case we need to create the prototype from the dynamic factory.
375     // We _must_ do this outside the lock because the dynamic factory will call
376     // back into the generated factory for cross linking.
377     result = dropped_defaults_factory_.GetPrototype(type);
378 
379     {
380       absl::WriterMutexLock lock(&mutex_);
381       // And update the main map to make the next lookup faster.
382       // We don't need to recheck here. Even if someone raced us here the result
383       // is the same, so we can just write it.
384       type_map_[type].set(result);
385     }
386   }
387 
388   return result;
389 }
390 
TryGetPrototype(const Descriptor * type)391 const Message* GeneratedMessageFactory::TryGetPrototype(
392     const Descriptor* type) {
393   absl::optional<const Message*> result;
394   {
395     absl::ReaderMutexLock lock(&mutex_);
396     result = FindInTypeMap(type);
397     if (result.has_value() && *result != nullptr) {
398       return *result;
399     }
400   }
401 
402   // If the type is not in the generated pool, then we can't possibly handle
403   // it.
404   if (type->file()->pool() != DescriptorPool::generated_pool()) return nullptr;
405 
406   // Apparently the file hasn't been registered yet.  Let's do that now.
407   const internal::DescriptorTable* registration_data =
408       FindInFileMap(type->file()->name());
409   if (registration_data == nullptr) {
410     ABSL_DLOG(FATAL) << "File appears to be in generated pool but wasn't "
411                         "registered: "
412                      << type->file()->name();
413     return nullptr;
414   }
415 
416   {
417     absl::WriterMutexLock lock(&mutex_);
418 
419     // Check if another thread preempted us.
420     result = FindInTypeMap(type);
421     if (!result.has_value()) {
422       // Nope.  OK, register everything.
423       internal::RegisterFileLevelMetadata(registration_data);
424       // Should be here now.
425       result = FindInTypeMap(type);
426       ABSL_DCHECK(result.has_value());
427     }
428   }
429 
430   return *result;
431 }
432 
433 }  // namespace
434 
TryGetGeneratedPrototype(const Descriptor * type)435 const Message* MessageFactory::TryGetGeneratedPrototype(
436     const Descriptor* type) {
437   return GeneratedMessageFactory::singleton()->TryGetPrototype(type);
438 }
439 
generated_factory()440 MessageFactory* MessageFactory::generated_factory() {
441   return GeneratedMessageFactory::singleton();
442 }
443 
InternalRegisterGeneratedFile(const google::protobuf::internal::DescriptorTable * table)444 void MessageFactory::InternalRegisterGeneratedFile(
445     const google::protobuf::internal::DescriptorTable* table) {
446   GeneratedMessageFactory::singleton()->RegisterFile(table);
447 }
448 
InternalRegisterGeneratedMessage(const Descriptor * descriptor,const Message * prototype)449 void MessageFactory::InternalRegisterGeneratedMessage(
450     const Descriptor* descriptor, const Message* prototype) {
451   GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
452 }
453 
454 
455 namespace {
456 template <typename T>
GetSingleton()457 T* GetSingleton() {
458   static T singleton;
459   return &singleton;
460 }
461 }  // namespace
462 
RepeatedFieldAccessor(const FieldDescriptor * field) const463 const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
464     const FieldDescriptor* field) const {
465   ABSL_CHECK(field->is_repeated());
466   switch (field->cpp_type()) {
467 #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
468   case FieldDescriptor::CPPTYPE_##TYPE:   \
469     return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
470     HANDLE_PRIMITIVE_TYPE(INT32, int32_t)
471     HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t)
472     HANDLE_PRIMITIVE_TYPE(INT64, int64_t)
473     HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t)
474     HANDLE_PRIMITIVE_TYPE(FLOAT, float)
475     HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
476     HANDLE_PRIMITIVE_TYPE(BOOL, bool)
477     HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
478 #undef HANDLE_PRIMITIVE_TYPE
479     case FieldDescriptor::CPPTYPE_STRING:
480       switch (field->cpp_string_type()) {
481         case FieldDescriptor::CppStringType::kCord:
482           ABSL_LOG(FATAL) << "Repeated cords are not supported.";
483         case FieldDescriptor::CppStringType::kView:
484         case FieldDescriptor::CppStringType::kString:
485           return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
486       }
487       break;
488     case FieldDescriptor::CPPTYPE_MESSAGE:
489       if (field->is_map()) {
490         return GetSingleton<internal::MapFieldAccessor>();
491       } else {
492         return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
493       }
494   }
495   ABSL_LOG(FATAL) << "Should not reach here.";
496   return nullptr;
497 }
498 
499 namespace internal {
500 template <>
501 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
502 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
503 // #240
504 PROTOBUF_NOINLINE
505 #endif
506     Message*
NewFromPrototype(const Message * prototype,Arena * arena)507     GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
508                                                   Arena* arena) {
509   return prototype->New(arena);
510 }
511 template <>
512 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
513 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
514 // #240
515 PROTOBUF_NOINLINE
516 #endif
517     Arena*
GetArena(Message * value)518     GenericTypeHandler<Message>::GetArena(Message* value) {
519   return value->GetArena();
520 }
521 
522 template void InternalMetadata::DoClear<UnknownFieldSet>();
523 template void InternalMetadata::DoMergeFrom<UnknownFieldSet>(
524     const UnknownFieldSet& other);
525 template void InternalMetadata::DoSwap<UnknownFieldSet>(UnknownFieldSet* other);
526 template void InternalMetadata::DeleteOutOfLineHelper<UnknownFieldSet>();
527 template UnknownFieldSet*
528 InternalMetadata::mutable_unknown_fields_slow<UnknownFieldSet>();
529 }  // namespace internal
530 
531 
532 }  // namespace protobuf
533 }  // namespace google
534 
535 #include "google/protobuf/port_undef.inc"
536