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 <climits>
37
38 #include <google/protobuf/arena.h>
39 #include <google/protobuf/generated_message_util.h>
40 #include <google/protobuf/message_lite.h>
41 #include <google/protobuf/repeated_field.h>
42 #include <string>
43 #include <google/protobuf/stubs/logging.h>
44 #include <google/protobuf/stubs/common.h>
45 #include <google/protobuf/io/coded_stream.h>
46 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
47 #include <google/protobuf/stubs/stl_util.h>
48
49 namespace google {
50 namespace protobuf {
51
InitializationErrorString() const52 string MessageLite::InitializationErrorString() const {
53 return "(cannot determine missing fields for lite message)";
54 }
55
56 namespace {
57
58 // When serializing, we first compute the byte size, then serialize the message.
59 // If serialization produces a different number of bytes than expected, we
60 // call this function, which crashes. The problem could be due to a bug in the
61 // protobuf implementation but is more likely caused by concurrent modification
62 // of the message. This function attempts to distinguish between the two and
63 // provide a useful error message.
ByteSizeConsistencyError(size_t byte_size_before_serialization,size_t byte_size_after_serialization,size_t bytes_produced_by_serialization,const MessageLite & message)64 void ByteSizeConsistencyError(size_t byte_size_before_serialization,
65 size_t byte_size_after_serialization,
66 size_t bytes_produced_by_serialization,
67 const MessageLite& message) {
68 GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
69 << message.GetTypeName()
70 << " was modified concurrently during serialization.";
71 GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
72 << "Byte size calculation and serialization were inconsistent. This "
73 "may indicate a bug in protocol buffers or it may be caused by "
74 "concurrent modification of " << message.GetTypeName() << ".";
75 GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
76 }
77
InitializationErrorMessage(const char * action,const MessageLite & message)78 string InitializationErrorMessage(const char* action,
79 const MessageLite& message) {
80 // Note: We want to avoid depending on strutil in the lite library, otherwise
81 // we'd use:
82 //
83 // return strings::Substitute(
84 // "Can't $0 message of type \"$1\" because it is missing required "
85 // "fields: $2",
86 // action, message.GetTypeName(),
87 // message.InitializationErrorString());
88
89 string result;
90 result += "Can't ";
91 result += action;
92 result += " message of type \"";
93 result += message.GetTypeName();
94 result += "\" because it is missing required fields: ";
95 result += message.InitializationErrorString();
96 return result;
97 }
98
99 // Several of the Parse methods below just do one thing and then call another
100 // method. In a naive implementation, we might have ParseFromString() call
101 // ParseFromArray() which would call ParseFromZeroCopyStream() which would call
102 // ParseFromCodedStream() which would call MergeFromCodedStream() which would
103 // call MergePartialFromCodedStream(). However, when parsing very small
104 // messages, every function call introduces significant overhead. To avoid
105 // this without reproducing code, we use these forced-inline helpers.
106 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineMergeFromCodedStream(
107 io::CodedInputStream* input, MessageLite* message);
108 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromCodedStream(
109 io::CodedInputStream* input, MessageLite* message);
110 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromCodedStream(
111 io::CodedInputStream* input, MessageLite* message);
112 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromArray(
113 const void* data, int size, MessageLite* message);
114 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromArray(
115 const void* data, int size, MessageLite* message);
116
InlineMergeFromCodedStream(io::CodedInputStream * input,MessageLite * message)117 inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
118 MessageLite* message) {
119 if (!message->MergePartialFromCodedStream(input)) return false;
120 if (!message->IsInitialized()) {
121 GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
122 return false;
123 }
124 return true;
125 }
126
InlineParseFromCodedStream(io::CodedInputStream * input,MessageLite * message)127 inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
128 MessageLite* message) {
129 message->Clear();
130 return InlineMergeFromCodedStream(input, message);
131 }
132
InlineParsePartialFromCodedStream(io::CodedInputStream * input,MessageLite * message)133 inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
134 MessageLite* message) {
135 message->Clear();
136 return message->MergePartialFromCodedStream(input);
137 }
138
InlineParseFromArray(const void * data,int size,MessageLite * message)139 inline bool InlineParseFromArray(
140 const void* data, int size, MessageLite* message) {
141 io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
142 return InlineParseFromCodedStream(&input, message) &&
143 input.ConsumedEntireMessage();
144 }
145
InlineParsePartialFromArray(const void * data,int size,MessageLite * message)146 inline bool InlineParsePartialFromArray(
147 const void* data, int size, MessageLite* message) {
148 io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
149 return InlineParsePartialFromCodedStream(&input, message) &&
150 input.ConsumedEntireMessage();
151 }
152
153 } // namespace
154
155
New(::google::protobuf::Arena * arena) const156 MessageLite* MessageLite::New(::google::protobuf::Arena* arena) const {
157 MessageLite* message = New();
158 if (arena != NULL) {
159 arena->Own(message);
160 }
161 return message;
162 }
163
MergeFromCodedStream(io::CodedInputStream * input)164 bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
165 return InlineMergeFromCodedStream(input, this);
166 }
167
ParseFromCodedStream(io::CodedInputStream * input)168 bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
169 return InlineParseFromCodedStream(input, this);
170 }
171
ParsePartialFromCodedStream(io::CodedInputStream * input)172 bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
173 return InlineParsePartialFromCodedStream(input, this);
174 }
175
ParseFromZeroCopyStream(io::ZeroCopyInputStream * input)176 bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
177 io::CodedInputStream decoder(input);
178 return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
179 }
180
ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream * input)181 bool MessageLite::ParsePartialFromZeroCopyStream(
182 io::ZeroCopyInputStream* input) {
183 io::CodedInputStream decoder(input);
184 return ParsePartialFromCodedStream(&decoder) &&
185 decoder.ConsumedEntireMessage();
186 }
187
ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream * input,int size)188 bool MessageLite::ParseFromBoundedZeroCopyStream(
189 io::ZeroCopyInputStream* input, int size) {
190 io::CodedInputStream decoder(input);
191 decoder.PushLimit(size);
192 return ParseFromCodedStream(&decoder) &&
193 decoder.ConsumedEntireMessage() &&
194 decoder.BytesUntilLimit() == 0;
195 }
196
ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream * input,int size)197 bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
198 io::ZeroCopyInputStream* input, int size) {
199 io::CodedInputStream decoder(input);
200 decoder.PushLimit(size);
201 return ParsePartialFromCodedStream(&decoder) &&
202 decoder.ConsumedEntireMessage() &&
203 decoder.BytesUntilLimit() == 0;
204 }
205
ParseFromString(const string & data)206 bool MessageLite::ParseFromString(const string& data) {
207 return InlineParseFromArray(data.data(), data.size(), this);
208 }
209
ParsePartialFromString(const string & data)210 bool MessageLite::ParsePartialFromString(const string& data) {
211 return InlineParsePartialFromArray(data.data(), data.size(), this);
212 }
213
ParseFromArray(const void * data,int size)214 bool MessageLite::ParseFromArray(const void* data, int size) {
215 return InlineParseFromArray(data, size, this);
216 }
217
ParsePartialFromArray(const void * data,int size)218 bool MessageLite::ParsePartialFromArray(const void* data, int size) {
219 return InlineParsePartialFromArray(data, size, this);
220 }
221
222
223 // ===================================================================
224
SerializeWithCachedSizesToArray(uint8 * target) const225 uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
226 return InternalSerializeWithCachedSizesToArray(
227 io::CodedOutputStream::IsDefaultSerializationDeterministic(), target);
228 }
229
SerializeToCodedStream(io::CodedOutputStream * output) const230 bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
231 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
232 return SerializePartialToCodedStream(output);
233 }
234
SerializePartialToCodedStream(io::CodedOutputStream * output) const235 bool MessageLite::SerializePartialToCodedStream(
236 io::CodedOutputStream* output) const {
237 const size_t size = ByteSizeLong(); // Force size to be cached.
238 if (size > INT_MAX) {
239 GOOGLE_LOG(ERROR) << "Exceeded maximum protobuf size of 2GB: " << size;
240 return false;
241 }
242
243 uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
244 if (buffer != NULL) {
245 uint8* end = InternalSerializeWithCachedSizesToArray(
246 output->IsSerializationDeterministic(), buffer);
247 if (end - buffer != size) {
248 ByteSizeConsistencyError(size, ByteSizeLong(), end - buffer, *this);
249 }
250 return true;
251 } else {
252 int original_byte_count = output->ByteCount();
253 SerializeWithCachedSizes(output);
254 if (output->HadError()) {
255 return false;
256 }
257 int final_byte_count = output->ByteCount();
258
259 if (final_byte_count - original_byte_count != size) {
260 ByteSizeConsistencyError(size, ByteSizeLong(),
261 final_byte_count - original_byte_count, *this);
262 }
263
264 return true;
265 }
266 }
267
SerializeToZeroCopyStream(io::ZeroCopyOutputStream * output) const268 bool MessageLite::SerializeToZeroCopyStream(
269 io::ZeroCopyOutputStream* output) const {
270 io::CodedOutputStream encoder(output);
271 return SerializeToCodedStream(&encoder);
272 }
273
SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream * output) const274 bool MessageLite::SerializePartialToZeroCopyStream(
275 io::ZeroCopyOutputStream* output) const {
276 io::CodedOutputStream encoder(output);
277 return SerializePartialToCodedStream(&encoder);
278 }
279
AppendToString(string * output) const280 bool MessageLite::AppendToString(string* output) const {
281 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
282 return AppendPartialToString(output);
283 }
284
AppendPartialToString(string * output) const285 bool MessageLite::AppendPartialToString(string* output) const {
286 size_t old_size = output->size();
287 size_t byte_size = ByteSizeLong();
288 if (byte_size > INT_MAX) {
289 GOOGLE_LOG(ERROR) << "Exceeded maximum protobuf size of 2GB: " << byte_size;
290 return false;
291 }
292
293 STLStringResizeUninitialized(output, old_size + byte_size);
294 uint8* start =
295 reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
296 uint8* end = SerializeWithCachedSizesToArray(start);
297 if (end - start != byte_size) {
298 ByteSizeConsistencyError(byte_size, ByteSizeLong(), end - start, *this);
299 }
300 return true;
301 }
302
SerializeToString(string * output) const303 bool MessageLite::SerializeToString(string* output) const {
304 output->clear();
305 return AppendToString(output);
306 }
307
SerializePartialToString(string * output) const308 bool MessageLite::SerializePartialToString(string* output) const {
309 output->clear();
310 return AppendPartialToString(output);
311 }
312
SerializeToArray(void * data,int size) const313 bool MessageLite::SerializeToArray(void* data, int size) const {
314 GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
315 return SerializePartialToArray(data, size);
316 }
317
SerializePartialToArray(void * data,int size) const318 bool MessageLite::SerializePartialToArray(void* data, int size) const {
319 int byte_size = ByteSizeLong();
320 if (size < byte_size) return false;
321 uint8* start = reinterpret_cast<uint8*>(data);
322 uint8* end = SerializeWithCachedSizesToArray(start);
323 if (end - start != byte_size) {
324 ByteSizeConsistencyError(byte_size, ByteSizeLong(), end - start, *this);
325 }
326 return true;
327 }
328
SerializeAsString() const329 string MessageLite::SerializeAsString() const {
330 // If the compiler implements the (Named) Return Value Optimization,
331 // the local variable 'output' will not actually reside on the stack
332 // of this function, but will be overlaid with the object that the
333 // caller supplied for the return value to be constructed in.
334 string output;
335 if (!AppendToString(&output))
336 output.clear();
337 return output;
338 }
339
SerializePartialAsString() const340 string MessageLite::SerializePartialAsString() const {
341 string output;
342 if (!AppendPartialToString(&output))
343 output.clear();
344 return output;
345 }
346
SerializeWithCachedSizes(io::CodedOutputStream * output) const347 void MessageLite::SerializeWithCachedSizes(io::CodedOutputStream* output) const
348 {
349 GOOGLE_DCHECK(InternalGetTable());
350 internal::TableSerialize(*this, static_cast<const internal::SerializationTable*>(InternalGetTable()), output);
351 }
352
353 // The table driven code optimizes the case that the CodedOutputStream buffer
354 // is large enough to serialize into it directly.
355 // If the proto is optimized for speed, this method will be overridden by
356 // generated code for maximum speed. If the proto is optimized for size or
357 // is lite, then we need to specialize this to avoid infinite recursion.
InternalSerializeWithCachedSizesToArray(bool deterministic,uint8 * target) const358 uint8* MessageLite::InternalSerializeWithCachedSizesToArray(bool deterministic,
359 uint8* target) const {
360 const internal::SerializationTable* table =
361 static_cast<const internal::SerializationTable*>(InternalGetTable());
362 if (table == NULL) {
363 // We only optimize this when using optimize_for = SPEED. In other cases
364 // we just use the CodedOutputStream path.
365 int size = GetCachedSize();
366 io::ArrayOutputStream out(target, size);
367 io::CodedOutputStream coded_out(&out);
368 coded_out.SetSerializationDeterministic(deterministic);
369 SerializeWithCachedSizes(&coded_out);
370 GOOGLE_CHECK(!coded_out.HadError());
371 return target + size;
372 } else {
373 return internal::TableSerializeToArray(*this, table, deterministic, target);
374 }
375 }
376
377 namespace internal {
378 template<>
NewFromPrototype(const MessageLite * prototype,google::protobuf::Arena * arena)379 MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
380 const MessageLite* prototype, google::protobuf::Arena* arena) {
381 return prototype->New(arena);
382 }
383 template <>
Merge(const MessageLite & from,MessageLite * to)384 void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
385 MessageLite* to) {
386 to->CheckTypeAndMergeFrom(from);
387 }
388 template<>
Merge(const string & from,string * to)389 void GenericTypeHandler<string>::Merge(const string& from,
390 string* to) {
391 *to = from;
392 }
393
394 bool proto3_preserve_unknown_ = false;
SetProto3PreserveUnknownsDefault(bool preserve)395 void SetProto3PreserveUnknownsDefault(bool preserve) {
396 proto3_preserve_unknown_ = preserve;
397 }
398
399
400 } // namespace internal
401
402 } // namespace protobuf
403 } // namespace google
404