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