Fixed a bug in msg.MergeFrom(msg2) in Python.

In `FixupMessageAfterMerge()`, the loop over fields was exiting the entire function if a mutable field was found, but this skips other fields that may need fixing up.

PiperOrigin-RevId: 882766354
This commit is contained in:
Joshua Haberman 2026-03-12 14:01:12 -07:00 committed by Copybara-Service
parent 08244d7a74
commit ab14c0f8ad
3 changed files with 54 additions and 1 deletions

View file

@ -3071,6 +3071,34 @@ class PackedFieldTest(unittest.TestCase):
self.assertEqual(golden_data, message.SerializeToString())
@testing_refleaks.TestCase
class MergeFromTest(unittest.TestCase):
def testBugFixupAfterMerge(self):
target = more_messages_pb2.LotsOfMessageFields()
wrappers = []
# Access all fields mutably, except for a10 which is accessed read-only.
for i in range(1, 21):
sub = getattr(target, f'a{i}')
wrappers.append(sub)
if i != 10:
# Access mutable.
sub.b = 1
self.assertEqual(target.a10.b, 0)
self.assertFalse(target.HasField('a10'))
source = more_messages_pb2.LotsOfMessageFields()
source.a10.b = 1
# The read-only message target.a10 needs to be updated to point to the new
# message that is created by MergeFrom.
target.MergeFrom(source)
self.assertEqual(target.a10.b, 1)
self.assertTrue(target.HasField('a10'))
@testing_refleaks.TestCase
class OversizeProtosTest(unittest.TestCase):

View file

@ -342,6 +342,31 @@ message LotsNestedMessage {
message B255 {}
}
message LotsOfMessageFields {
optional LotsOfMessageFields a1 = 1;
optional LotsOfMessageFields a2 = 2;
optional LotsOfMessageFields a3 = 3;
optional LotsOfMessageFields a4 = 4;
optional LotsOfMessageFields a5 = 5;
optional LotsOfMessageFields a6 = 6;
optional LotsOfMessageFields a7 = 7;
optional LotsOfMessageFields a8 = 8;
optional LotsOfMessageFields a9 = 9;
optional LotsOfMessageFields a10 = 10;
optional LotsOfMessageFields a11 = 11;
optional LotsOfMessageFields a12 = 12;
optional LotsOfMessageFields a13 = 13;
optional LotsOfMessageFields a14 = 14;
optional LotsOfMessageFields a15 = 15;
optional LotsOfMessageFields a16 = 16;
optional LotsOfMessageFields a17 = 17;
optional LotsOfMessageFields a18 = 18;
optional LotsOfMessageFields a19 = 19;
optional LotsOfMessageFields a20 = 20;
optional int32 b = 100;
}
message RequiredField {
required int32 id = 1;
}

View file

@ -810,7 +810,7 @@ int FixupMessageAfterMerge(CMessage* self) {
!descriptor->is_repeated()) {
CMessage* cmsg = reinterpret_cast<CMessage*>(item.second);
if (cmsg->read_only == false) {
return 0;
continue;
}
Message* message = self->message;
const Reflection* reflection = message->GetReflection();