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
66namespace google {
67namespace protobuf {
68
69namespace 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
74void RegisterFileLevelMetadata(const DescriptorTable* descriptor_table);
75
76} // namespace internal
77
78using internal::ReflectionOps;
79using internal::WireFormat;
80using internal::WireFormatLite;
81
82void 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: &to);
89 };
90 }
91 merge_to_from(*this, from);
92}
93
94void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
95 MergeFrom(from: *down_cast<const Message*>(f: &other));
96}
97
98void 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: &to);
116 };
117 }
118 copy_to_from(*this, from);
119}
120
121void 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
129void 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
138std::string Message::GetTypeName() const {
139 return GetDescriptor()->full_name();
140}
141
142void Message::Clear() { ReflectionOps::Clear(message: this); }
143
144bool Message::IsInitialized() const {
145 return ReflectionOps::IsInitialized(message: *this);
146}
147
148void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
149 return ReflectionOps::FindInitializationErrors(message: *this, prefix: "", errors);
150}
151
152std::string Message::InitializationErrorString() const {
153 std::vector<std::string> errors;
154 FindInitializationErrors(errors: &errors);
155 return Join(components: errors, delim: ", ");
156}
157
158void Message::CheckInitialized() const {
159 GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
160 << "\" is missing required fields: "
161 << InitializationErrorString();
162}
163
164void Message::DiscardUnknownFields() {
165 return ReflectionOps::DiscardUnknownFields(message: this);
166}
167
168const char* Message::_InternalParse(const char* ptr,
169 internal::ParseContext* ctx) {
170 return WireFormat::_InternalParse(msg: this, ptr, ctx);
171}
172
173uint8_t* Message::_InternalSerialize(uint8_t* target,
174 io::EpsCopyOutputStream* stream) const {
175 return WireFormat::_InternalSerialize(message: *this, target, stream);
176}
177
178size_t Message::ByteSizeLong() const {
179 size_t size = WireFormat::ByteSize(message: *this);
180 SetCachedSize(internal::ToCachedSize(size));
181 return size;
182}
183
184void 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
190size_t Message::ComputeUnknownFieldsSize(
191 size_t total_size, internal::CachedSize* cached_size) const {
192 total_size += WireFormat::ComputeUnknownFieldsSize(
193 unknown_fields: _internal_metadata_.unknown_fields<UnknownFieldSet>(
194 default_instance: UnknownFieldSet::default_instance));
195 cached_size->Set(internal::ToCachedSize(size: total_size));
196 return total_size;
197}
198
199size_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(size: total_size));
205 return total_size;
206}
207
208size_t Message::SpaceUsedLong() const {
209 return GetReflection()->SpaceUsedLong(message: *this);
210}
211
212uint64_t Message::GetInvariantPerBuild(uint64_t salt) {
213 return salt;
214}
215
216// =============================================================================
217// MessageFactory
218
219MessageFactory::~MessageFactory() {}
220
221namespace {
222
223
224#define HASH_MAP std::unordered_map
225#define STR_HASH_FXN hash<::google::protobuf::StringPiece>
226
227
228class 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
249GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
250 static auto instance =
251 internal::OnShutdownDelete(p: new GeneratedMessageFactory);
252 return instance;
253}
254
255void GeneratedMessageFactory::RegisterFile(
256 const google::protobuf::internal::DescriptorTable* table) {
257 if (!InsertIfNotPresent(collection: &file_map_, key: table->filename, value: table)) {
258 GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
259 }
260}
261
262void 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(collection: &type_map_, key: descriptor, value: prototype)) {
273 GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
274 }
275}
276
277
278const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
279 {
280 ReaderMutexLock lock(&mutex_);
281 const Message* result = FindPtrOrNull(collection&: type_map_, key: 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(collection&: file_map_, key: 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(collection&: type_map_, key: type);
303 if (result == nullptr) {
304 // Nope. OK, register everything.
305 internal::RegisterFileLevelMetadata(descriptor_table: registration_data);
306 // Should be here now.
307 result = FindPtrOrNull(collection&: type_map_, key: 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
320MessageFactory* MessageFactory::generated_factory() {
321 return GeneratedMessageFactory::singleton();
322}
323
324void MessageFactory::InternalRegisterGeneratedFile(
325 const google::protobuf::internal::DescriptorTable* table) {
326 GeneratedMessageFactory::singleton()->RegisterFile(table);
327}
328
329void MessageFactory::InternalRegisterGeneratedMessage(
330 const Descriptor* descriptor, const Message* prototype) {
331 GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
332}
333
334
335namespace {
336template <typename T>
337T* GetSingleton() {
338 static T singleton;
339 return &singleton;
340}
341} // namespace
342
343const 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
377namespace internal {
378template <>
379#if defined(_MSC_VER) && (_MSC_VER >= 1800)
380// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
381// #240
382PROTOBUF_NOINLINE
383#endif
384 Message*
385 GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
386 Arena* arena) {
387 return prototype->New(arena);
388}
389template <>
390#if defined(_MSC_VER) && (_MSC_VER >= 1800)
391// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
392// #240
393PROTOBUF_NOINLINE
394#endif
395 Arena*
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