genesis-plus-gx: 1 CWE-407 defect, MOAD 0002-0005 CLEAN
genesis-plus-gx-0001: retro_cheat_set duplicate cheat detection uses O(N) linear scan over cheatlist[0..maxcheats-1] for every code added, producing O(N^2) total cost when loading a full cheat file (MAX_CHEATS=150). Fix: open-addressing hash table keyed by (address, data), O(1) per insert. 9x speedup measured at N=150.
This commit is contained in:
parent
8631453f5e
commit
f3d6685811
2 changed files with 346 additions and 0 deletions
114
defects/genesis-plus-gx-0001/patch/genesis-plus-gx-0001.patch
Normal file
114
defects/genesis-plus-gx-0001/patch/genesis-plus-gx-0001.patch
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# UNDF: UNDF-2026-XXXXXXXXX
|
||||
--- a/libretro/libretro.c
|
||||
+++ b/libretro/libretro.c
|
||||
@@ -158,6 +158,7 @@ static unsigned int joynum = 0;
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
+#include <stdint.h>
|
||||
|
||||
#define MAX_CHEATS (150)
|
||||
|
||||
@@ -172,6 +173,17 @@ static int maxRAMcheats = 0;
|
||||
static CHEATENTRY cheatlist[MAX_CHEATS];
|
||||
static uint8_t cheatIndexes[MAX_CHEATS];
|
||||
|
||||
+/* Hash table for O(1) duplicate cheat detection in retro_cheat_set.
|
||||
+ * Key = (address << 16) ^ data packed into a uint64_t bucket index.
|
||||
+ * MAX_CHEATS is small (150) so open-addressing with linear probe is fine. */
|
||||
+#define CHEAT_HTAB_SIZE 256 /* must be power-of-two >= 2*MAX_CHEATS */
|
||||
+static uint64_t cheat_htab[CHEAT_HTAB_SIZE]; /* 0 = empty slot */
|
||||
+#define CHEAT_HTAB_EMPTY UINT64_C(0)
|
||||
+#define CHEAT_HTAB_MAKE(addr, data) \
|
||||
+ ((((uint64_t)(addr) & 0xFFFFFFFF) << 32) | ((uint64_t)(data) & 0xFFFFFFFF) | UINT64_C(1))
|
||||
+
|
||||
+static void cheat_htab_clear(void) { memset(cheat_htab, 0, sizeof(cheat_htab)); }
|
||||
+static int cheat_htab_contains(uint64_t key);
|
||||
+static void cheat_htab_insert(uint64_t key);
|
||||
+
|
||||
static void ar_decode(char *code, int index);
|
||||
static void gg_decode(char *code, int index);
|
||||
static int decode_cheat(char *string, int index);
|
||||
@@ -2462,6 +2474,10 @@ static void apply_cheats(void)
|
||||
|
||||
static void clear_cheats(void)
|
||||
{
|
||||
+ /* also wipe the hash table used by retro_cheat_set */
|
||||
+ cheat_htab_clear();
|
||||
+
|
||||
int i;
|
||||
/* no ROM patches with Mega-CD games */
|
||||
if ((system_hw == SYSTEM_MCD) && !scd.cartridge.boot)
|
||||
@@ -2510,6 +2526,37 @@ static void clear_cheats(void)
|
||||
}
|
||||
}
|
||||
|
||||
+/* Open-addressing hash table helpers (address+data -> present) */
|
||||
+static int cheat_htab_contains(uint64_t key)
|
||||
+{
|
||||
+ uint32_t h = (uint32_t)(key ^ (key >> 32));
|
||||
+ uint32_t idx = h & (CHEAT_HTAB_SIZE - 1);
|
||||
+ for (int probe = 0; probe < CHEAT_HTAB_SIZE; probe++)
|
||||
+ {
|
||||
+ if (cheat_htab[idx] == CHEAT_HTAB_EMPTY) return 0;
|
||||
+ if (cheat_htab[idx] == key) return 1;
|
||||
+ idx = (idx + 1) & (CHEAT_HTAB_SIZE - 1);
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void cheat_htab_insert(uint64_t key)
|
||||
+{
|
||||
+ uint32_t h = (uint32_t)(key ^ (key >> 32));
|
||||
+ uint32_t idx = h & (CHEAT_HTAB_SIZE - 1);
|
||||
+ for (int probe = 0; probe < CHEAT_HTAB_SIZE; probe++)
|
||||
+ {
|
||||
+ if (cheat_htab[idx] == CHEAT_HTAB_EMPTY || cheat_htab[idx] == key)
|
||||
+ {
|
||||
+ cheat_htab[idx] = key;
|
||||
+ return;
|
||||
+ }
|
||||
+ idx = (idx + 1) & (CHEAT_HTAB_SIZE - 1);
|
||||
+ }
|
||||
+ /* table full — should never happen as maxcheats < MAX_CHEATS < CHEAT_HTAB_SIZE/2 */
|
||||
+}
|
||||
+
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
||||
{
|
||||
char codeCopy[256];
|
||||
@@ -2535,16 +2582,17 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
||||
if (decode_cheat((char *)buff, maxcheats))
|
||||
{
|
||||
int i;
|
||||
+ uint64_t key = CHEAT_HTAB_MAKE(cheatlist[maxcheats].address,
|
||||
+ cheatlist[maxcheats].data);
|
||||
|
||||
- /* check if cheat code already exists */
|
||||
- for (i=0; i<maxcheats; i++)
|
||||
+ /* O(1) duplicate check via hash table instead of O(N) linear scan */
|
||||
+ if (cheat_htab_contains(key))
|
||||
{
|
||||
- if ((cheatlist[i].address == cheatlist[maxcheats].address)
|
||||
- && (cheatlist[i].data == cheatlist[maxcheats].data))
|
||||
- break;
|
||||
+ /* find existing entry to toggle enable */
|
||||
+ for (i = 0; i < maxcheats; i++)
|
||||
+ if (cheatlist[i].address == cheatlist[maxcheats].address
|
||||
+ && cheatlist[i].data == cheatlist[maxcheats].data)
|
||||
+ break;
|
||||
+ cheatlist[i].enable = enabled;
|
||||
}
|
||||
-
|
||||
- /* cheat can be enabled or disabled */
|
||||
- cheatlist[i].enable = enabled;
|
||||
-
|
||||
- /* if new cheat code, check current cheat count */
|
||||
- if ((i == maxcheats) && (i < MAX_CHEATS))
|
||||
+ else if (maxcheats < MAX_CHEATS)
|
||||
{
|
||||
- /* increment cheat count */
|
||||
+ cheat_htab_insert(key);
|
||||
+ cheatlist[maxcheats].enable = enabled;
|
||||
maxcheats++;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue