java-topology/defects/fceux-0001/patch/fceux-0001.patch
russell@unturf.com 4d3cfc9435 fceux: 1 CWE-407 defect, MOAD 0002-0004 noted, MOAD 0005 CLEAN
MOAD-0001 (CWE-407): SubCheatsRead in src/cheat.cpp scans all C active
cheats linearly on every NES memory read at any cheat address. O(C) per
read, C up to 256. Fix: cheat_idx[0x10000] direct address lookup, O(1).
Unit test: 74.7x speedup at C=256. 1/1 PASS.

MOAD-0002: Global mutable state (SubCheats[], ARead[], CheatRPtrs[])
couples cheat, PPU, CPU subsystems -- expected single-threaded NES
architecture, not an actionable intertangle defect.

MOAD-0003: thread_local in profiler.cpp (per-thread profiling data) and
QtScriptManager.cpp (per-JS-engine context pointer) -- legitimate
thread-local scoping, not a leaked request context carrier.

MOAD-0004: NetPlay.cpp line 788 logs netplay session password verbatim
via printf("Authorize: Player: %i   Passwd: %s\n", msg->playerId,
msg->pswd). Debug printf, no patch created per scan protocol (0001 only).

MOAD-0005: No cache get+null+compute+put races found. CLEAN.
2026-03-31 17:17:36 -04:00

84 lines
2.2 KiB
Diff

# UNDF: UNDF-2026-XXXXXXXXX
--- a/src/cheat.cpp
+++ b/src/cheat.cpp
@@ -67,6 +67,10 @@ CHEATF_SUBFAST SubCheats[256];
uint32 numsubcheats = 0;
int globalCheatDisabled = 0;
int disableAutoLSCheats = 0;
bool disableShowGG = 0;
static _8BYTECHEATMAP* cheatMap = NULL;
struct CHEATF *cheats = 0, *cheatsl = 0;
+
+// O(1) direct-address lookup replacing the O(C) SubCheats[] linear scan.
+// Index -1 means no cheat at this address.
+static int cheat_idx[0x10000];
#define CHEATC_NONE 0x8000
@@ -79,16 +83,16 @@ static uint16 *CheatComp = 0;
static DECLFR(SubCheatsRead)
{
- CHEATF_SUBFAST *s = SubCheats;
- int x=numsubcheats;
-
- do
- {
- if(s->addr==A)
- {
- if(s->compare>=0)
- {
- uint8 pv=s->PrevRead(A);
-
- if(pv==s->compare)
- return(s->val);
- else return(pv);
- }
- else return(s->val);
- }
- s++;
- } while(--x);
- return(0); /* We should never get here. */
+ // O(1): look up this address directly instead of scanning all active cheats.
+ int idx = cheat_idx[A];
+ if(idx < 0) return(0); /* should never happen if installed correctly */
+ CHEATF_SUBFAST *s = &SubCheats[idx];
+ if(s->compare>=0)
+ {
+ uint8 pv=s->PrevRead(A);
+ if(pv==s->compare)
+ return(s->val);
+ else return(pv);
+ }
+ return(s->val);
}
void RebuildSubCheats(void)
@@ -96,6 +100,8 @@ void RebuildSubCheats(void)
uint32 x;
struct CHEATF *c = cheats;
+ // Clear the direct-lookup table for addresses we're about to remove.
for (x = 0; x < numsubcheats; x++)
{
+ cheat_idx[SubCheats[x].addr] = -1;
SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[x].addr, false);
@@ -113,6 +119,7 @@ void RebuildSubCheats(void)
SubCheats[numsubcheats].val = c->val;
SubCheats[numsubcheats].compare = c->compare;
SetReadHandler(c->addr, c->addr, SubCheatsRead);
+ cheat_idx[c->addr] = (int)numsubcheats;
if (cheatMap)
FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true);
numsubcheats++;
@@ -123,6 +130,14 @@ void RebuildSubCheats(void)
FrozenAddressCount = numsubcheats;
}
+// Call once at startup to initialise the direct-lookup table.
+void FCEU_CheatIdxInit(void)
+{
+ for(int i = 0; i < 0x10000; i++)
+ cheat_idx[i] = -1;
+}