From ab0828a4cebca5a5c8af040c6840fa77e500fd36 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 10 Mar 2026 01:08:13 -0700 Subject: [PATCH] game: fix Classic 1.12 SMSG_WHO missing gender byte alignment Vanilla 1.12 SMSG_WHO per-player format: name(CString) + guild(CString) + level(u32) + class(u32) + race(u32) + zone(u32) WotLK 3.3.5a added a gender(u8) byte between race and zone. The previous handleWho always read the gender byte, causing a one-byte misalignment for Classic/TBC: the first byte of zoneId was consumed as gender, then zoneId read from the next 4 bytes (spanning into the next player entry). Now only reads the gender byte for WotLK (isActiveExpansion("wotlk")), and adds bounds checks to prevent out-of-bounds reads on truncated packets. --- src/game/game_handler.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index d5cbbba5..57197a39 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -16390,7 +16390,10 @@ void GameHandler::handlePlayedTime(network::Packet& packet) { } void GameHandler::handleWho(network::Packet& packet) { - // Parse WHO response + // Classic 1.12 / TBC 2.4.3 per-player: name + guild + level(u32) + class(u32) + race(u32) + zone(u32) + // WotLK 3.3.5a added a gender(u8) field between race and zone. + const bool hasGender = isActiveExpansion("wotlk"); + uint32_t displayCount = packet.readUInt32(); uint32_t onlineCount = packet.readUInt32(); @@ -16404,18 +16407,21 @@ void GameHandler::handleWho(network::Packet& packet) { addSystemChatMessage(std::to_string(onlineCount) + " player(s) online:"); for (uint32_t i = 0; i < displayCount; ++i) { + if (packet.getReadPos() >= packet.getSize()) break; std::string playerName = packet.readString(); std::string guildName = packet.readString(); - uint32_t level = packet.readUInt32(); + if (packet.getSize() - packet.getReadPos() < 12) break; + uint32_t level = packet.readUInt32(); uint32_t classId = packet.readUInt32(); - uint32_t raceId = packet.readUInt32(); - packet.readUInt8(); // gender (unused) - packet.readUInt32(); // zoneId (unused) + uint32_t raceId = packet.readUInt32(); + if (hasGender && packet.getSize() - packet.getReadPos() >= 1) + packet.readUInt8(); // gender (WotLK only, unused) + if (packet.getSize() - packet.getReadPos() >= 4) + packet.readUInt32(); // zoneId (unused) std::string msg = " " + playerName; - if (!guildName.empty()) { + if (!guildName.empty()) msg += " <" + guildName + ">"; - } msg += " - Level " + std::to_string(level); addSystemChatMessage(msg);