1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
8 #import "GPBCodedInputStream.h"
9 #import "GPBCodedInputStream_PackagePrivate.h"
11 #import "GPBDictionary.h"
12 #import "GPBDictionary_PackagePrivate.h"
13 #import "GPBMessage.h"
14 #import "GPBMessage_PackagePrivate.h"
15 #import "GPBUtilities.h"
16 #import "GPBUtilities_PackagePrivate.h"
17 #import "GPBWireFormat.h"
19 // TODO: Consider using on other functions to reduce bloat when
20 // some compiler optimizations are enabled.
21 #define GPB_NOINLINE __attribute__((noinline))
23 NSString *const GPBCodedInputStreamException = GPBNSStringifySymbol(GPBCodedInputStreamException);
25 NSString *const GPBCodedInputStreamUnderlyingErrorKey =
26 GPBNSStringifySymbol(GPBCodedInputStreamUnderlyingErrorKey);
28 NSString *const GPBCodedInputStreamErrorDomain =
29 GPBNSStringifySymbol(GPBCodedInputStreamErrorDomain);
32 // https://github.com/protocolbuffers/protobuf/blob/main/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L62
33 // private static final int DEFAULT_RECURSION_LIMIT = 100;
34 // https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/io/coded_stream.cc#L86
35 // int CodedInputStream::default_recursion_limit_ = 100;
36 static const NSUInteger kDefaultRecursionLimit = 100;
39 void GPBRaiseStreamError(NSInteger code, NSString *reason) {
40 NSDictionary *errorInfo = nil;
41 if ([reason length]) {
42 errorInfo = @{GPBErrorReasonKey : reason};
44 NSError *error = [NSError errorWithDomain:GPBCodedInputStreamErrorDomain
48 NSDictionary *exceptionInfo = @{GPBCodedInputStreamUnderlyingErrorKey : error};
49 [[NSException exceptionWithName:GPBCodedInputStreamException reason:reason
50 userInfo:exceptionInfo] raise];
53 GPB_INLINE void CheckRecursionLimit(GPBCodedInputStreamState *state) {
54 if (state->recursionDepth >= kDefaultRecursionLimit) {
55 GPBRaiseStreamError(GPBCodedInputStreamErrorRecursionDepthExceeded, nil);
59 GPB_INLINE void CheckFieldSize(uint64_t size) {
60 // Bytes and Strings have a max size of 2GB. And since messages are on the wire as bytes/length
61 // delimited, they also have a 2GB size limit. The C++ does the same sort of enforcement (see
62 // parse_context, delimited_message_util, message_lite, etc.).
63 // https://protobuf.dev/programming-guides/encoding/#cheat-sheet
64 if (size > 0x7fffffff) {
65 // TODO: Maybe a different error code for this, but adding one is a breaking
66 // change so reuse an existing one.
67 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidSize, nil);
71 static void CheckSize(GPBCodedInputStreamState *state, size_t size) {
72 size_t newSize = state->bufferPos + size;
73 if (newSize > state->bufferSize) {
74 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidSize, nil);
76 if (newSize > state->currentLimit) {
77 // Fast forward to end of currentLimit;
78 state->bufferPos = state->currentLimit;
79 GPBRaiseStreamError(GPBCodedInputStreamErrorSubsectionLimitReached, nil);
83 static int8_t ReadRawByte(GPBCodedInputStreamState *state) {
84 CheckSize(state, sizeof(int8_t));
85 return ((int8_t *)state->bytes)[state->bufferPos++];
88 static int32_t ReadRawLittleEndian32(GPBCodedInputStreamState *state) {
89 CheckSize(state, sizeof(int32_t));
90 // Not using OSReadLittleInt32 because it has undocumented dependency
91 // on reads being aligned.
93 memcpy(&value, state->bytes + state->bufferPos, sizeof(int32_t));
94 value = OSSwapLittleToHostInt32(value);
95 state->bufferPos += sizeof(int32_t);
99 static int64_t ReadRawLittleEndian64(GPBCodedInputStreamState *state) {
100 CheckSize(state, sizeof(int64_t));
101 // Not using OSReadLittleInt64 because it has undocumented dependency
102 // on reads being aligned.
104 memcpy(&value, state->bytes + state->bufferPos, sizeof(int64_t));
105 value = OSSwapLittleToHostInt64(value);
106 state->bufferPos += sizeof(int64_t);
110 static int64_t ReadRawVarint64(GPBCodedInputStreamState *state) {
114 int8_t b = ReadRawByte(state);
115 result |= (int64_t)((uint64_t)(b & 0x7F) << shift);
116 if ((b & 0x80) == 0) {
121 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidVarInt, @"Invalid VarInt64");
125 static int32_t ReadRawVarint32(GPBCodedInputStreamState *state) {
126 return (int32_t)ReadRawVarint64(state);
129 static void SkipRawData(GPBCodedInputStreamState *state, size_t size) {
130 CheckSize(state, size);
131 state->bufferPos += size;
134 double GPBCodedInputStreamReadDouble(GPBCodedInputStreamState *state) {
135 int64_t value = ReadRawLittleEndian64(state);
136 return GPBConvertInt64ToDouble(value);
139 float GPBCodedInputStreamReadFloat(GPBCodedInputStreamState *state) {
140 int32_t value = ReadRawLittleEndian32(state);
141 return GPBConvertInt32ToFloat(value);
144 uint64_t GPBCodedInputStreamReadUInt64(GPBCodedInputStreamState *state) {
145 uint64_t value = ReadRawVarint64(state);
149 uint32_t GPBCodedInputStreamReadUInt32(GPBCodedInputStreamState *state) {
150 uint32_t value = ReadRawVarint32(state);
154 int64_t GPBCodedInputStreamReadInt64(GPBCodedInputStreamState *state) {
155 int64_t value = ReadRawVarint64(state);
159 int32_t GPBCodedInputStreamReadInt32(GPBCodedInputStreamState *state) {
160 int32_t value = ReadRawVarint32(state);
164 uint64_t GPBCodedInputStreamReadFixed64(GPBCodedInputStreamState *state) {
165 uint64_t value = ReadRawLittleEndian64(state);
169 uint32_t GPBCodedInputStreamReadFixed32(GPBCodedInputStreamState *state) {
170 uint32_t value = ReadRawLittleEndian32(state);
174 int32_t GPBCodedInputStreamReadEnum(GPBCodedInputStreamState *state) {
175 int32_t value = ReadRawVarint32(state);
179 int32_t GPBCodedInputStreamReadSFixed32(GPBCodedInputStreamState *state) {
180 int32_t value = ReadRawLittleEndian32(state);
184 int64_t GPBCodedInputStreamReadSFixed64(GPBCodedInputStreamState *state) {
185 int64_t value = ReadRawLittleEndian64(state);
189 int32_t GPBCodedInputStreamReadSInt32(GPBCodedInputStreamState *state) {
190 int32_t value = GPBDecodeZigZag32(ReadRawVarint32(state));
194 int64_t GPBCodedInputStreamReadSInt64(GPBCodedInputStreamState *state) {
195 int64_t value = GPBDecodeZigZag64(ReadRawVarint64(state));
199 BOOL GPBCodedInputStreamReadBool(GPBCodedInputStreamState *state) {
200 return ReadRawVarint64(state) != 0;
203 int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) {
204 if (GPBCodedInputStreamIsAtEnd(state)) {
209 state->lastTag = ReadRawVarint32(state);
210 // Tags have to include a valid wireformat.
211 if (!GPBWireFormatIsValidTag(state->lastTag)) {
212 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidTag, @"Invalid wireformat in tag.");
214 // Zero is not a valid field number.
215 if (GPBWireFormatGetTagFieldNumber(state->lastTag) == 0) {
216 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidTag,
217 @"A zero field number on the wire is invalid.");
219 return state->lastTag;
222 NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state) {
223 uint64_t size = GPBCodedInputStreamReadUInt64(state);
224 CheckFieldSize(size);
225 NSUInteger ns_size = (NSUInteger)size;
230 size_t size2 = (size_t)size; // Cast safe on 32bit because of CheckFieldSize() above.
231 CheckSize(state, size2);
232 result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
234 encoding:NSUTF8StringEncoding];
235 state->bufferPos += size;
238 // https://developers.google.com/protocol-buffers/docs/proto#scalar
239 NSLog(@"UTF-8 failure, is some field type 'string' when it should be "
242 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidUTF8, nil);
248 NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
249 uint64_t size = GPBCodedInputStreamReadUInt64(state);
250 CheckFieldSize(size);
251 size_t size2 = (size_t)size; // Cast safe on 32bit because of CheckFieldSize() above.
252 CheckSize(state, size2);
253 NSUInteger ns_size = (NSUInteger)size;
254 NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:ns_size];
255 state->bufferPos += size;
259 NSData *GPBCodedInputStreamReadRetainedBytesNoCopy(GPBCodedInputStreamState *state) {
260 uint64_t size = GPBCodedInputStreamReadUInt64(state);
261 CheckFieldSize(size);
262 size_t size2 = (size_t)size; // Cast safe on 32bit because of CheckFieldSize() above.
263 CheckSize(state, size2);
264 NSUInteger ns_size = (NSUInteger)size;
265 // Cast is safe because freeWhenDone is NO.
266 NSData *result = [[NSData alloc] initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos)
269 state->bufferPos += size;
273 static void SkipToEndGroupInternal(GPBCodedInputStreamState *state, uint32_t endGroupTag) {
274 CheckRecursionLimit(state);
275 ++state->recursionDepth;
277 uint32_t tag = GPBCodedInputStreamReadTag(state);
278 if (tag == endGroupTag || tag == 0) {
279 GPBCodedInputStreamCheckLastTagWas(state, endGroupTag); // Will fail for end of input.
280 --state->recursionDepth;
283 switch (GPBWireFormatGetTagWireType(tag)) {
284 case GPBWireFormatVarint:
285 (void)ReadRawVarint64(state);
287 case GPBWireFormatFixed64:
288 SkipRawData(state, sizeof(uint64_t));
290 case GPBWireFormatLengthDelimited: {
291 uint64_t size = ReadRawVarint64(state);
292 CheckFieldSize(size);
293 size_t size2 = (size_t)size; // Cast safe on 32bit because of CheckFieldSize() above.
294 SkipRawData(state, size2);
297 case GPBWireFormatStartGroup:
298 SkipToEndGroupInternal(state, GPBWireFormatMakeTag(GPBWireFormatGetTagFieldNumber(tag),
299 GPBWireFormatEndGroup));
301 case GPBWireFormatEndGroup:
302 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidTag, @"Unmatched end group");
304 case GPBWireFormatFixed32:
305 SkipRawData(state, sizeof(uint32_t));
311 // This doesn't include the start group, but it collects all bytes until the end group including
312 // the end group tag.
313 NSData *GPBCodedInputStreamReadRetainedBytesToEndGroupNoCopy(GPBCodedInputStreamState *state,
314 int32_t fieldNumber) {
315 // Better have just read the start of the group.
316 GPBCodedInputStreamCheckLastTagWas(state,
317 GPBWireFormatMakeTag(fieldNumber, GPBWireFormatStartGroup));
318 const uint8_t *start = state->bytes + state->bufferPos;
319 SkipToEndGroupInternal(state, GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup));
320 // This will be after the end group tag.
321 const uint8_t *end = state->bytes + state->bufferPos;
322 return [[NSData alloc] initWithBytesNoCopy:(void *)start
323 length:(NSUInteger)(end - start)
327 size_t GPBCodedInputStreamPushLimit(GPBCodedInputStreamState *state, size_t byteLimit) {
328 byteLimit += state->bufferPos;
329 size_t oldLimit = state->currentLimit;
330 if (byteLimit > oldLimit) {
331 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidSubsectionLimit, nil);
333 state->currentLimit = byteLimit;
337 void GPBCodedInputStreamPopLimit(GPBCodedInputStreamState *state, size_t oldLimit) {
338 state->currentLimit = oldLimit;
341 size_t GPBCodedInputStreamBytesUntilLimit(GPBCodedInputStreamState *state) {
342 return state->currentLimit - state->bufferPos;
345 BOOL GPBCodedInputStreamIsAtEnd(GPBCodedInputStreamState *state) {
346 return (state->bufferPos == state->bufferSize) || (state->bufferPos == state->currentLimit);
349 void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, int32_t value) {
350 if (state->lastTag != value) {
351 GPBRaiseStreamError(GPBCodedInputStreamErrorInvalidTag, @"Unexpected tag read");
355 @implementation GPBCodedInputStream
357 + (instancetype)streamWithData:(NSData *)data {
358 return [[[self alloc] initWithData:data] autorelease];
361 - (instancetype)initWithData:(NSData *)data {
362 if ((self = [super init])) {
364 NSCAssert([self class] == [GPBCodedInputStream class],
365 @"Subclassing of GPBCodedInputStream is not allowed.");
367 buffer_ = [data retain];
368 state_.bytes = (const uint8_t *)[data bytes];
369 state_.bufferSize = [data length];
370 state_.currentLimit = state_.bufferSize;
380 // Direct access is use for speed, to avoid even internally declaring things
381 // read/write, etc. The warning is enabled in the project to ensure code calling
382 // protos can turn on -Wdirect-ivar-access without issues.
383 #pragma clang diagnostic push
384 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
387 return GPBCodedInputStreamReadTag(&state_);
390 - (void)checkLastTagWas:(int32_t)value {
391 GPBCodedInputStreamCheckLastTagWas(&state_, value);
394 - (BOOL)skipField:(int32_t)tag {
395 NSAssert(GPBWireFormatIsValidTag(tag), @"Invalid tag");
396 switch (GPBWireFormatGetTagWireType(tag)) {
397 case GPBWireFormatVarint:
398 GPBCodedInputStreamReadInt32(&state_);
400 case GPBWireFormatFixed64:
401 SkipRawData(&state_, sizeof(int64_t));
403 case GPBWireFormatLengthDelimited: {
404 uint64_t size = GPBCodedInputStreamReadUInt64(&state_);
405 CheckFieldSize(size);
406 size_t size2 = (size_t)size; // Cast safe on 32bit because of CheckFieldSize() above.
407 SkipRawData(&state_, size2);
410 case GPBWireFormatStartGroup:
412 GPBCodedInputStreamCheckLastTagWas(
414 GPBWireFormatMakeTag(GPBWireFormatGetTagFieldNumber(tag), GPBWireFormatEndGroup));
416 case GPBWireFormatEndGroup:
418 case GPBWireFormatFixed32:
419 SkipRawData(&state_, sizeof(int32_t));
424 - (void)skipMessage {
426 int32_t tag = GPBCodedInputStreamReadTag(&state_);
427 if (tag == 0 || ![self skipField:tag]) {
434 return GPBCodedInputStreamIsAtEnd(&state_);
438 return state_.bufferPos;
441 - (size_t)pushLimit:(size_t)byteLimit {
442 return GPBCodedInputStreamPushLimit(&state_, byteLimit);
445 - (void)popLimit:(size_t)oldLimit {
446 GPBCodedInputStreamPopLimit(&state_, oldLimit);
449 - (size_t)bytesUntilLimit {
450 return GPBCodedInputStreamBytesUntilLimit(&state_);
453 - (double)readDouble {
454 return GPBCodedInputStreamReadDouble(&state_);
458 return GPBCodedInputStreamReadFloat(&state_);
461 - (uint64_t)readUInt64 {
462 return GPBCodedInputStreamReadUInt64(&state_);
465 - (int64_t)readInt64 {
466 return GPBCodedInputStreamReadInt64(&state_);
469 - (int32_t)readInt32 {
470 return GPBCodedInputStreamReadInt32(&state_);
473 - (uint64_t)readFixed64 {
474 return GPBCodedInputStreamReadFixed64(&state_);
477 - (uint32_t)readFixed32 {
478 return GPBCodedInputStreamReadFixed32(&state_);
482 return GPBCodedInputStreamReadBool(&state_);
485 - (NSString *)readString {
486 return [GPBCodedInputStreamReadRetainedString(&state_) autorelease];
489 - (void)readGroup:(int32_t)fieldNumber
490 message:(GPBMessage *)message
491 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
492 CheckRecursionLimit(&state_);
493 ++state_.recursionDepth;
494 [message mergeFromCodedInputStream:self
495 extensionRegistry:extensionRegistry
496 endingTag:GPBWireFormatMakeTag(fieldNumber, GPBWireFormatEndGroup)];
497 --state_.recursionDepth;
500 - (void)readMessage:(GPBMessage *)message
501 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
502 CheckRecursionLimit(&state_);
503 uint64_t length = GPBCodedInputStreamReadUInt64(&state_);
504 CheckFieldSize(length);
505 size_t length2 = (size_t)length; // Cast safe on 32bit because of CheckFieldSize() above.
506 size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length2);
507 ++state_.recursionDepth;
508 [message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry endingTag:0];
509 --state_.recursionDepth;
510 GPBCodedInputStreamPopLimit(&state_, oldLimit);
513 - (void)readMapEntry:(id)mapDictionary
514 extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
515 field:(GPBFieldDescriptor *)field
516 parentMessage:(GPBMessage *)parentMessage {
517 CheckRecursionLimit(&state_);
518 uint64_t length = GPBCodedInputStreamReadUInt64(&state_);
519 CheckFieldSize(length);
520 size_t length2 = (size_t)length; // Cast safe on 32bit because of CheckFieldSize() above.
521 size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length2);
522 ++state_.recursionDepth;
523 GPBDictionaryReadEntry(mapDictionary, self, extensionRegistry, field, parentMessage);
524 GPBCodedInputStreamCheckLastTagWas(&state_, 0);
525 --state_.recursionDepth;
526 GPBCodedInputStreamPopLimit(&state_, oldLimit);
529 - (NSData *)readBytes {
530 return [GPBCodedInputStreamReadRetainedBytes(&state_) autorelease];
533 - (uint32_t)readUInt32 {
534 return GPBCodedInputStreamReadUInt32(&state_);
537 - (int32_t)readEnum {
538 return GPBCodedInputStreamReadEnum(&state_);
541 - (int32_t)readSFixed32 {
542 return GPBCodedInputStreamReadSFixed32(&state_);
545 - (int64_t)readSFixed64 {
546 return GPBCodedInputStreamReadSFixed64(&state_);
549 - (int32_t)readSInt32 {
550 return GPBCodedInputStreamReadSInt32(&state_);
553 - (int64_t)readSInt64 {
554 return GPBCodedInputStreamReadSInt64(&state_);
557 #pragma clang diagnostic pop