From 34bd2adcd3bc22397b0b1da18547d8f827ee5a0f Mon Sep 17 00:00:00 2001 From: Dave Allison Date: Thu, 1 Oct 2026 12:21:38 -0700 Subject: [PATCH] Fix vector header issues --- MODULE.bazel | 2 +- phaser/runtime/message_test.cc | 34 ++++++++++++++++++++++++++++++++++ phaser/runtime/vectors.h | 2 +- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index ba2f84d..49a7a93 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "phaser", - version = "2.1.1" + version = "2.1.2" ) bazel_dep(name = "bazel_skylib", version = "1.9.0") diff --git a/phaser/runtime/message_test.cc b/phaser/runtime/message_test.cc index 7e10a25..cdcc418 100644 --- a/phaser/runtime/message_test.cc +++ b/phaser/runtime/message_test.cc @@ -2111,6 +2111,40 @@ TEST(MessageTest, PhaserBank) { free(buffer); } +// Regression for pooled-output reuse: repeated nested messages with per-element +// strings in an 8 KiB dynamic buffer without vector reserve. Tick 1 string +// corruption and tick 2 Clear() spinning in PayloadBuffer::Free occurred when +// vector/string mutation used static layout offsets instead of resolved metadata +// offsets (StringHeaderOffset / ResolvedVectorHeader). +TEST(MessageTest, RepeatedNestedMessagesNoReserveSurvivesPoolClear) { + constexpr size_t kBufSize = 8192; + TestMessage msg = TestMessage::CreateDynamicMutable(kBufSize); + + auto build_and_check = [&](int tick) { + for (int i = 0; i < 50; ++i) { + InnerMessage entry = msg.vm_.Add(); + const std::string name = absl::StrFormat( + "/example/item_%02d_repeated_nested_field_with_a_long_string_value", + i + tick * 100); + entry.str_.Set(name); + entry.f_.Set(static_cast(i)); + } + ASSERT_EQ(50u, msg.vm_.size()); + for (int i = 0; i < 50; ++i) { + const std::string expect = absl::StrFormat( + "/example/item_%02d_repeated_nested_field_with_a_long_string_value", + i + tick * 100); + SCOPED_TRACE(absl::StrFormat("tick=%d index=%d", tick, i)); + EXPECT_EQ(expect, msg.vm_.Get(static_cast(i)).str_.Get()); + } + }; + + build_and_check(1); + msg.Clear(); + build_and_check(2); + msg.Clear(); +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); diff --git a/phaser/runtime/vectors.h b/phaser/runtime/vectors.h index 0fbf8a2..42106b6 100644 --- a/phaser/runtime/vectors.h +++ b/phaser/runtime/vectors.h @@ -1676,7 +1676,7 @@ class StringVectorField : public Field { } const ::toolbelt::BufferOffset string_offset = GetRuntime()->ToOffset(str_hdr); - hdr = Header(); + hdr = ResolvedVectorHeader(); if (hdr == nullptr) { return {}; }