From 1e0338b2ba720243766cbda76b27bcf010aa1fa7 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Tue, 7 Nov 2023 09:31:49 -0800 Subject: [PATCH] [ObjC] Ensure `-[GPBMessage writeToOutputStream:]` still throws exception on flush failure This restores the behavior of `-[GPBMessage writeToOutputStream:]` throwing an exception if the underlying `GPBCodedOutputStream` failed to flush. `GPBDictionary` and `GPBUnknownFieldSet` could also have theoretically thrown exceptions from just about any method (although not for disk I/O reasons), so this also restores that functionality by explicitly flushing before deallocating the `GPBCodedOutputStream`. PiperOrigin-RevId: 580207004 --- objectivec/GPBDictionary.m | 7 +++++++ objectivec/GPBMessage.m | 3 +++ objectivec/GPBUnknownFieldSet.m | 1 + objectivec/Tests/GPBMessageTests.m | 13 +++++++++++++ 4 files changed, 24 insertions(+) diff --git a/objectivec/GPBDictionary.m b/objectivec/GPBDictionary.m index 4d7c08c1ee..a07a419f8b 100644 --- a/objectivec/GPBDictionary.m +++ b/objectivec/GPBDictionary.m @@ -1044,6 +1044,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, //% GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; //% WriteDict##KEY_NAME##Field(outputStream, key->value##KEY_NAME, kMapKeyFieldNumber, keyDataType); //% WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); +//% [outputStream flush]; //% [outputStream release]; //% return data; //%} @@ -2788,6 +2789,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; WriteDictUInt32Field(outputStream, key->valueUInt32, kMapKeyFieldNumber, keyDataType); WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); + [outputStream flush]; [outputStream release]; return data; } @@ -4518,6 +4520,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; WriteDictInt32Field(outputStream, key->valueInt32, kMapKeyFieldNumber, keyDataType); WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); + [outputStream flush]; [outputStream release]; return data; } @@ -6248,6 +6251,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; WriteDictUInt64Field(outputStream, key->valueUInt64, kMapKeyFieldNumber, keyDataType); WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); + [outputStream flush]; [outputStream release]; return data; } @@ -7978,6 +7982,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; WriteDictInt64Field(outputStream, key->valueInt64, kMapKeyFieldNumber, keyDataType); WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); + [outputStream flush]; [outputStream release]; return data; } @@ -9768,6 +9773,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; WriteDictStringField(outputStream, key->valueString, kMapKeyFieldNumber, keyDataType); WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); + [outputStream flush]; [outputStream release]; return data; } @@ -11741,6 +11747,7 @@ void GPBDictionaryReadEntry(id mapDictionary, GPBCodedInputStream *stream, GPBCodedOutputStream *outputStream = [[GPBCodedOutputStream alloc] initWithData:data]; WriteDictBoolField(outputStream, key->valueBool, kMapKeyFieldNumber, keyDataType); WriteDictEnumField(outputStream, value, kMapValueFieldNumber, GPBDataTypeEnum); + [outputStream flush]; [outputStream release]; return data; } diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 6124b70814..e2436a226a 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -1343,6 +1343,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithData:data]; @try { [self writeToCodedOutputStream:stream]; + [stream flush]; } @catch (NSException *exception) { // This really shouldn't happen. Normally, this could mean there was a bug in the library and it // failed to match between computing the size and writing out the bytes. However, the more @@ -1393,6 +1394,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithOutputStream:output]; @try { [self writeToCodedOutputStream:stream]; + [stream flush]; size_t bytesWritten = [stream bytesWritten]; if (bytesWritten > kMaximumMessageSize) { [NSException raise:GPBMessageExceptionMessageTooLarge @@ -1436,6 +1438,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { GPBCodedOutputStream *codedOutput = [[GPBCodedOutputStream alloc] initWithOutputStream:output]; @try { [self writeDelimitedToCodedOutputStream:codedOutput]; + [codedOutput flush]; } @finally { [codedOutput release]; } diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m index a68b62c841..768734070d 100644 --- a/objectivec/GPBUnknownFieldSet.m +++ b/objectivec/GPBUnknownFieldSet.m @@ -207,6 +207,7 @@ static void GPBUnknownFieldSetSerializedSizeAsMessageSet(__unused const void *ke NSMutableData *data = [NSMutableData dataWithLength:self.serializedSize]; GPBCodedOutputStream *output = [[GPBCodedOutputStream alloc] initWithData:data]; [self writeToCodedOutputStream:output]; + [output flush]; [output release]; return data; } diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m index d5a085c83d..d598a48b60 100644 --- a/objectivec/Tests/GPBMessageTests.m +++ b/objectivec/Tests/GPBMessageTests.m @@ -2225,4 +2225,17 @@ XCTAssertNil(shouldGetAPrefixMessage); } +- (void)testWriteToFullOutputStreamShouldThrow { + uint8_t buffer[1] = {0}; + + // Output stream which can write precisely 1 byte of data before it's full. + NSOutputStream *output = [[[NSOutputStream alloc] initToBuffer:buffer + capacity:sizeof(buffer)] autorelease]; + + TestAllTypes *message = [TestAllTypes message]; + [message setOptionalInt32:1]; + XCTAssertThrowsSpecificNamed([message writeToOutputStream:output], NSException, + GPBCodedOutputStreamException_WriteFailed); +} + @end