Skip to content

Commit b3b9888

Browse files
committed
[ObjC] Fix GPBUnknownField/GPBUnknownFields copy.
Since a group GPBUnknownField uses a GPBUnknownFields and that is mutable, it needs to be copied so two instances aren't linked. PiperOrigin-RevId: 663323972
1 parent 35bd2be commit b3b9888

File tree

3 files changed

+26
-14
lines changed

3 files changed

+26
-14
lines changed

objectivec/GPBUnknownField.m

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,17 @@ - (id)copyWithZone:(NSZone *)zone {
165165
case GPBUnknownFieldTypeFixed32:
166166
case GPBUnknownFieldTypeFixed64:
167167
case GPBUnknownFieldTypeLengthDelimited:
168-
case GPBUnknownFieldTypeGroup:
169168
// In these modes, the object isn't mutable, so just return self.
170169
return [self retain];
170+
case GPBUnknownFieldTypeGroup: {
171+
// The `GPBUnknownFields` for the group is mutable, so a new instance of this object and
172+
// the group is needed.
173+
GPBUnknownFields *copyGroup = [storage_.group copyWithZone:zone];
174+
GPBUnknownField *copy = [[GPBUnknownField allocWithZone:zone] initWithNumber:number_
175+
group:copyGroup];
176+
[copyGroup release];
177+
return copy;
178+
}
171179
case GPBUnknownFieldTypeLegacy: {
172180
#pragma clang diagnostic push
173181
#pragma clang diagnostic ignored "-Wdeprecated-declarations"

objectivec/GPBUnknownFields.m

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,8 @@ - (instancetype)init {
228228
}
229229

230230
- (id)copyWithZone:(NSZone *)zone {
231-
GPBUnknownFields *copy = [[GPBUnknownFields alloc] init];
232-
// Fields are r/o in this api, so just copy the array.
233-
copy->fields_ = [fields_ mutableCopyWithZone:zone];
231+
GPBUnknownFields *copy = [[GPBUnknownFields allocWithZone:zone] init];
232+
copy->fields_ = [[NSMutableArray allocWithZone:zone] initWithArray:fields_ copyItems:YES];
234233
return copy;
235234
}
236235

objectivec/Tests/GPBUnknownFieldsTest.m

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -683,25 +683,30 @@ - (void)testCopy {
683683
[ufs addFieldNumber:3 fixed64:3];
684684
[ufs addFieldNumber:4 lengthDelimited:DataFromCStr("foo")];
685685
GPBUnknownFields* group = [ufs addGroupWithFieldNumber:5];
686+
[group addFieldNumber:10 varint:10];
687+
GPBUnknownFields* subGroup = [group addGroupWithFieldNumber:100];
688+
[subGroup addFieldNumber:20 varint:20];
686689

687690
GPBUnknownFields* ufs2 = [[ufs copy] autorelease];
688691
XCTAssertTrue(ufs != ufs2); // Different objects
689692
XCTAssertEqualObjects(ufs, ufs2); // Equal contents
690-
// All the actual field objects should be the same since they are immutable.
693+
// All field objects but the group should be the same since they are immutable.
691694
XCTAssertTrue([[ufs fields:1] firstObject] == [[ufs2 fields:1] firstObject]); // Same object
692695
XCTAssertTrue([[ufs fields:2] firstObject] == [[ufs2 fields:2] firstObject]); // Same object
693696
XCTAssertTrue([[ufs fields:3] firstObject] == [[ufs2 fields:3] firstObject]); // Same object
694697
XCTAssertTrue([[ufs fields:4] firstObject] == [[ufs2 fields:4] firstObject]); // Same object
695698
XCTAssertTrue([[ufs fields:4] firstObject].lengthDelimited ==
696-
[[ufs2 fields:4] firstObject].lengthDelimited); // Same object
697-
XCTAssertTrue([[ufs fields:5] firstObject] == [[ufs2 fields:5] firstObject]); // Same object
698-
XCTAssertTrue(group == [[ufs2 fields:5] firstObject].group); // Same object
699-
700-
// Now force copies on the fields to confirm that is not making new objects either.
701-
for (GPBUnknownField* field in ufs) {
702-
GPBUnknownField* field2 = [[field copy] autorelease];
703-
XCTAssertTrue(field == field2); // Same object (since they aren't mutable).
704-
}
699+
[[ufs2 fields:4] firstObject].lengthDelimited); // Same object
700+
// Since the group holds another `GPBUnknownFields` object (which is mutable), it will be a
701+
// different object.
702+
XCTAssertTrue([[ufs fields:5] firstObject] != [[ufs2 fields:5] firstObject]);
703+
XCTAssertTrue(group != [[ufs2 fields:5] firstObject].group);
704+
XCTAssertEqualObjects(group, [[ufs2 fields:5] firstObject].group);
705+
// And confirm that copy went deep so the nested group also is a different object.
706+
GPBUnknownFields* groupCopied = [[ufs2 fields:5] firstObject].group;
707+
XCTAssertTrue([[group fields:100] firstObject] != [[groupCopied fields:100] firstObject]);
708+
XCTAssertTrue(subGroup != [[groupCopied fields:100] firstObject].group);
709+
XCTAssertEqualObjects(subGroup, [[groupCopied fields:100] firstObject].group);
705710
}
706711

707712
- (void)testInvalidFieldNumbers {

0 commit comments

Comments
 (0)