java-topology/defects/mgba-0001/SCAN-NOTES.md
russell@unturf.com 52bf9f213e snes9x+mgba: 5-MOAD scan; 1 defect (mgba-0001) / snes9x CLEAN
mgba-0001: SM83DebuggerCheckBreakpoints() O(N) linear scan per GB/GBC
CPU instruction — no bloom filter guard, unlike ARMDebugger which already
has bpBloom[4].  Fix: add identical bloom guard to SM83Debugger.
Op-count ratio 10.4x at N=16 breakpoints (PASS).

snes9x: CLEAN across all 5 MOADs.  Breakpoint array is fixed size-6 (O(1)).
Cheat apply is per-frame O(G*C), not per-instruction.  No credential logging.
2026-03-31 21:48:05 -04:00

2.6 KiB
Raw Blame History

mgba-0001: SM83 (Game Boy/GBC) Breakpoint Linear Scan — CWE-407

Target

mGBA — multi-system game emulator Source: https://github.com/mgba-emu/mgba File: src/sm83/debugger/debugger.c

Defect

SM83DebuggerCheckBreakpoints() performs a linear scan (O(N)) through the entire breakpoint list on every single SM83 CPU instruction fetch.

// Called every instruction — inner loop is O(N)
for (i = 0; i < mBreakpointListSize(&debugger->breakpoints); ++i) {
    struct mBreakpoint* breakpoint = mBreakpointListGetPointer(&debugger->breakpoints, i);
    if (breakpoint->disabled) { continue; }
    ...
    if (breakpoint->address != cpu->pc) { continue; }
    ...
}

The Game Boy SM83 CPU runs at 4.194 MHz (GBC double-speed: 8.389 MHz). At N=16 breakpoints this is 16 comparisons per opcode = 67 million address comparisons per emulated second.

ARM Debugger Comparison

The ARM (GBA) debugger ARMDebuggerCheckBreakpoints() in src/arm/debugger/debugger.c already has this exact fix:

if (ARMDebugBreakpointListSize(&debugger->breakpoints) > 3 &&
    !_checkBpBloom(debugger, pc)) {
    return;  // bloom miss — skip O(N) scan entirely
}

The SM83 debugger was never given the same treatment. Our struct SM83Debugger has no bpBloom[] field at all.

Fix

Add uint64_t bpBloom[4] to SM83Debugger (header). Implement _rebuildBpBloom and _checkBpBloom (same logic as ARM debugger). Guard SM83DebuggerCheckBreakpoints with if (!_checkBpBloom(...)) return. Call _rebuildBpBloom from SM83DebuggerSetBreakpoint, SM83DebuggerClearBreakpoint, and SM83DebuggerToggleBreakpoint.

Severity

MEDIUM — affects only debug mode (not production gameplay). However, when a user is debugging a GB/GBC ROM with N breakpoints set, every instruction fetch incurs O(N) work regardless of whether the PC is anywhere near a breakpoint. At high N this causes measurable emulation slowdown while debugging.

Speedup

Java model (MgbaSM83BreakpointTest.java):

  • N=16 breakpoints, 100k instruction fetches across 16-bit address space
  • Bloom false-positive rate: ~1.5% (most non-matching PCs skip list scan)
  • Measured op-count ratio: 10.4x (PASS)
  • At N breakpoints the ratio scales as N × (1 - fp_rate) ≈ N × 0.985

MOADs checked

MOAD Result
0001 CWE-407 DEFECT — SM83 breakpoint O(N) per instruction (this ticket)
0002 Intertangle CLEAN — god-state is intentional emulator architecture
0003 Leaked Context CLEAN — C codebase, no ThreadLocal/ScopedValue
0004 CWE-312 CLEAN — no credential logging found
0005 Thundering Herd CLEAN — single-threaded event loop, no concurrent cache