[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
pull/14670/head
Protobuf Team Bot 2023-11-07 09:31:49 -08:00 committed by Copybara-Service
parent 9ac3548fa9
commit 1e0338b2ba
4 changed files with 24 additions and 0 deletions

View File

@ -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;
}

View File

@ -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];
}

View File

@ -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;
}

View File

@ -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