java-topology/defects/openxcom-0002/patch/openxcom-0002.patch
russell@unturf.com 47aa94a654 openxcom: 2 CWE-407 defects, MOAD 0002-0005 CLEAN
openxcom-0001: AIModule _reachable/_reachableWithAttack std::vector<int>
  with std::find() inside AI loops (setupAmbush, setupEscape,
  selectPointNearTarget, findFirePoint). O(N*R) per alien turn where
  N = nodes checked, R = reachable tiles (~500 on typical map).
  Fix: std::unordered_set<int> for O(1) lookup. MEDIUM-HIGH, 7.6x.

openxcom-0002: SavedGame::isResearched linear scan of _discovered vector
  O(D) per call, called O(R*4) times from getAvailableResearchProjects
  per base. Also unlocked vector with std::find O(R*U).
  Fix: parallel unordered_set<string> for O(1) lookup. MEDIUM, 4.5x.

MOAD-0002 (Intertangle): CLEAN, typical game state architecture
MOAD-0003 (Leaked Context): CLEAN, single-threaded game
MOAD-0004 (Logged Secret): CLEAN, no credentials
MOAD-0005 (Thundering Herd): CLEAN, no concurrent caching
2026-03-31 12:56:27 -04:00

62 lines
2.1 KiB
Diff

--- a/src/Savegame/SavedGame.h
+++ b/src/Savegame/SavedGame.h
@@ -18,6 +18,7 @@
*/
#include <map>
#include <vector>
+#include <unordered_set>
#include <string>
#include "GameTime.h"
#include "../Mod/RuleAlienMission.h"
@@ -121,1 +122,2 @@
std::vector<const RuleResearch*> _discovered;
+ std::unordered_set<std::string> _discoveredNames;
--- a/src/Savegame/SavedGame.cpp
+++ b/src/Savegame/SavedGame.cpp
# Fix 1: isResearched(string) uses O(1) hash lookup instead of O(D) linear scan
@@ -1433,13 +1434,5 @@
bool SavedGame::isResearched(const std::string &research, bool considerDebugMode) const
{
if (considerDebugMode && _debug)
return true;
- for (std::vector<const RuleResearch *>::const_iterator i = _discovered.begin(); i != _discovered.end(); ++i)
- {
- if ((*i)->getName() == research)
- return true;
- }
-
- return false;
+ return _discoveredNames.count(research) != 0;
}
# Fix 2: Maintain _discoveredNames at all three push_back sites
@@ -500,1 +500,2 @@
_discovered.push_back(mod->getResearch(research));
+ _discoveredNames.insert(research);
@@ -1110,1 +1111,2 @@
_discovered.push_back(research);
+ _discoveredNames.insert(research->getName());
@@ -1138,1 +1140,2 @@
_discovered.push_back(currentQueueItem);
+ _discoveredNames.insert(currentQueueItem->getName());
# Fix 3: getAvailableResearchProjects unlocked vector -> unordered_set
@@ -1247,7 +1250,7 @@
- std::vector<const RuleResearch *> unlocked;
+ std::unordered_set<const RuleResearch *> unlocked;
for (std::vector<const RuleResearch *>::const_iterator it = _discovered.begin(); it != _discovered.end(); ++it)
{
for (std::vector<std::string>::const_iterator itUnlocked = (*it)->getUnlocked().begin(); itUnlocked != (*it)->getUnlocked().end(); ++itUnlocked)
{
- unlocked.push_back(mod->getResearch(*itUnlocked, true));
+ unlocked.insert(mod->getResearch(*itUnlocked, true));
}
}
@@ -1261,1 +1264,1 @@
- if ((considerDebugMode && _debug) || std::find(unlocked.begin(), unlocked.end(), research) != unlocked.end())
+ if ((considerDebugMode && _debug) || unlocked.count(research) != 0)