diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m index acba71568..2b578dd54 100644 --- a/objectivec/GPBCodedInputStream.m +++ b/objectivec/GPBCodedInputStream.m @@ -227,7 +227,13 @@ int32_t GPBCodedInputStreamReadTag(GPBCodedInputStreamState *state) { state->lastTag = ReadRawVarint32(state); if (state->lastTag == 0) { // If we actually read zero, that's not a valid tag. - RaiseException(GPBCodedInputStreamErrorInvalidTag, @"Last tag can't be 0"); + RaiseException(GPBCodedInputStreamErrorInvalidTag, + @"A zero tag on the wire is invalid."); + } + // Tags have to include a valid wireformat, check that also. + if (!GPBWireFormatIsValidTag(state->lastTag)) { + RaiseException(GPBCodedInputStreamErrorInvalidTag, + @"Invalid wireformat in tag."); } return state->lastTag; } @@ -352,6 +358,7 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, } - (BOOL)skipField:(int32_t)tag { + NSAssert(GPBWireFormatIsValidTag(tag), @"Invalid tag"); switch (GPBWireFormatGetTagWireType(tag)) { case GPBWireFormatVarint: GPBCodedInputStreamReadInt32(&state_); @@ -374,8 +381,6 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, SkipRawData(&state_, sizeof(int32_t)); return YES; } - RaiseException(GPBCodedInputStreamErrorInvalidTag, nil); - return NO; } - (void)skipMessage { diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 7ab184c1f..b9566bdf4 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -2279,6 +2279,9 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( while (YES) { BOOL merged = NO; tag = GPBCodedInputStreamReadTag(state); + if (tag == 0) { + break; // Reached end. + } for (NSUInteger i = 0; i < numFields; ++i) { if (startingIndex >= numFields) startingIndex = 0; GPBFieldDescriptor *fieldDescriptor = fields[startingIndex]; @@ -2317,7 +2320,7 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( } } // for(i < numFields) - if (!merged) { + if (!merged && (tag != 0)) { // Primitive, repeated types can be packed on unpacked on the wire, and // are parsed either way. The above loop covered tag in the preferred // for, so this need to check the alternate form. diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m index af08556e6..9ba1d65c8 100644 --- a/objectivec/GPBUnknownFieldSet.m +++ b/objectivec/GPBUnknownFieldSet.m @@ -359,6 +359,7 @@ static void GPBUnknownFieldSetMergeUnknownFields(const void *key, } - (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input { + NSAssert(GPBWireFormatIsValidTag(tag), @"Got passed an invalid tag"); int32_t number = GPBWireFormatGetTagFieldNumber(tag); GPBCodedInputStreamState *state = &input->state_; switch (GPBWireFormatGetTagWireType(tag)) { diff --git a/objectivec/GPBWireFormat.h b/objectivec/GPBWireFormat.h index 29cf2f0b8..c5941a382 100644 --- a/objectivec/GPBWireFormat.h +++ b/objectivec/GPBWireFormat.h @@ -53,6 +53,7 @@ uint32_t GPBWireFormatMakeTag(uint32_t fieldNumber, GPBWireFormat wireType) __attribute__((const)); GPBWireFormat GPBWireFormatGetTagWireType(uint32_t tag) __attribute__((const)); uint32_t GPBWireFormatGetTagFieldNumber(uint32_t tag) __attribute__((const)); +BOOL GPBWireFormatIsValidTag(uint32_t tag) __attribute__((const)); GPBWireFormat GPBWireFormatForType(GPBDataType dataType, BOOL isPacked) __attribute__((const)); diff --git a/objectivec/GPBWireFormat.m b/objectivec/GPBWireFormat.m index 193235d6c..860a339f9 100644 --- a/objectivec/GPBWireFormat.m +++ b/objectivec/GPBWireFormat.m @@ -49,6 +49,13 @@ uint32_t GPBWireFormatGetTagFieldNumber(uint32_t tag) { return GPBLogicalRightShift32(tag, GPBWireFormatTagTypeBits); } +BOOL GPBWireFormatIsValidTag(uint32_t tag) { + uint32_t formatBits = (tag & GPBWireFormatTagTypeMask); + // The valid GPBWireFormat* values are 0-5, anything else is not a valid tag. + BOOL result = (formatBits <= 5); + return result; +} + GPBWireFormat GPBWireFormatForType(GPBDataType type, BOOL isPacked) { if (isPacked) { return GPBWireFormatLengthDelimited;