From b346b26c81dd18ae83f637d14ce337090d8336cb Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 03:46:15 +0000 Subject: [PATCH] RankPoints: Add safety checks for potentially corrupted TheGameSpyConfig pointer --- .../Include/GameNetwork/GameSpy/GSConfig.h | 8 ++++ .../GUICallbacks/Menus/PopupPlayerInfo.cpp | 42 ++++++++++++------- .../Include/GameNetwork/GameSpy/GSConfig.h | 8 ++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h index 561c2f232a5..a2126ae3286 100644 --- a/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h +++ b/Generals/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h @@ -79,4 +79,12 @@ class GameSpyConfigInterface extern GameSpyConfigInterface *TheGameSpyConfig; +// Helper function to safely check if TheGameSpyConfig pointer is valid +// Protects against both NULL and corrupted pointer values (e.g., small integers like 0x4) +inline bool IsGameSpyConfigValid() +{ + // A valid pointer on Windows should be >= 0x10000 (64KB) to avoid accessing low memory + return (TheGameSpyConfig != NULL) && ((uintptr_t)TheGameSpyConfig >= 0x10000); +} + #endif // __GSCONFIG_H__ diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp index 4df6ed0f319..7ffdfe2b938 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp @@ -246,22 +246,36 @@ void GetAdditionalDisconnectsFromUserFile(PSPlayerStats *stats) RankPoints::RankPoints(void) { m_ranks[RANK_PRIVATE] = 0; - // Use default values if TheGameSpyConfig is NULL (can happen if called during teardown) - if (TheGameSpyConfig != NULL) - { - m_ranks[RANK_CORPORAL] = TheGameSpyConfig->getPointsForRank(RANK_CORPORAL); // 5 - m_ranks[RANK_SERGEANT] = TheGameSpyConfig->getPointsForRank(RANK_SERGEANT); // 10 - m_ranks[RANK_LIEUTENANT] = TheGameSpyConfig->getPointsForRank(RANK_LIEUTENANT); // 20 - m_ranks[RANK_CAPTAIN] = TheGameSpyConfig->getPointsForRank(RANK_CAPTAIN); // 50 - m_ranks[RANK_MAJOR] = TheGameSpyConfig->getPointsForRank(RANK_MAJOR); // 100 - m_ranks[RANK_COLONEL] = TheGameSpyConfig->getPointsForRank(RANK_COLONEL); // 200 - m_ranks[RANK_BRIGADIER_GENERAL] = TheGameSpyConfig->getPointsForRank(RANK_BRIGADIER_GENERAL); // 500 - m_ranks[RANK_GENERAL] = TheGameSpyConfig->getPointsForRank(RANK_GENERAL); // 1000 - m_ranks[RANK_COMMANDER_IN_CHIEF] = TheGameSpyConfig->getPointsForRank(RANK_COMMANDER_IN_CHIEF); // 2000 + + // Validate TheGameSpyConfig pointer before use using helper function + Bool isValidPointer = IsGameSpyConfigValid(); + + if (isValidPointer) + { + // Additional safety: wrap in try-catch to handle any remaining access violations + try + { + m_ranks[RANK_CORPORAL] = TheGameSpyConfig->getPointsForRank(RANK_CORPORAL); // 5 + m_ranks[RANK_SERGEANT] = TheGameSpyConfig->getPointsForRank(RANK_SERGEANT); // 10 + m_ranks[RANK_LIEUTENANT] = TheGameSpyConfig->getPointsForRank(RANK_LIEUTENANT); // 20 + m_ranks[RANK_CAPTAIN] = TheGameSpyConfig->getPointsForRank(RANK_CAPTAIN); // 50 + m_ranks[RANK_MAJOR] = TheGameSpyConfig->getPointsForRank(RANK_MAJOR); // 100 + m_ranks[RANK_COLONEL] = TheGameSpyConfig->getPointsForRank(RANK_COLONEL); // 200 + m_ranks[RANK_BRIGADIER_GENERAL] = TheGameSpyConfig->getPointsForRank(RANK_BRIGADIER_GENERAL); // 500 + m_ranks[RANK_GENERAL] = TheGameSpyConfig->getPointsForRank(RANK_GENERAL); // 1000 + m_ranks[RANK_COMMANDER_IN_CHIEF] = TheGameSpyConfig->getPointsForRank(RANK_COMMANDER_IN_CHIEF); // 2000 + } + catch (...) + { + // If any exception occurs (e.g., access violation), fall back to default values + DEBUG_LOG(("RankPoints::RankPoints() - Exception accessing TheGameSpyConfig (possibly corrupted pointer), using defaults")); + isValidPointer = false; + } } - else + + if (!isValidPointer) { - // Use default hardcoded values when TheGameSpyConfig is not available + // Use default hardcoded values when TheGameSpyConfig is not available or corrupted m_ranks[RANK_CORPORAL] = 5; m_ranks[RANK_SERGEANT] = 10; m_ranks[RANK_LIEUTENANT] = 20; diff --git a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h index fb03080e9e1..84e5040179e 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h +++ b/GeneralsMD/Code/GameEngine/Include/GameNetwork/GameSpy/GSConfig.h @@ -70,4 +70,12 @@ class GameSpyConfigInterface extern GameSpyConfigInterface *TheGameSpyConfig; +// Helper function to safely check if TheGameSpyConfig pointer is valid +// Protects against both NULL and corrupted pointer values (e.g., small integers like 0x4) +inline bool IsGameSpyConfigValid() +{ + // A valid pointer on Windows should be >= 0x10000 (64KB) to avoid accessing low memory + return (TheGameSpyConfig != NULL) && ((uintptr_t)TheGameSpyConfig >= 0x10000); +} + #endif // __GSCONFIG_H__