diff --git a/CHANGES.txt b/CHANGES.txt index 1bb36d5504bc..b3c43613f18e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,6 +3,10 @@ Python * Make libprotobuf symbols local on OSX to fix issue #9395 (#9435) + Ruby + * 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). diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index d68caac0e2cc..d6c2a0bc5d3e 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -5583,7 +5583,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/ruby/tests/basic.rb b/ruby/tests/basic.rb index 841b8b502f22..b9d1554dbd33 100755 --- a/ruby/tests/basic.rb +++ b/ruby/tests/basic.rb @@ -71,6 +71,14 @@ def test_issue_8559_crash TestMessage.encode(msg) end + def test_issue_9440 + msg = HelloRequest.new + msg.id = 8 + assert_equal 8, msg.id + msg.version = '1' + assert_equal 8, msg.id + end + def test_has_field m = TestSingularFields.new assert !m.has_singular_msg? diff --git a/ruby/tests/basic_test.proto b/ruby/tests/basic_test.proto index bca172a722ec..fb70f479db5b 100644 --- a/ruby/tests/basic_test.proto +++ b/ruby/tests/basic_test.proto @@ -215,3 +215,38 @@ message WithJsonName { optional int32 foo_bar = 1 [json_name="jsonFooBar"]; repeated WithJsonName baz = 2 [json_name="jsonBaz"]; } + +message HelloRequest { + 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; +}