• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: kenton@google.com (Kenton Varda)
32 //  Based on original Protocol Buffers design by
33 //  Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <google/protobuf/message.h>
36 
37 #include <iostream>
38 #include <stack>
39 #include <unordered_map>
40 
41 #include <google/protobuf/stubs/casts.h>
42 #include <google/protobuf/stubs/logging.h>
43 #include <google/protobuf/stubs/common.h>
44 #include <google/protobuf/io/coded_stream.h>
45 #include <google/protobuf/io/zero_copy_stream_impl.h>
46 #include <google/protobuf/stubs/strutil.h>
47 #include <google/protobuf/descriptor.h>
48 #include <google/protobuf/descriptor.pb.h>
49 #include <google/protobuf/generated_message_reflection.h>
50 #include <google/protobuf/generated_message_util.h>
51 #include <google/protobuf/map_field.h>
52 #include <google/protobuf/map_field_inl.h>
53 #include <google/protobuf/parse_context.h>
54 #include <google/protobuf/reflection_internal.h>
55 #include <google/protobuf/reflection_ops.h>
56 #include <google/protobuf/unknown_field_set.h>
57 #include <google/protobuf/wire_format.h>
58 #include <google/protobuf/wire_format_lite.h>
59 #include <google/protobuf/stubs/map_util.h>
60 #include <google/protobuf/stubs/stl_util.h>
61 #include <google/protobuf/stubs/hash.h>
62 
63 // Must be included last.
64 #include <google/protobuf/port_def.inc>
65 
66 namespace google {
67 namespace protobuf {
68 
69 namespace internal {
70 
71 // TODO(gerbens) make this factorized better. This should not have to hop
72 // to reflection. Currently uses GeneratedMessageReflection and thus is
73 // defined in generated_message_reflection.cc
74 void RegisterFileLevelMetadata(const DescriptorTable* descriptor_table);
75 
76 }  // namespace internal
77 
78 using internal::ReflectionOps;
79 using internal::WireFormat;
80 using internal::WireFormatLite;
81 
MergeFrom(const Message & from)82 void Message::MergeFrom(const Message& from) {
83   auto* class_to = GetClassData();
84   auto* class_from = from.GetClassData();
85   auto* merge_to_from = class_to ? class_to->merge_to_from : nullptr;
86   if (class_to == nullptr || class_to != class_from) {
87     merge_to_from = [](Message& to, const Message& from) {
88       ReflectionOps::Merge(from, &to);
89     };
90   }
91   merge_to_from(*this, from);
92 }
93 
CheckTypeAndMergeFrom(const MessageLite & other)94 void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
95   MergeFrom(*down_cast<const Message*>(&other));
96 }
97 
CopyFrom(const Message & from)98 void Message::CopyFrom(const Message& from) {
99   if (&from == this) return;
100 
101   auto* class_to = GetClassData();
102   auto* class_from = from.GetClassData();
103   auto* copy_to_from = class_to ? class_to->copy_to_from : nullptr;
104 
105   if (class_to == nullptr || class_to != class_from) {
106     const Descriptor* descriptor = GetDescriptor();
107     GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
108         << ": Tried to copy from a message with a different type. "
109            "to: "
110         << descriptor->full_name()
111         << ", "
112            "from: "
113         << from.GetDescriptor()->full_name();
114     copy_to_from = [](Message& to, const Message& from) {
115       ReflectionOps::Copy(from, &to);
116     };
117   }
118   copy_to_from(*this, from);
119 }
120 
CopyWithSourceCheck(Message & to,const Message & from)121 void Message::CopyWithSourceCheck(Message& to, const Message& from) {
122 #ifndef NDEBUG
123   FailIfCopyFromDescendant(to, from);
124 #endif
125   to.Clear();
126   to.GetClassData()->merge_to_from(to, from);
127 }
128 
FailIfCopyFromDescendant(Message & to,const Message & from)129 void Message::FailIfCopyFromDescendant(Message& to, const Message& from) {
130   auto* arena = to.GetArenaForAllocation();
131   bool same_message_owned_arena = to.GetOwningArena() == nullptr &&
132                                   arena != nullptr &&
133                                   arena == from.GetOwningArena();
134   GOOGLE_CHECK(!same_message_owned_arena && !internal::IsDescendant(to, from))
135       << "Source of CopyFrom cannot be a descendant of the target.";
136 }
137 
GetTypeName() const138 std::string Message::GetTypeName() const {
139   return GetDescriptor()->full_name();
140 }
141 
Clear()142 void Message::Clear() { ReflectionOps::Clear(this); }
143 
IsInitialized() const144 bool Message::IsInitialized() const {
145   return ReflectionOps::IsInitialized(*this);
146 }
147 
FindInitializationErrors(std::vector<std::string> * errors) const148 void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
149   return ReflectionOps::FindInitializationErrors(*this, "", errors);
150 }
151 
InitializationErrorString() const152 std::string Message::InitializationErrorString() const {
153   std::vector<std::string> errors;
154   FindInitializationErrors(&errors);
155   return Join(errors, ", ");
156 }
157 
CheckInitialized() const158 void Message::CheckInitialized() const {
159   GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
160                          << "\" is missing required fields: "
161                          << InitializationErrorString();
162 }
163 
DiscardUnknownFields()164 void Message::DiscardUnknownFields() {
165   return ReflectionOps::DiscardUnknownFields(this);
166 }
167 
_InternalParse(const char * ptr,internal::ParseContext * ctx)168 const char* Message::_InternalParse(const char* ptr,
169                                     internal::ParseContext* ctx) {
170   return WireFormat::_InternalParse(this, ptr, ctx);
171 }
172 
_InternalSerialize(uint8_t * target,io::EpsCopyOutputStream * stream) const173 uint8_t* Message::_InternalSerialize(uint8_t* target,
174                                      io::EpsCopyOutputStream* stream) const {
175   return WireFormat::_InternalSerialize(*this, target, stream);
176 }
177 
ByteSizeLong() const178 size_t Message::ByteSizeLong() const {
179   size_t size = WireFormat::ByteSize(*this);
180   SetCachedSize(internal::ToCachedSize(size));
181   return size;
182 }
183 
SetCachedSize(int) const184 void Message::SetCachedSize(int /* size */) const {
185   GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
186              << "\" implements neither SetCachedSize() nor ByteSize().  "
187                 "Must implement one or the other.";
188 }
189 
ComputeUnknownFieldsSize(size_t total_size,internal::CachedSize * cached_size) const190 size_t Message::ComputeUnknownFieldsSize(
191     size_t total_size, internal::CachedSize* cached_size) const {
192   total_size += WireFormat::ComputeUnknownFieldsSize(
193       _internal_metadata_.unknown_fields<UnknownFieldSet>(
194           UnknownFieldSet::default_instance));
195   cached_size->Set(internal::ToCachedSize(total_size));
196   return total_size;
197 }
198 
MaybeComputeUnknownFieldsSize(size_t total_size,internal::CachedSize * cached_size) const199 size_t Message::MaybeComputeUnknownFieldsSize(
200     size_t total_size, internal::CachedSize* cached_size) const {
201   if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
202     return ComputeUnknownFieldsSize(total_size, cached_size);
203   }
204   cached_size->Set(internal::ToCachedSize(total_size));
205   return total_size;
206 }
207 
SpaceUsedLong() const208 size_t Message::SpaceUsedLong() const {
209   return GetReflection()->SpaceUsedLong(*this);
210 }
211 
GetInvariantPerBuild(uint64_t salt)212 uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
213   return salt;
214 }
215 
216 // =============================================================================
217 // MessageFactory
218 
~MessageFactory()219 MessageFactory::~MessageFactory() {}
220 
221 namespace {
222 
223 
224 #define HASH_MAP std::unordered_map
225 #define STR_HASH_FXN hash<::google::protobuf::StringPiece>
226 
227 
228 class GeneratedMessageFactory final : public MessageFactory {
229  public:
230   static GeneratedMessageFactory* singleton();
231 
232   void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
233   void RegisterType(const Descriptor* descriptor, const Message* prototype);
234 
235   // implements MessageFactory ---------------------------------------
236   const Message* GetPrototype(const Descriptor* type) override;
237 
238  private:
239   // Only written at static init time, so does not require locking.
240   HASH_MAP<StringPiece, const google::protobuf::internal::DescriptorTable*,
241            STR_HASH_FXN>
242       file_map_;
243 
244   internal::WrappedMutex mutex_;
245   // Initialized lazily, so requires locking.
246   std::unordered_map<const Descriptor*, const Message*> type_map_;
247 };
248 
singleton()249 GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
250   static auto instance =
251       internal::OnShutdownDelete(new GeneratedMessageFactory);
252   return instance;
253 }
254 
RegisterFile(const google::protobuf::internal::DescriptorTable * table)255 void GeneratedMessageFactory::RegisterFile(
256     const google::protobuf::internal::DescriptorTable* table) {
257   if (!InsertIfNotPresent(&file_map_, table->filename, table)) {
258     GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
259   }
260 }
261 
RegisterType(const Descriptor * descriptor,const Message * prototype)262 void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
263                                            const Message* prototype) {
264   GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
265       << "Tried to register a non-generated type with the generated "
266          "type registry.";
267 
268   // This should only be called as a result of calling a file registration
269   // function during GetPrototype(), in which case we already have locked
270   // the mutex.
271   mutex_.AssertHeld();
272   if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
273     GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
274   }
275 }
276 
277 
GetPrototype(const Descriptor * type)278 const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
279   {
280     ReaderMutexLock lock(&mutex_);
281     const Message* result = FindPtrOrNull(type_map_, type);
282     if (result != nullptr) return result;
283   }
284 
285   // If the type is not in the generated pool, then we can't possibly handle
286   // it.
287   if (type->file()->pool() != DescriptorPool::generated_pool()) return nullptr;
288 
289   // Apparently the file hasn't been registered yet.  Let's do that now.
290   const internal::DescriptorTable* registration_data =
291       FindPtrOrNull(file_map_, type->file()->name().c_str());
292   if (registration_data == nullptr) {
293     GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
294                    "registered: "
295                 << type->file()->name();
296     return nullptr;
297   }
298 
299   WriterMutexLock lock(&mutex_);
300 
301   // Check if another thread preempted us.
302   const Message* result = FindPtrOrNull(type_map_, type);
303   if (result == nullptr) {
304     // Nope.  OK, register everything.
305     internal::RegisterFileLevelMetadata(registration_data);
306     // Should be here now.
307     result = FindPtrOrNull(type_map_, type);
308   }
309 
310   if (result == nullptr) {
311     GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
312                 << "registered: " << type->full_name();
313   }
314 
315   return result;
316 }
317 
318 }  // namespace
319 
generated_factory()320 MessageFactory* MessageFactory::generated_factory() {
321   return GeneratedMessageFactory::singleton();
322 }
323 
InternalRegisterGeneratedFile(const google::protobuf::internal::DescriptorTable * table)324 void MessageFactory::InternalRegisterGeneratedFile(
325     const google::protobuf::internal::DescriptorTable* table) {
326   GeneratedMessageFactory::singleton()->RegisterFile(table);
327 }
328 
InternalRegisterGeneratedMessage(const Descriptor * descriptor,const Message * prototype)329 void MessageFactory::InternalRegisterGeneratedMessage(
330     const Descriptor* descriptor, const Message* prototype) {
331   GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
332 }
333 
334 
335 namespace {
336 template <typename T>
GetSingleton()337 T* GetSingleton() {
338   static T singleton;
339   return &singleton;
340 }
341 }  // namespace
342 
RepeatedFieldAccessor(const FieldDescriptor * field) const343 const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
344     const FieldDescriptor* field) const {
345   GOOGLE_CHECK(field->is_repeated());
346   switch (field->cpp_type()) {
347 #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
348   case FieldDescriptor::CPPTYPE_##TYPE:   \
349     return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
350     HANDLE_PRIMITIVE_TYPE(INT32, int32_t)
351     HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t)
352     HANDLE_PRIMITIVE_TYPE(INT64, int64_t)
353     HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t)
354     HANDLE_PRIMITIVE_TYPE(FLOAT, float)
355     HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
356     HANDLE_PRIMITIVE_TYPE(BOOL, bool)
357     HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
358 #undef HANDLE_PRIMITIVE_TYPE
359     case FieldDescriptor::CPPTYPE_STRING:
360       switch (field->options().ctype()) {
361         default:
362         case FieldOptions::STRING:
363           return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
364       }
365       break;
366     case FieldDescriptor::CPPTYPE_MESSAGE:
367       if (field->is_map()) {
368         return GetSingleton<internal::MapFieldAccessor>();
369       } else {
370         return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
371       }
372   }
373   GOOGLE_LOG(FATAL) << "Should not reach here.";
374   return nullptr;
375 }
376 
377 namespace internal {
378 template <>
379 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
380 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
381 // #240
382 PROTOBUF_NOINLINE
383 #endif
384     Message*
NewFromPrototype(const Message * prototype,Arena * arena)385     GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
386                                                   Arena* arena) {
387   return prototype->New(arena);
388 }
389 template <>
390 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
391 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
392 // #240
393 PROTOBUF_NOINLINE
394 #endif
395     Arena*
GetOwningArena(Message * value)396     GenericTypeHandler<Message>::GetOwningArena(Message* value) {
397   return value->GetOwningArena();
398 }
399 }  // namespace internal
400 
401 }  // namespace protobuf
402 }  // namespace google
403 
404 #include <google/protobuf/port_undef.inc>
405