java-topology/defects/fceux-0001/test/test_fceux_0001.cpp
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

144 lines
3.9 KiB
C++

// test_fceux_0001.cpp
// Unit test for fceux-0001: SubCheatsRead O(C) linear scan -> O(1) direct lookup
//
// Reproduces the defect in isolation, verifies the fix gives correct results,
// and benchmarks the operation ratio at C=256 cheats.
#include <cassert>
#include <cstdint>
#include <cstring>
#include <cstdio>
#include <ctime>
// ---- Reproduction of the defect ----
struct CHEATF_SUBFAST {
uint16_t addr;
uint8_t val;
int compare; // -1 means no compare
};
static const int MAX_CHEATS = 256;
// ---- DEFECT: O(C) linear scan per read ----
static CHEATF_SUBFAST SubCheats_defect[MAX_CHEATS];
static int numsubcheats_defect = 0;
static uint8_t defect_SubCheatsRead(uint16_t A)
{
CHEATF_SUBFAST *s = SubCheats_defect;
int x = numsubcheats_defect;
do {
if (s->addr == A) {
return s->val;
}
s++;
} while (--x);
return 0; // should not reach
}
// ---- FIX: O(1) direct index lookup ----
static CHEATF_SUBFAST SubCheats_fixed[MAX_CHEATS];
static int numsubcheats_fixed = 0;
static int cheat_idx[0x10000];
static void fixed_init()
{
memset(cheat_idx, -1, sizeof(cheat_idx));
}
static void fixed_add(uint16_t addr, uint8_t val, int compare)
{
int idx = numsubcheats_fixed;
SubCheats_fixed[idx] = { addr, val, compare };
cheat_idx[addr] = idx;
numsubcheats_fixed++;
}
static uint8_t fixed_SubCheatsRead(uint16_t A)
{
int idx = cheat_idx[A];
if (idx < 0) return 0;
return SubCheats_fixed[idx].val;
}
// ---- Helpers ----
static long clock_ns()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (long)ts.tv_sec * 1000000000L + ts.tv_nsec;
}
static void build_defect(int n_cheats)
{
numsubcheats_defect = 0;
for (int i = 0; i < n_cheats; i++) {
uint16_t addr = (uint16_t)(0x0300 + i);
SubCheats_defect[numsubcheats_defect++] = { addr, (uint8_t)(i & 0xFF), -1 };
}
}
static void build_fixed(int n_cheats)
{
fixed_init();
numsubcheats_fixed = 0;
for (int i = 0; i < n_cheats; i++) {
uint16_t addr = (uint16_t)(0x0300 + i);
fixed_add(addr, (uint8_t)(i & 0xFF), -1);
}
}
int main()
{
const int N = MAX_CHEATS; // 256 active cheats
const int REPS = 10000000;
// ---- Correctness: both implementations must return identical values ----
build_defect(N);
build_fixed(N);
for (int i = 0; i < N; i++) {
uint16_t addr = (uint16_t)(0x0300 + i);
uint8_t expected = (uint8_t)(i & 0xFF);
uint8_t got_defect = defect_SubCheatsRead(addr);
uint8_t got_fixed = fixed_SubCheatsRead(addr);
assert(got_defect == expected && "defect implementation returned wrong value");
assert(got_fixed == expected && "fixed implementation returned wrong value");
}
printf("CORRECTNESS: PASS (both return identical values for %d cheats)\n", N);
// ---- Performance: O(1) must be substantially faster than O(C) ----
// Simulate reading from all cheat addresses REPS times (worst-case: last address each read)
uint16_t worst_addr = (uint16_t)(0x0300 + N - 1); // last cheat = max scan in defect
volatile uint8_t sink = 0;
long t0 = clock_ns();
for (int r = 0; r < REPS; r++) {
sink ^= defect_SubCheatsRead(worst_addr);
}
long defect_ns = clock_ns() - t0;
long t1 = clock_ns();
for (int r = 0; r < REPS; r++) {
sink ^= fixed_SubCheatsRead(worst_addr);
}
long fixed_ns = clock_ns() - t1;
(void)sink;
double ratio = (double)defect_ns / (double)fixed_ns;
printf("BENCHMARK: defect=%ldns fixed=%ldns ratio=%.1fx (C=%d cheats)\n",
defect_ns, fixed_ns, ratio, N);
// Expect at least 5x improvement with 256 cheats
assert(ratio >= 5.0 && "expected at least 5x speedup with O(1) lookup vs O(256) scan");
printf("PERFORMANCE: PASS (%.1fx >= 5.0x required)\n", ratio);
printf("ALL TESTS PASSED\n");
return 0;
}