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