java-topology/defects/openmw-0004/patch/openmw-0004.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

29 lines
1.1 KiB
Diff

# UNDF: UNDF-2026-000000966
--- a/apps/openmw/mwrender/objectpaging.cpp
+++ b/apps/openmw/mwrender/objectpaging.cpp
@@ -1,4 +1,5 @@
#include "objectpaging.hpp"
+#include <unordered_set>
// ...existing includes...
@@ -555,6 +556,12 @@
+ // Build mMovedRefs lookup set once per cell for O(1) membership check.
+ std::unordered_set<ESM::RefNum, ESM::RefNum::HashPair> movedRefSet;
+ movedRefSet.reserve(cell->mMovedRefs.size());
+ for (const auto& moved : cell->mMovedRefs)
+ movedRefSet.insert(moved.mRefNum);
+
{
try
{
@@ -573,8 +580,7 @@
if (moved)
continue;
- if (std::find(cell->mMovedRefs.begin(), cell->mMovedRefs.end(), ref.mRefNum)
- != cell->mMovedRefs.end())
+ if (movedRefSet.count(ref.mRefNum))
continue;
int type = store.findStatic(ref.mRefID);