From 951edfdde21c46c9add18397ee5c2de94ffc26ee Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Wed, 30 Sep 2026 06:32:35 -0500 Subject: [PATCH] fix(master): a server list's outdated flags are read all or none A list cut short inside the flags was read as if complete; an older master's list, which has none, still reads. The test checks every cut. Co-Authored-By: Claude Opus 5.5 --- dNet/MasterPackets.cpp | 4 +++- tests/dGameTests/dNetTests/MasterPacketsTests.cpp | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dNet/MasterPackets.cpp b/dNet/MasterPackets.cpp index b46082332..42279ac7d 100644 --- a/dNet/MasterPackets.cpp +++ b/dNet/MasterPackets.cpp @@ -297,7 +297,9 @@ namespace MasterPackets { VALIDATE_READ(bitStream.Read(endpoint.port)); VALIDATE_READ(bitStream.Read(endpoint.host)); } - if (bitStream.GetNumberOfUnreadBits() >= instances.size() * 8) { + // Each world's outdated flag, when the master is new enough to send them: all of them or none + if (bitStream.GetNumberOfUnreadBits() > 0) { + if (bitStream.GetNumberOfUnreadBits() < instances.size() * 8) return false; for (auto& instance : instances) VALIDATE_READ(bitStream.Read(instance.outdated)); } return true; diff --git a/tests/dGameTests/dNetTests/MasterPacketsTests.cpp b/tests/dGameTests/dNetTests/MasterPacketsTests.cpp index 1d79ebaf9..0fe7d8fc9 100644 --- a/tests/dGameTests/dNetTests/MasterPacketsTests.cpp +++ b/tests/dGameTests/dNetTests/MasterPacketsTests.cpp @@ -426,7 +426,16 @@ TEST(MasterPacketsTests, ServerListMatchesLegacy) { EXPECT_EQ(copy.endpoints[i].port, 3000 + i); EXPECT_EQ(copy.endpoints[i].host.string, i == 2 ? "192.168.1.20" : "localhost"); } - ExpectTruncatedFails(response); + // Cut short anywhere it fails, except exactly before the outdated flags (an older master's list), which reads + RakNet::BitStream full; + response.Serialize(full); + const auto olderMaster = full.GetNumberOfBitsUsed() - static_cast(count) * 8; + for (uint32_t bits = 0; bits < full.GetNumberOfBitsUsed(); bits++) { + RakNet::BitStream prefix; + prefix.WriteBits(full.GetData(), bits, false); + MasterPackets::ServerListResponse cut; + EXPECT_EQ(cut.Deserialize(prefix), bits == olderMaster && count > 0) << "read from only " << bits << " bits"; + } } }