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// Authors: wink@google.com (Wink Saville),
32// kenton@google.com (Kenton Varda)
33// Based on original Protocol Buffers design by
34// Sanjay Ghemawat, Jeff Dean, and others.
35
36#include <google/protobuf/message_lite.h>
37
38#include <climits>
39#include <cstdint>
40#include <string>
41
42#include <google/protobuf/stubs/logging.h>
43#include <google/protobuf/stubs/common.h>
44#include <google/protobuf/parse_context.h>
45#include <google/protobuf/io/coded_stream.h>
46#include <google/protobuf/io/zero_copy_stream.h>
47#include <google/protobuf/io/zero_copy_stream_impl.h>
48#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
49#include <google/protobuf/arena.h>
50#include <google/protobuf/stubs/strutil.h>
51#include <google/protobuf/generated_message_util.h>
52#include <google/protobuf/repeated_field.h>
53#include <google/protobuf/stubs/stl_util.h>
54#include <google/protobuf/stubs/mutex.h>
55
56// Must be included last.
57#include <google/protobuf/port_def.inc>
58
59namespace google {
60namespace protobuf {
61
62std::string MessageLite::InitializationErrorString() const {
63 return "(cannot determine missing fields for lite message)";
64}
65
66std::string MessageLite::DebugString() const {
67 std::uintptr_t address = reinterpret_cast<std::uintptr_t>(this);
68 return StrCat(a: "MessageLite at 0x", b: strings::Hex(address));
69}
70
71namespace {
72
73// When serializing, we first compute the byte size, then serialize the message.
74// If serialization produces a different number of bytes than expected, we
75// call this function, which crashes. The problem could be due to a bug in the
76// protobuf implementation but is more likely caused by concurrent modification
77// of the message. This function attempts to distinguish between the two and
78// provide a useful error message.
79void ByteSizeConsistencyError(size_t byte_size_before_serialization,
80 size_t byte_size_after_serialization,
81 size_t bytes_produced_by_serialization,
82 const MessageLite& message) {
83 GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
84 << message.GetTypeName()
85 << " was modified concurrently during serialization.";
86 GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
87 << "Byte size calculation and serialization were inconsistent. This "
88 "may indicate a bug in protocol buffers or it may be caused by "
89 "concurrent modification of "
90 << message.GetTypeName() << ".";
91 GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
92}
93
94std::string InitializationErrorMessage(const char* action,
95 const MessageLite& message) {
96 // Note: We want to avoid depending on strutil in the lite library, otherwise
97 // we'd use:
98 //
99 // return strings::Substitute(
100 // "Can't $0 message of type \"$1\" because it is missing required "
101 // "fields: $2",
102 // action, message.GetTypeName(),
103 // message.InitializationErrorString());
104
105 std::string result;
106 result += "Can't ";
107 result += action;
108 result += " message of type \"";
109 result += message.GetTypeName();
110 result += "\" because it is missing required fields: ";
111 result += message.InitializationErrorString();
112 return result;
113}
114
115inline StringPiece as_string_view(const void* data, int size) {
116 return StringPiece(static_cast<const char*>(data), size);
117}
118
119// Returns true of all required fields are present / have values.
120inline bool CheckFieldPresence(const internal::ParseContext& ctx,
121 const MessageLite& msg,
122 MessageLite::ParseFlags parse_flags) {
123 (void)ctx; // Parameter is used by Google-internal code.
124 if (PROTOBUF_PREDICT_FALSE((parse_flags & MessageLite::kMergePartial) != 0)) {
125 return true;
126 }
127 return msg.IsInitializedWithErrors();
128}
129
130} // namespace
131
132void MessageLite::LogInitializationErrorMessage() const {
133 GOOGLE_LOG(ERROR) << InitializationErrorMessage(action: "parse", message: *this);
134}
135
136namespace internal {
137
138template <bool aliasing>
139bool MergeFromImpl(StringPiece input, MessageLite* msg,
140 MessageLite::ParseFlags parse_flags) {
141 const char* ptr;
142 internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
143 aliasing, &ptr, input);
144 ptr = msg->_InternalParse(ptr, &ctx);
145 // ctx has an explicit limit set (length of string_view).
146 if (PROTOBUF_PREDICT_TRUE(ptr && ctx.EndedAtLimit())) {
147 return CheckFieldPresence(ctx, msg: *msg, parse_flags);
148 }
149 return false;
150}
151
152template <bool aliasing>
153bool MergeFromImpl(io::ZeroCopyInputStream* input, MessageLite* msg,
154 MessageLite::ParseFlags parse_flags) {
155 const char* ptr;
156 internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
157 aliasing, &ptr, input);
158 ptr = msg->_InternalParse(ptr, &ctx);
159 // ctx has no explicit limit (hence we end on end of stream)
160 if (PROTOBUF_PREDICT_TRUE(ptr && ctx.EndedAtEndOfStream())) {
161 return CheckFieldPresence(ctx, msg: *msg, parse_flags);
162 }
163 return false;
164}
165
166template <bool aliasing>
167bool MergeFromImpl(BoundedZCIS input, MessageLite* msg,
168 MessageLite::ParseFlags parse_flags) {
169 const char* ptr;
170 internal::ParseContext ctx(io::CodedInputStream::GetDefaultRecursionLimit(),
171 aliasing, &ptr, input.zcis, input.limit);
172 ptr = msg->_InternalParse(ptr, &ctx);
173 if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
174 ctx.BackUp(ptr);
175 if (PROTOBUF_PREDICT_TRUE(ctx.EndedAtLimit())) {
176 return CheckFieldPresence(ctx, msg: *msg, parse_flags);
177 }
178 return false;
179}
180
181template bool MergeFromImpl<false>(StringPiece input, MessageLite* msg,
182 MessageLite::ParseFlags parse_flags);
183template bool MergeFromImpl<true>(StringPiece input, MessageLite* msg,
184 MessageLite::ParseFlags parse_flags);
185template bool MergeFromImpl<false>(io::ZeroCopyInputStream* input,
186 MessageLite* msg,
187 MessageLite::ParseFlags parse_flags);
188template bool MergeFromImpl<true>(io::ZeroCopyInputStream* input,
189 MessageLite* msg,
190 MessageLite::ParseFlags parse_flags);
191template bool MergeFromImpl<false>(BoundedZCIS input, MessageLite* msg,
192 MessageLite::ParseFlags parse_flags);
193template bool MergeFromImpl<true>(BoundedZCIS input, MessageLite* msg,
194 MessageLite::ParseFlags parse_flags);
195
196} // namespace internal
197
198class ZeroCopyCodedInputStream : public io::ZeroCopyInputStream {
199 public:
200 ZeroCopyCodedInputStream(io::CodedInputStream* cis) : cis_(cis) {}
201 bool Next(const void** data, int* size) final {
202 if (!cis_->GetDirectBufferPointer(data, size)) return false;
203 cis_->Skip(count: *size);
204 return true;
205 }
206 void BackUp(int count) final { cis_->Advance(amount: -count); }
207 bool Skip(int count) final { return cis_->Skip(count); }
208 int64_t ByteCount() const final { return 0; }
209
210 bool aliasing_enabled() { return cis_->aliasing_enabled_; }
211
212 private:
213 io::CodedInputStream* cis_;
214};
215
216bool MessageLite::MergeFromImpl(io::CodedInputStream* input,
217 MessageLite::ParseFlags parse_flags) {
218 ZeroCopyCodedInputStream zcis(input);
219 const char* ptr;
220 internal::ParseContext ctx(input->RecursionBudget(), zcis.aliasing_enabled(),
221 &ptr, &zcis);
222 // MergePartialFromCodedStream allows terminating the wireformat by 0 or
223 // end-group tag. Leaving it up to the caller to verify correct ending by
224 // calling LastTagWas on input. We need to maintain this behavior.
225 ctx.TrackCorrectEnding();
226 ctx.data().pool = input->GetExtensionPool();
227 ctx.data().factory = input->GetExtensionFactory();
228 ptr = _InternalParse(ptr, &ctx);
229 if (PROTOBUF_PREDICT_FALSE(!ptr)) return false;
230 ctx.BackUp(ptr);
231 if (!ctx.EndedAtEndOfStream()) {
232 GOOGLE_DCHECK_NE(ctx.LastTag(), 1); // We can't end on a pushed limit.
233 if (ctx.IsExceedingLimit(ptr)) return false;
234 input->SetLastTag(ctx.LastTag());
235 } else {
236 input->SetConsumed();
237 }
238 return CheckFieldPresence(ctx, msg: *this, parse_flags);
239}
240
241bool MessageLite::MergePartialFromCodedStream(io::CodedInputStream* input) {
242 return MergeFromImpl(input, parse_flags: kMergePartial);
243}
244
245bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
246 return MergeFromImpl(input, parse_flags: kMerge);
247}
248
249bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
250 Clear();
251 return MergeFromImpl(input, parse_flags: kParse);
252}
253
254bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
255 Clear();
256 return MergeFromImpl(input, parse_flags: kParsePartial);
257}
258
259bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
260 return ParseFrom<kParse>(input);
261}
262
263bool MessageLite::ParsePartialFromZeroCopyStream(
264 io::ZeroCopyInputStream* input) {
265 return ParseFrom<kParsePartial>(input);
266}
267
268bool MessageLite::ParseFromFileDescriptor(int file_descriptor) {
269 io::FileInputStream input(file_descriptor);
270 return ParseFromZeroCopyStream(input: &input) && input.GetErrno() == 0;
271}
272
273bool MessageLite::ParsePartialFromFileDescriptor(int file_descriptor) {
274 io::FileInputStream input(file_descriptor);
275 return ParsePartialFromZeroCopyStream(input: &input) && input.GetErrno() == 0;
276}
277
278bool MessageLite::ParseFromIstream(std::istream* input) {
279 io::IstreamInputStream zero_copy_input(input);
280 return ParseFromZeroCopyStream(input: &zero_copy_input) && input->eof();
281}
282
283bool MessageLite::ParsePartialFromIstream(std::istream* input) {
284 io::IstreamInputStream zero_copy_input(input);
285 return ParsePartialFromZeroCopyStream(input: &zero_copy_input) && input->eof();
286}
287
288bool MessageLite::MergePartialFromBoundedZeroCopyStream(
289 io::ZeroCopyInputStream* input, int size) {
290 return ParseFrom<kMergePartial>(input: internal::BoundedZCIS{.zcis: input, .limit: size});
291}
292
293bool MessageLite::MergeFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
294 int size) {
295 return ParseFrom<kMerge>(input: internal::BoundedZCIS{.zcis: input, .limit: size});
296}
297
298bool MessageLite::ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
299 int size) {
300 return ParseFrom<kParse>(input: internal::BoundedZCIS{.zcis: input, .limit: size});
301}
302
303bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
304 io::ZeroCopyInputStream* input, int size) {
305 return ParseFrom<kParsePartial>(input: internal::BoundedZCIS{.zcis: input, .limit: size});
306}
307
308bool MessageLite::ParseFromString(ConstStringParam data) {
309 return ParseFrom<kParse>(input: data);
310}
311
312bool MessageLite::ParsePartialFromString(ConstStringParam data) {
313 return ParseFrom<kParsePartial>(input: data);
314}
315
316bool MessageLite::ParseFromArray(const void* data, int size) {
317 return ParseFrom<kParse>(input: as_string_view(data, size));
318}
319
320bool MessageLite::ParsePartialFromArray(const void* data, int size) {
321 return ParseFrom<kParsePartial>(input: as_string_view(data, size));
322}
323
324bool MessageLite::MergeFromString(ConstStringParam data) {
325 return ParseFrom<kMerge>(input: data);
326}
327
328
329// ===================================================================
330
331inline uint8_t* SerializeToArrayImpl(const MessageLite& msg, uint8_t* target,
332 int size) {
333 constexpr bool debug = false;
334 if (debug) {
335 // Force serialization to a stream with a block size of 1, which forces
336 // all writes to the stream to cross buffers triggering all fallback paths
337 // in the unittests when serializing to string / array.
338 io::ArrayOutputStream stream(target, size, 1);
339 uint8_t* ptr;
340 io::EpsCopyOutputStream out(
341 &stream, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
342 &ptr);
343 ptr = msg._InternalSerialize(ptr, stream: &out);
344 out.Trim(ptr);
345 GOOGLE_DCHECK(!out.HadError() && stream.ByteCount() == size);
346 return target + size;
347 } else {
348 io::EpsCopyOutputStream out(
349 target, size,
350 io::CodedOutputStream::IsDefaultSerializationDeterministic());
351 auto res = msg._InternalSerialize(ptr: target, stream: &out);
352 GOOGLE_DCHECK(target + size == res);
353 return res;
354 }
355}
356
357uint8_t* MessageLite::SerializeWithCachedSizesToArray(uint8_t* target) const {
358 // We only optimize this when using optimize_for = SPEED. In other cases
359 // we just use the CodedOutputStream path.
360 return SerializeToArrayImpl(msg: *this, target, size: GetCachedSize());
361}
362
363bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
364 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage(action: "serialize", message: *this);
365 return SerializePartialToCodedStream(output);
366}
367
368bool MessageLite::SerializePartialToCodedStream(
369 io::CodedOutputStream* output) const {
370 const size_t size = ByteSizeLong(); // Force size to be cached.
371 if (size > INT_MAX) {
372 GOOGLE_LOG(ERROR) << GetTypeName()
373 << " exceeded maximum protobuf size of 2GB: " << size;
374 return false;
375 }
376
377 int original_byte_count = output->ByteCount();
378 SerializeWithCachedSizes(output);
379 if (output->HadError()) {
380 return false;
381 }
382 int final_byte_count = output->ByteCount();
383
384 if (final_byte_count - original_byte_count != static_cast<int64_t>(size)) {
385 ByteSizeConsistencyError(byte_size_before_serialization: size, byte_size_after_serialization: ByteSizeLong(),
386 bytes_produced_by_serialization: final_byte_count - original_byte_count, message: *this);
387 }
388
389 return true;
390}
391
392bool MessageLite::SerializeToZeroCopyStream(
393 io::ZeroCopyOutputStream* output) const {
394 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage(action: "serialize", message: *this);
395 return SerializePartialToZeroCopyStream(output);
396}
397
398bool MessageLite::SerializePartialToZeroCopyStream(
399 io::ZeroCopyOutputStream* output) const {
400 const size_t size = ByteSizeLong(); // Force size to be cached.
401 if (size > INT_MAX) {
402 GOOGLE_LOG(ERROR) << GetTypeName()
403 << " exceeded maximum protobuf size of 2GB: " << size;
404 return false;
405 }
406
407 uint8_t* target;
408 io::EpsCopyOutputStream stream(
409 output, io::CodedOutputStream::IsDefaultSerializationDeterministic(),
410 &target);
411 target = _InternalSerialize(ptr: target, stream: &stream);
412 stream.Trim(ptr: target);
413 if (stream.HadError()) return false;
414 return true;
415}
416
417bool MessageLite::SerializeToFileDescriptor(int file_descriptor) const {
418 io::FileOutputStream output(file_descriptor);
419 return SerializeToZeroCopyStream(output: &output) && output.Flush();
420}
421
422bool MessageLite::SerializePartialToFileDescriptor(int file_descriptor) const {
423 io::FileOutputStream output(file_descriptor);
424 return SerializePartialToZeroCopyStream(output: &output) && output.Flush();
425}
426
427bool MessageLite::SerializeToOstream(std::ostream* output) const {
428 {
429 io::OstreamOutputStream zero_copy_output(output);
430 if (!SerializeToZeroCopyStream(output: &zero_copy_output)) return false;
431 }
432 return output->good();
433}
434
435bool MessageLite::SerializePartialToOstream(std::ostream* output) const {
436 io::OstreamOutputStream zero_copy_output(output);
437 return SerializePartialToZeroCopyStream(output: &zero_copy_output);
438}
439
440bool MessageLite::AppendToString(std::string* output) const {
441 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage(action: "serialize", message: *this);
442 return AppendPartialToString(output);
443}
444
445bool MessageLite::AppendPartialToString(std::string* output) const {
446 size_t old_size = output->size();
447 size_t byte_size = ByteSizeLong();
448 if (byte_size > INT_MAX) {
449 GOOGLE_LOG(ERROR) << GetTypeName()
450 << " exceeded maximum protobuf size of 2GB: " << byte_size;
451 return false;
452 }
453
454 STLStringResizeUninitializedAmortized(s: output, new_size: old_size + byte_size);
455 uint8_t* start =
456 reinterpret_cast<uint8_t*>(io::mutable_string_data(s: output) + old_size);
457 SerializeToArrayImpl(msg: *this, target: start, size: byte_size);
458 return true;
459}
460
461bool MessageLite::SerializeToString(std::string* output) const {
462 output->clear();
463 return AppendToString(output);
464}
465
466bool MessageLite::SerializePartialToString(std::string* output) const {
467 output->clear();
468 return AppendPartialToString(output);
469}
470
471bool MessageLite::SerializeToArray(void* data, int size) const {
472 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage(action: "serialize", message: *this);
473 return SerializePartialToArray(data, size);
474}
475
476bool MessageLite::SerializePartialToArray(void* data, int size) const {
477 const size_t byte_size = ByteSizeLong();
478 if (byte_size > INT_MAX) {
479 GOOGLE_LOG(ERROR) << GetTypeName()
480 << " exceeded maximum protobuf size of 2GB: " << byte_size;
481 return false;
482 }
483 if (size < static_cast<int64_t>(byte_size)) return false;
484 uint8_t* start = reinterpret_cast<uint8_t*>(data);
485 SerializeToArrayImpl(msg: *this, target: start, size: byte_size);
486 return true;
487}
488
489std::string MessageLite::SerializeAsString() const {
490 // If the compiler implements the (Named) Return Value Optimization,
491 // the local variable 'output' will not actually reside on the stack
492 // of this function, but will be overlaid with the object that the
493 // caller supplied for the return value to be constructed in.
494 std::string output;
495 if (!AppendToString(output: &output)) output.clear();
496 return output;
497}
498
499std::string MessageLite::SerializePartialAsString() const {
500 std::string output;
501 if (!AppendPartialToString(output: &output)) output.clear();
502 return output;
503}
504
505
506namespace internal {
507
508MessageLite* NewFromPrototypeHelper(const MessageLite* prototype,
509 Arena* arena) {
510 return prototype->New(arena);
511}
512template <>
513void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
514 MessageLite* to) {
515 to->CheckTypeAndMergeFrom(other: from);
516}
517template <>
518void GenericTypeHandler<std::string>::Merge(const std::string& from,
519 std::string* to) {
520 *to = from;
521}
522
523// Non-inline implementations of InternalMetadata destructor
524// This is moved out of the header because the GOOGLE_DCHECK produces a lot of code.
525void InternalMetadata::CheckedDestruct() {
526 if (HasMessageOwnedArenaTag()) {
527 GOOGLE_DCHECK(!HasUnknownFieldsTag());
528 delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
529 }
530}
531
532// Non-inline variants of std::string specializations for
533// various InternalMetadata routines.
534template <>
535void InternalMetadata::DoClear<std::string>() {
536 mutable_unknown_fields<std::string>()->clear();
537}
538
539template <>
540void InternalMetadata::DoMergeFrom<std::string>(const std::string& other) {
541 mutable_unknown_fields<std::string>()->append(str: other);
542}
543
544template <>
545void InternalMetadata::DoSwap<std::string>(std::string* other) {
546 mutable_unknown_fields<std::string>()->swap(s&: *other);
547}
548
549} // namespace internal
550
551
552// ===================================================================
553// Shutdown support.
554
555namespace internal {
556
557struct ShutdownData {
558 ~ShutdownData() {
559 std::reverse(first: functions.begin(), last: functions.end());
560 for (auto pair : functions) pair.first(pair.second);
561 }
562
563 static ShutdownData* get() {
564 static auto* data = new ShutdownData;
565 return data;
566 }
567
568 std::vector<std::pair<void (*)(const void*), const void*>> functions;
569 Mutex mutex;
570};
571
572static void RunZeroArgFunc(const void* arg) {
573 void (*func)() = reinterpret_cast<void (*)()>(const_cast<void*>(arg));
574 func();
575}
576
577void OnShutdown(void (*func)()) {
578 OnShutdownRun(f: RunZeroArgFunc, arg: reinterpret_cast<void*>(func));
579}
580
581void OnShutdownRun(void (*f)(const void*), const void* arg) {
582 auto shutdown_data = ShutdownData::get();
583 MutexLock lock(&shutdown_data->mutex);
584 shutdown_data->functions.push_back(x: std::make_pair(x&: f, y&: arg));
585}
586
587} // namespace internal
588
589void ShutdownProtobufLibrary() {
590 // This function should be called only once, but accepts multiple calls.
591 static bool is_shutdown = false;
592 if (!is_shutdown) {
593 delete internal::ShutdownData::get();
594 is_shutdown = true;
595 }
596}
597
598
599} // namespace protobuf
600} // namespace google
601
602#include <google/protobuf/port_undef.inc>
603