@ -51,10 +51,6 @@ NSString *const GPBCodedInputStreamErrorDomain =
/ / int CodedInputStream : : default_recursion_limit_ = 100 ;
static const NSUInteger kDefaultRecursionLimit = 100 ;
/ / Bytes and Strings have a max size of 2 GB .
/ / https : / / protobuf . dev / programming - guides / encoding / #cheat - sheet
static const uint32_t kMaxFieldSize = 0 x7fffffff ;
static void RaiseException ( NSInteger code , NSString * reason ) {
NSDictionary * errorInfo = nil ;
if ( [ reason length ] ) {
@ -69,12 +65,24 @@ static void RaiseException(NSInteger code, NSString *reason) {
userInfo : exceptionInfo ] raise ] ;
}
static void CheckRecursionLimit ( GPBCodedInputStreamState * state ) {
GPB_INLINE void CheckRecursionLimit ( GPBCodedInputStreamState * state ) {
if ( state - > recursionDepth > = kDefaultRecursionLimit ) {
RaiseException ( GPBCodedInputStreamErrorRecursionDepthExceeded , nil ) ;
}
}
GPB_INLINE void CheckFieldSize ( uint64_t size ) {
/ / Bytes and Strings have a max size of 2 GB . And since messages are on the wire as bytes / length
/ / delimited , they also have a 2 GB size limit . The C + + does the same sort of enforcement ( see
/ / parse_context , delimited_message_util , message_lite , etc . ) .
/ / https : / / protobuf . dev / programming - guides / encoding / #cheat - sheet
if ( size > 0 x7fffffff ) {
/ / TODO ( thomasvl ) : Maybe a different error code for this , but adding one is a breaking
/ / change so reuse an existing one .
RaiseException ( GPBCodedInputStreamErrorInvalidSize , nil ) ;
}
}
static void CheckSize ( GPBCodedInputStreamState * state , size_t size ) {
size_t newSize = state - > bufferPos + size ;
if ( newSize > state - > bufferSize ) {
@ -228,11 +236,7 @@ int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) {
NSString * GPBCodedInputStreamReadRetainedString ( GPBCodedInputStreamState * state ) {
uint64_t size = GPBCodedInputStreamReadUInt64 ( state ) ;
if ( size > kMaxFieldSize ) {
/ / TODO ( thomasvl ) : Maybe a different error code for this , but adding one is a breaking change
/ / so reuse an existing one .
RaiseException ( GPBCodedInputStreamErrorInvalidSize , nil ) ;
}
CheckFieldSize ( size ) ;
NSUInteger ns_size = ( NSUInteger ) size ;
NSString * result ;
if ( size == 0 ) {
@ -257,11 +261,7 @@ NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state)
NSData * GPBCodedInputStreamReadRetainedBytes ( GPBCodedInputStreamState * state ) {
uint64_t size = GPBCodedInputStreamReadUInt64 ( state ) ;
if ( size > kMaxFieldSize ) {
/ / TODO ( thomasvl ) : Maybe a different error code for this , but adding one is a breaking change
/ / so reuse an existing one .
RaiseException ( GPBCodedInputStreamErrorInvalidSize , nil ) ;
}
CheckFieldSize ( size ) ;
NSUInteger ns_size = ( NSUInteger ) size ;
CheckSize ( state , size ) ;
NSData * result = [ [ NSData alloc ] initWithBytes : state - > bytes + state - > bufferPos length : ns_size ] ;
@ -271,11 +271,7 @@ NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
NSData * GPBCodedInputStreamReadRetainedBytesNoCopy ( GPBCodedInputStreamState * state ) {
uint64_t size = GPBCodedInputStreamReadUInt64 ( state ) ;
if ( size > kMaxFieldSize ) {
/ / TODO ( thomasvl ) : Maybe a different error code for this , but adding one is a breaking change
/ / so reuse an existing one .
RaiseException ( GPBCodedInputStreamErrorInvalidSize , nil ) ;
}
CheckFieldSize ( size ) ;
NSUInteger ns_size = ( NSUInteger ) size ;
CheckSize ( state , size ) ;
/ / Cast is safe because freeWhenDone is NO .
@ -362,9 +358,12 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, int32_t
case GPBWireFormatFixed64 :
SkipRawData ( & state_ , sizeof ( int64_t ) ) ;
return YES ;
case GPBWireFormatLengthDelimited :
SkipRawData ( & state_ , ReadRawVarint32 ( & state_ ) ) ;
case GPBWireFormatLengthDelimited : {
uint64_t size = GPBCodedInputStreamReadUInt64 ( & state_ ) ;
CheckFieldSize ( size ) ;
SkipRawData ( & state_ , size ) ;
return YES ;
}
case GPBWireFormatStartGroup :
[ self skipMessage ] ;
GPBCodedInputStreamCheckLastTagWas (
@ -463,7 +462,8 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, int32_t
- ( void ) readMessage : ( GPBMessage * ) message
extensionRegistry : ( id < GPBExtensionRegistry > ) extensionRegistry {
CheckRecursionLimit ( & state_ ) ;
int32_t length = ReadRawVarint32 ( & state_ ) ;
uint64_t length = GPBCodedInputStreamReadUInt64 ( & state_ ) ;
CheckFieldSize ( length ) ;
size_t oldLimit = GPBCodedInputStreamPushLimit ( & state_ , length ) ;
+ + state_ . recursionDepth ;
[ message mergeFromCodedInputStream : self extensionRegistry : extensionRegistry ] ;
@ -477,7 +477,8 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, int32_t
field : ( GPBFieldDescriptor * ) field
parentMessage : ( GPBMessage * ) parentMessage {
CheckRecursionLimit ( & state_ ) ;
int32_t length = ReadRawVarint32 ( & state_ ) ;
uint64_t length = GPBCodedInputStreamReadUInt64 ( & state_ ) ;
CheckFieldSize ( length ) ;
size_t oldLimit = GPBCodedInputStreamPushLimit ( & state_ , length ) ;
+ + state_ . recursionDepth ;
GPBDictionaryReadEntry ( mapDictionary , self , extensionRegistry , field , parentMessage ) ;