• 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 
CopyWithSizeCheck(Message * to,const Message & from)121 void Message::CopyWithSizeCheck(Message* to, const Message& from) {
122 #ifndef NDEBUG
123   size_t from_size = from.ByteSizeLong();
124 #endif
125   to->Clear();
126 #ifndef NDEBUG
127   GOOGLE_CHECK_EQ(from_size, from.ByteSizeLong())
128       << "Source of CopyFrom changed when clearing target.  Either "
129          "source is a nested message in target (not allowed), or "
130          "another thread is modifying the source.";
131 #endif
132   to->GetClassData()->merge_to_from(to, from);
133 }
134 
GetTypeName() const135 std::string Message::GetTypeName() const {
136   return GetDescriptor()->full_name();
137 }
138 
Clear()139 void Message::Clear() { ReflectionOps::Clear(this); }
140 
IsInitialized() const141 bool Message::IsInitialized() const {
142   return ReflectionOps::IsInitialized(*this);
143 }
144 
FindInitializationErrors(std::vector<std::string> * errors) const145 void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
146   return ReflectionOps::FindInitializationErrors(*this, "", errors);
147 }
148 
InitializationErrorString() const149 std::string Message::InitializationErrorString() const {
150   std::vector<std::string> errors;
151   FindInitializationErrors(&errors);
152   return Join(errors, ", ");
153 }
154 
CheckInitialized() const155 void Message::CheckInitialized() const {
156   GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
157                          << "\" is missing required fields: "
158                          << InitializationErrorString();
159 }
160 
DiscardUnknownFields()161 void Message::DiscardUnknownFields() {
162   return ReflectionOps::DiscardUnknownFields(this);
163 }
164 
_InternalParse(const char * ptr,internal::ParseContext * ctx)165 const char* Message::_InternalParse(const char* ptr,
166                                     internal::ParseContext* ctx) {
167   return WireFormat::_InternalParse(this, ptr, ctx);
168 }
169 
_InternalSerialize(uint8_t * target,io::EpsCopyOutputStream * stream) const170 uint8_t* Message::_InternalSerialize(uint8_t* target,
171                                      io::EpsCopyOutputStream* stream) const {
172   return WireFormat::_InternalSerialize(*this, target, stream);
173 }
174 
ByteSizeLong() const175 size_t Message::ByteSizeLong() const {
176   size_t size = WireFormat::ByteSize(*this);
177   SetCachedSize(internal::ToCachedSize(size));
178   return size;
179 }
180 
SetCachedSize(int) const181 void Message::SetCachedSize(int /* size */) const {
182   GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
183              << "\" implements neither SetCachedSize() nor ByteSize().  "
184                 "Must implement one or the other.";
185 }
186 
ComputeUnknownFieldsSize(size_t total_size,internal::CachedSize * cached_size) const187 size_t Message::ComputeUnknownFieldsSize(
188     size_t total_size, 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,internal::CachedSize * cached_size) const196 size_t Message::MaybeComputeUnknownFieldsSize(
197     size_t total_size, 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 GetReflection()->SpaceUsedLong(*this);
207 }
208 
GetInvariantPerBuild(uint64_t salt)209 uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
210   return salt;
211 }
212 
213 // =============================================================================
214 // MessageFactory
215 
~MessageFactory()216 MessageFactory::~MessageFactory() {}
217 
218 namespace {
219 
220 
221 #define HASH_MAP std::unordered_map
222 #define STR_HASH_FXN hash<::google::protobuf::StringPiece>
223 
224 
225 class GeneratedMessageFactory final : public MessageFactory {
226  public:
227   static GeneratedMessageFactory* singleton();
228 
229   void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
230   void RegisterType(const Descriptor* descriptor, const Message* prototype);
231 
232   // implements MessageFactory ---------------------------------------
233   const Message* GetPrototype(const Descriptor* type) override;
234 
235  private:
236   // Only written at static init time, so does not require locking.
237   HASH_MAP<StringPiece, const google::protobuf::internal::DescriptorTable*,
238            STR_HASH_FXN>
239       file_map_;
240 
241   internal::WrappedMutex mutex_;
242   // Initialized lazily, so requires locking.
243   std::unordered_map<const Descriptor*, const Message*> type_map_;
244 };
245 
singleton()246 GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
247   static auto instance =
248       internal::OnShutdownDelete(new GeneratedMessageFactory);
249   return instance;
250 }
251 
RegisterFile(const google::protobuf::internal::DescriptorTable * table)252 void GeneratedMessageFactory::RegisterFile(
253     const google::protobuf::internal::DescriptorTable* table) {
254   if (!InsertIfNotPresent(&file_map_, table->filename, table)) {
255     GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
256   }
257 }
258 
RegisterType(const Descriptor * descriptor,const Message * prototype)259 void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
260                                            const Message* prototype) {
261   GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
262       << "Tried to register a non-generated type with the generated "
263          "type registry.";
264 
265   // This should only be called as a result of calling a file registration
266   // function during GetPrototype(), in which case we already have locked
267   // the mutex.
268   mutex_.AssertHeld();
269   if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
270     GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
271   }
272 }
273 
274 
GetPrototype(const Descriptor * type)275 const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
276   {
277     ReaderMutexLock lock(&mutex_);
278     const Message* result = FindPtrOrNull(type_map_, type);
279     if (result != nullptr) return result;
280   }
281 
282   // If the type is not in the generated pool, then we can't possibly handle
283   // it.
284   if (type->file()->pool() != DescriptorPool::generated_pool()) return nullptr;
285 
286   // Apparently the file hasn't been registered yet.  Let's do that now.
287   const internal::DescriptorTable* registration_data =
288       FindPtrOrNull(file_map_, type->file()->name().c_str());
289   if (registration_data == nullptr) {
290     GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
291                    "registered: "
292                 << type->file()->name();
293     return nullptr;
294   }
295 
296   WriterMutexLock lock(&mutex_);
297 
298   // Check if another thread preempted us.
299   const Message* result = FindPtrOrNull(type_map_, type);
300   if (result == nullptr) {
301     // Nope.  OK, register everything.
302     internal::RegisterFileLevelMetadata(registration_data);
303     // Should be here now.
304     result = FindPtrOrNull(type_map_, type);
305   }
306 
307   if (result == nullptr) {
308     GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
309                 << "registered: " << type->full_name();
310   }
311 
312   return result;
313 }
314 
315 }  // namespace
316 
generated_factory()317 MessageFactory* MessageFactory::generated_factory() {
318   return GeneratedMessageFactory::singleton();
319 }
320 
InternalRegisterGeneratedFile(const google::protobuf::internal::DescriptorTable * table)321 void MessageFactory::InternalRegisterGeneratedFile(
322     const google::protobuf::internal::DescriptorTable* table) {
323   GeneratedMessageFactory::singleton()->RegisterFile(table);
324 }
325 
InternalRegisterGeneratedMessage(const Descriptor * descriptor,const Message * prototype)326 void MessageFactory::InternalRegisterGeneratedMessage(
327     const Descriptor* descriptor, const Message* prototype) {
328   GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
329 }
330 
331 
332 namespace {
333 template <typename T>
GetSingleton()334 T* GetSingleton() {
335   static T singleton;
336   return &singleton;
337 }
338 }  // namespace
339 
RepeatedFieldAccessor(const FieldDescriptor * field) const340 const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
341     const FieldDescriptor* field) const {
342   GOOGLE_CHECK(field->is_repeated());
343   switch (field->cpp_type()) {
344 #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \
345   case FieldDescriptor::CPPTYPE_##TYPE:   \
346     return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
347     HANDLE_PRIMITIVE_TYPE(INT32, int32_t)
348     HANDLE_PRIMITIVE_TYPE(UINT32, uint32_t)
349     HANDLE_PRIMITIVE_TYPE(INT64, int64_t)
350     HANDLE_PRIMITIVE_TYPE(UINT64, uint64_t)
351     HANDLE_PRIMITIVE_TYPE(FLOAT, float)
352     HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
353     HANDLE_PRIMITIVE_TYPE(BOOL, bool)
354     HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
355 #undef HANDLE_PRIMITIVE_TYPE
356     case FieldDescriptor::CPPTYPE_STRING:
357       switch (field->options().ctype()) {
358         default:
359         case FieldOptions::STRING:
360           return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
361       }
362       break;
363     case FieldDescriptor::CPPTYPE_MESSAGE:
364       if (field->is_map()) {
365         return GetSingleton<internal::MapFieldAccessor>();
366       } else {
367         return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
368       }
369   }
370   GOOGLE_LOG(FATAL) << "Should not reach here.";
371   return nullptr;
372 }
373 
374 namespace internal {
375 template <>
376 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
377 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
378 // #240
379 PROTOBUF_NOINLINE
380 #endif
381     Message*
NewFromPrototype(const Message * prototype,Arena * arena)382     GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
383                                                   Arena* arena) {
384   return prototype->New(arena);
385 }
386 template <>
387 #if defined(_MSC_VER) && (_MSC_VER >= 1800)
388 // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
389 // #240
390 PROTOBUF_NOINLINE
391 #endif
392     Arena*
GetOwningArena(Message * value)393     GenericTypeHandler<Message>::GetOwningArena(Message* value) {
394   return value->GetOwningArena();
395 }
396 }  // namespace internal
397 
398 }  // namespace protobuf
399 }  // namespace google
400 
401 #include <google/protobuf/port_undef.inc>
402