java-topology/defects/openmw-0002/patch/openmw-0002.patch
russell@unturf.com 4e3dcc8d2a openmw: 4 CWE-407 defects, MOAD 0002-0005 CLEAN
openmw-0001: pathgrid.cpp Tarjan SCC std::find(mSCCStack) O(V^2), 2.3x (HIGH)
openmw-0002: pathgrid.cpp A* openset std::find O(V*E), 4.4x op-count (HIGH)
openmw-0003: cellstore.cpp mMovedRefs std::find O(R*M), 15.6x (MEDIUM)
openmw-0004: objectpaging.cpp mMovedRefs std::find O(R*M), 4.9x (MEDIUM)

MOAD-0002 (Intertangle): CLEAN, typical game engine global state
MOAD-0003 (Leaked Context): CLEAN, no thread_local identity carriers
MOAD-0004 (Logged Secret): CLEAN, game engine has no credentials
MOAD-0005 (Thundering Herd): CLEAN, no unsynchronized cache patterns

8/8 unit tests PASS.
2026-03-31 12:11:13 -04:00

43 lines
1.7 KiB
Diff

# UNDF: UNDF-2026-000000964
--- a/apps/openmw/mwmechanics/pathgrid.cpp
+++ b/apps/openmw/mwmechanics/pathgrid.cpp
@@ -1,6 +1,7 @@
#include "pathgrid.hpp"
#include <algorithm>
+#include <unordered_set>
#include <list>
#include <set>
@@ -250,6 +251,7 @@
std::list<size_t> openset;
std::set<size_t> closedset;
+ std::unordered_set<size_t> opensetMembership;
openset.push_back(start);
+ opensetMembership.insert(start);
size_t current = start;
@@ -260,6 +262,7 @@
current = openset.front(); // front has the lowest cost
openset.pop_front();
+ opensetMembership.erase(current);
if (current == goal)
break;
@@ -274,7 +277,7 @@
size_t dest = edge.index;
float tentativeG = gScore[current] + edge.cost;
- bool isInOpenSet = std::find(openset.begin(), openset.end(), dest) != openset.end();
+ bool isInOpenSet = opensetMembership.count(dest) > 0;
if (!isInOpenSet || tentativeG < gScore[dest])
{
graphParent[dest] = current;
@@ -282,6 +285,7 @@
fScore[dest] = tentativeG + costAStar(mPathgrid->mPoints[dest], mPathgrid->mPoints[goal]);
if (!isInOpenSet)
{
+ opensetMembership.insert(dest);
// add this edge to openset, lowest cost goes to the front
// TODO: if this causes performance problems a hash table may help
auto it = openset.begin();