51
51
// int CodedInputStream::default_recursion_limit_ = 100;
52
52
static const NSUInteger kDefaultRecursionLimit = 100 ;
53
53
54
+ // Bytes and Strings have a max size of 2GB.
55
+ // https://protobuf.dev/programming-guides/encoding/#cheat-sheet
56
+ static const uint32_t kMaxFieldSize = 0x7fffffff ;
57
+
54
58
static void RaiseException (NSInteger code, NSString *reason) {
55
59
NSDictionary *errorInfo = nil ;
56
60
if ([reason length ]) {
@@ -223,14 +227,20 @@ int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) {
223
227
}
224
228
225
229
NSString *GPBCodedInputStreamReadRetainedString (GPBCodedInputStreamState *state) {
226
- int32_t size = ReadRawVarint32 (state);
230
+ uint64_t size = GPBCodedInputStreamReadUInt64 (state);
231
+ if (size > kMaxFieldSize ) {
232
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
233
+ // so reuse an existing one.
234
+ RaiseException (GPBCodedInputStreamErrorInvalidSize, nil );
235
+ }
236
+ NSUInteger ns_size = (NSUInteger )size;
227
237
NSString *result;
228
238
if (size == 0 ) {
229
239
result = @" " ;
230
240
} else {
231
241
CheckSize (state, size);
232
242
result = [[NSString alloc ] initWithBytes: &state->bytes[state->bufferPos]
233
- length: size
243
+ length: ns_size
234
244
encoding: NSUTF8StringEncoding];
235
245
state->bufferPos += size;
236
246
if (!result) {
@@ -246,21 +256,31 @@ int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) {
246
256
}
247
257
248
258
NSData *GPBCodedInputStreamReadRetainedBytes (GPBCodedInputStreamState *state) {
249
- int32_t size = ReadRawVarint32 (state);
250
- if (size < 0 ) return nil ;
259
+ uint64_t size = GPBCodedInputStreamReadUInt64 (state);
260
+ if (size > kMaxFieldSize ) {
261
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
262
+ // so reuse an existing one.
263
+ RaiseException (GPBCodedInputStreamErrorInvalidSize, nil );
264
+ }
265
+ NSUInteger ns_size = (NSUInteger )size;
251
266
CheckSize (state, size);
252
- NSData *result = [[NSData alloc ] initWithBytes: state->bytes + state->bufferPos length: size ];
267
+ NSData *result = [[NSData alloc ] initWithBytes: state->bytes + state->bufferPos length: ns_size ];
253
268
state->bufferPos += size;
254
269
return result;
255
270
}
256
271
257
272
NSData *GPBCodedInputStreamReadRetainedBytesNoCopy (GPBCodedInputStreamState *state) {
258
- int32_t size = ReadRawVarint32 (state);
259
- if (size < 0 ) return nil ;
273
+ uint64_t size = GPBCodedInputStreamReadUInt64 (state);
274
+ if (size > kMaxFieldSize ) {
275
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
276
+ // so reuse an existing one.
277
+ RaiseException (GPBCodedInputStreamErrorInvalidSize, nil );
278
+ }
279
+ NSUInteger ns_size = (NSUInteger )size;
260
280
CheckSize (state, size);
261
281
// Cast is safe because freeWhenDone is NO.
262
282
NSData *result = [[NSData alloc ] initWithBytesNoCopy: (void *)(state->bytes + state->bufferPos)
263
- length: size
283
+ length: ns_size
264
284
freeWhenDone: NO ];
265
285
state->bufferPos += size;
266
286
return result;
0 commit comments