diff --git a/CHANGES.txt b/CHANGES.txt index f5afcdf47c5c..b3c43613f18e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,6 +7,10 @@ * Fixed a data loss bug that could occur when the number of `optional` fields in a message is an exact multiple of 32. (#9440). + PHP + * Fixed a data loss bug that could occur when the number of `optional` + fields in a message is an exact multiple of 32. (#9440). + 2022-01-10 version 3.19.3 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) Python diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index a668fe0c6d5c..925faa645a56 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -5968,7 +5968,7 @@ static void make_layout(symtab_addctx *ctx, const upb_msgdef *m) { } /* Account for space used by hasbits. */ - l->size = div_round_up(hasbit, 8); + l->size = div_round_up(hasbit + 1, 8); /* Allocate non-oneof fields. */ for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); diff --git a/php/tests/GeneratedClassTest.php b/php/tests/GeneratedClassTest.php index 837f05215ddc..a6101dcbfb2b 100644 --- a/php/tests/GeneratedClassTest.php +++ b/php/tests/GeneratedClassTest.php @@ -9,6 +9,7 @@ use Bar\TestLegacyMessage; use Bar\TestLegacyMessage_NestedEnum; use Bar\TestLegacyMessage_NestedMessage; +use Foo\Test32Fields; use Foo\TestEnum; use Foo\TestIncludeNamespaceMessage; use Foo\TestIncludePrefixMessage; @@ -1849,4 +1850,13 @@ public function testNoExceptionWithVarDump() $this->assertTrue(true); } + + public function testIssue9440() + { + $m = new Test32Fields(); + $m->setId(8); + $this->assertEquals(8, $m->getId()); + $m->setVersion('1'); + $this->assertEquals(8, $m->getId()); + } } diff --git a/php/tests/proto/test.proto b/php/tests/proto/test.proto index 609b8cfe0cdc..421292ab5287 100644 --- a/php/tests/proto/test.proto +++ b/php/tests/proto/test.proto @@ -306,3 +306,38 @@ message TestBytesValue { int32 int32_field = 4; } } + +message Test32Fields { + optional uint32 id = 1; + optional uint32 random_name_a0 = 2; + optional uint32 random_name_a1 = 3; + optional uint32 random_name_a2 = 4; + optional uint32 random_name_a3 = 5; + optional uint32 random_name_a4 = 6; + optional uint32 random_name_a5 = 7; + optional uint32 random_name_a6 = 8; + optional uint32 random_name_a7 = 9; + optional uint32 random_name_a8 = 10; + optional uint32 random_name_a9 = 11; + optional uint32 random_name_b0 = 12; + optional uint32 random_name_b1 = 13; + optional uint32 random_name_b2 = 14; + optional uint32 random_name_b3 = 15; + optional uint32 random_name_b4 = 16; + optional uint32 random_name_b5 = 17; + optional uint32 random_name_b6 = 18; + optional uint32 random_name_b7 = 19; + optional uint32 random_name_b8 = 20; + optional uint32 random_name_b9 = 21; + optional uint32 random_name_c0 = 22; + optional uint32 random_name_c1 = 23; + optional uint32 random_name_c2 = 24; + optional uint32 random_name_c3 = 25; + optional uint32 random_name_c4 = 26; + optional uint32 random_name_c5 = 27; + optional uint32 random_name_c6 = 28; + optional uint32 random_name_c7 = 29; + optional uint32 random_name_c8 = 30; + optional uint32 random_name_c9 = 31; + optional string version = 32; +}