hatari: 1 CWE-407 defect, MOAD 0002-0005 CLEAN
This commit is contained in:
parent
64dee0eb9c
commit
2611f389b6
2 changed files with 300 additions and 0 deletions
101
defects/hatari-0001/patch/hatari-0001.patch
Normal file
101
defects/hatari-0001/patch/hatari-0001.patch
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# UNDF: UNDF-2026-000001040
|
||||
--- a/src/ikbd.c
|
||||
+++ b/src/ikbd.c
|
||||
@@ -218,6 +218,28 @@ static const struct {
|
||||
void (*pCallFunction)(void);
|
||||
} KeyboardCommands[] =
|
||||
{
|
||||
+ /* Dispatch table built at init from KeyboardCommands[] for O(1) lookup. */
|
||||
+ /* See IKBD_InitDispatch() and IKBD_RunKeyboardCommand(). */
|
||||
/* Known messages, counts include command byte */
|
||||
{ 0x80,2, IKBD_Cmd_Reset },
|
||||
{ 0x07,2, IKBD_Cmd_MouseAction },
|
||||
@@ -258,6 +280,33 @@ static const struct {
|
||||
{ 0xFF,0, NULL } /* Term */
|
||||
};
|
||||
|
||||
+/* Dispatch table: indexed by command byte, holds index into KeyboardCommands[]
|
||||
+ * or -1 for unknown commands. Built once by IKBD_InitDispatch(). */
|
||||
+static int IKBDCmdIndex[256];
|
||||
+
|
||||
+/**
|
||||
+ * Build the O(1) command-dispatch index from KeyboardCommands[].
|
||||
+ * Called once during IKBD initialisation.
|
||||
+ */
|
||||
+static void IKBD_InitDispatch(void)
|
||||
+{
|
||||
+ int i;
|
||||
+ for (i = 0; i < 256; i++)
|
||||
+ IKBDCmdIndex[i] = -1;
|
||||
+ for (i = 0; KeyboardCommands[i].Command != 0xFF; i++)
|
||||
+ IKBDCmdIndex[KeyboardCommands[i].Command] = i;
|
||||
+}
|
||||
+
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
/* Variables/defines/functions used to transfer data between the */
|
||||
@@ -830,6 +879,7 @@ void IKBD_Reset(bool bCold)
|
||||
/* Reset */
|
||||
memset(&Keyboard, 0, sizeof(Keyboard));
|
||||
|
||||
+ IKBD_InitDispatch();
|
||||
+
|
||||
/* IKBD gets reset whenever the computer does */
|
||||
IKBD_ResetKeyboardProcessor();
|
||||
|
||||
@@ -1854,22 +1904,22 @@ static void IKBD_RunKeyboardCommand(uint8_t aciabyte)
|
||||
{
|
||||
- int i=0;
|
||||
|
||||
/* Write into our keyboard input buffer if it's not full yet */
|
||||
if ( Keyboard.nBytesInInputBuffer < SIZE_KEYBOARDINPUT_BUFFER )
|
||||
Keyboard.InputBuffer[Keyboard.nBytesInInputBuffer++] = aciabyte;
|
||||
|
||||
- /* Now check bytes to see if we have a valid/in-valid command string set */
|
||||
- while (KeyboardCommands[i].Command!=0xff)
|
||||
- {
|
||||
- /* Found command? */
|
||||
- if (KeyboardCommands[i].Command==Keyboard.InputBuffer[0])
|
||||
- {
|
||||
- /* If the command is complete (with its possible parameters) we can execute it */
|
||||
- /* Else, we wait for the next bytes until the command is complete */
|
||||
- if (KeyboardCommands[i].NumParameters==Keyboard.nBytesInInputBuffer)
|
||||
- {
|
||||
- /* Any new valid command will unpause the output (if command 0x13 was used) */
|
||||
- Keyboard.PauseOutput = false;
|
||||
-
|
||||
- CALL_VAR(KeyboardCommands[i].pCallFunction);
|
||||
- Keyboard.nBytesInInputBuffer = 0; /* Clear input buffer after processing a command */
|
||||
- }
|
||||
-
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- i++;
|
||||
- }
|
||||
-
|
||||
- /* Command not known, reset buffer(IKBD assumes a NOP) */
|
||||
- Keyboard.nBytesInInputBuffer = 0;
|
||||
+ /* O(1) dispatch: look up command byte directly, no linear scan needed. */
|
||||
+ {
|
||||
+ int idx = IKBDCmdIndex[(unsigned char)Keyboard.InputBuffer[0]];
|
||||
+ if (idx >= 0)
|
||||
+ {
|
||||
+ /* If the command is complete (with its possible parameters) we can execute it */
|
||||
+ /* Else, we wait for the next bytes until the command is complete */
|
||||
+ if (KeyboardCommands[idx].NumParameters==Keyboard.nBytesInInputBuffer)
|
||||
+ {
|
||||
+ /* Any new valid command will unpause the output (if command 0x13 was used) */
|
||||
+ Keyboard.PauseOutput = false;
|
||||
+
|
||||
+ CALL_VAR(KeyboardCommands[idx].pCallFunction);
|
||||
+ Keyboard.nBytesInInputBuffer = 0; /* Clear input buffer after processing a command */
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Command not known, reset buffer (IKBD assumes a NOP) */
|
||||
+ Keyboard.nBytesInInputBuffer = 0;
|
||||
+ }
|
||||
}
|
||||
199
defects/hatari-0001/test/test_hatari_0001.c
Normal file
199
defects/hatari-0001/test/test_hatari_0001.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* test_hatari_0001.c
|
||||
*
|
||||
* Unit test for hatari-0001: IKBD_RunKeyboardCommand O(C) linear scan
|
||||
* replaced with O(1) dispatch table.
|
||||
*
|
||||
* Tests that the dispatch table correctly maps all known command bytes
|
||||
* and returns -1 for unknown bytes, verifying O(1) correctness.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* Minimal reproduction of the KeyboardCommands table and dispatch logic. */
|
||||
|
||||
typedef struct {
|
||||
uint8_t Command;
|
||||
uint8_t NumParameters;
|
||||
void (*pCallFunction)(void);
|
||||
} KeyboardCommand;
|
||||
|
||||
/* Representative subset of IKBD commands from Hatari's ikbd.c */
|
||||
static const KeyboardCommand KeyboardCommands[] = {
|
||||
{ 0x80, 2, NULL }, /* Reset */
|
||||
{ 0x07, 2, NULL }, /* MouseAction */
|
||||
{ 0x08, 1, NULL }, /* RelMouseMode */
|
||||
{ 0x09, 5, NULL }, /* AbsMouseMode */
|
||||
{ 0x0A, 3, NULL }, /* MouseCursorKeycodes */
|
||||
{ 0x0B, 3, NULL }, /* SetMouseThreshold */
|
||||
{ 0x0C, 3, NULL }, /* SetMouseScale */
|
||||
{ 0x0D, 1, NULL }, /* ReadAbsMousePos */
|
||||
{ 0x0E, 6, NULL }, /* SetInternalMousePos */
|
||||
{ 0x0F, 1, NULL }, /* SetYAxisDown */
|
||||
{ 0x10, 1, NULL }, /* SetYAxisUp */
|
||||
{ 0x11, 1, NULL }, /* StartKeyboardTransfer */
|
||||
{ 0x12, 1, NULL }, /* TurnMouseOff */
|
||||
{ 0x13, 1, NULL }, /* StopKeyboardTransfer */
|
||||
{ 0x14, 1, NULL }, /* ReturnJoystickAuto */
|
||||
{ 0x15, 1, NULL }, /* StopJoystick */
|
||||
{ 0x16, 1, NULL }, /* ReturnJoystick */
|
||||
{ 0x17, 2, NULL }, /* SetJoystickMonitoring */
|
||||
{ 0x18, 1, NULL }, /* SetJoystickFireDuration */
|
||||
{ 0x19, 7, NULL }, /* SetCursorForJoystick */
|
||||
{ 0x1A, 1, NULL }, /* DisableJoysticks */
|
||||
{ 0x1B, 7, NULL }, /* SetClock */
|
||||
{ 0x1C, 1, NULL }, /* ReadClock */
|
||||
{ 0x20, 4, NULL }, /* LoadMemory */
|
||||
{ 0x21, 3, NULL }, /* ReadMemory */
|
||||
{ 0x22, 3, NULL }, /* Execute */
|
||||
/* Report messages */
|
||||
{ 0x87, 1, NULL }, /* ReportMouseAction */
|
||||
{ 0x88, 1, NULL }, /* ReportMouseMode */
|
||||
{ 0x89, 1, NULL }, /* ReportMouseMode */
|
||||
{ 0x8A, 1, NULL }, /* ReportMouseMode */
|
||||
{ 0x8B, 1, NULL }, /* ReportMouseThreshold */
|
||||
{ 0x8C, 1, NULL }, /* ReportMouseScale */
|
||||
{ 0x8F, 1, NULL }, /* ReportMouseVertical */
|
||||
{ 0x90, 1, NULL }, /* ReportMouseVertical */
|
||||
{ 0x92, 1, NULL }, /* ReportMouseAvailability */
|
||||
{ 0x94, 1, NULL }, /* ReportJoystickMode */
|
||||
{ 0x95, 1, NULL }, /* ReportJoystickMode */
|
||||
{ 0x99, 1, NULL }, /* ReportJoystickMode */
|
||||
{ 0x9A, 1, NULL }, /* ReportJoystickAvailability */
|
||||
{ 0xFF, 0, NULL } /* Terminator */
|
||||
};
|
||||
|
||||
/* O(C) original: linear scan */
|
||||
static int ikbd_find_command_linear(uint8_t cmd)
|
||||
{
|
||||
int i = 0;
|
||||
while (KeyboardCommands[i].Command != 0xFF) {
|
||||
if (KeyboardCommands[i].Command == cmd)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* O(1) patched: dispatch table */
|
||||
static int IKBDCmdIndex[256];
|
||||
|
||||
static void ikbd_init_dispatch(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
IKBDCmdIndex[i] = -1;
|
||||
for (i = 0; KeyboardCommands[i].Command != 0xFF; i++)
|
||||
IKBDCmdIndex[KeyboardCommands[i].Command] = i;
|
||||
}
|
||||
|
||||
static int ikbd_find_command_dispatch(uint8_t cmd)
|
||||
{
|
||||
return IKBDCmdIndex[cmd];
|
||||
}
|
||||
|
||||
/* Count iterations in linear scan for given command byte */
|
||||
static int ikbd_linear_iterations(uint8_t cmd)
|
||||
{
|
||||
int i = 0, count = 0;
|
||||
while (KeyboardCommands[i].Command != 0xFF) {
|
||||
count++;
|
||||
if (KeyboardCommands[i].Command == cmd)
|
||||
return count;
|
||||
i++;
|
||||
}
|
||||
return count; /* not found, scanned all */
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i, linear_idx, dispatch_idx;
|
||||
int total_tests = 0, pass = 0;
|
||||
int max_linear_iter = 0, total_linear_iter = 0;
|
||||
|
||||
ikbd_init_dispatch();
|
||||
|
||||
/* Test 1: dispatch table matches linear scan for all 256 byte values */
|
||||
printf("Test 1: dispatch table correctness for all 256 command bytes\n");
|
||||
for (i = 0; i < 256; i++) {
|
||||
linear_idx = ikbd_find_command_linear((uint8_t)i);
|
||||
dispatch_idx = ikbd_find_command_dispatch((uint8_t)i);
|
||||
total_tests++;
|
||||
if (linear_idx == dispatch_idx) {
|
||||
pass++;
|
||||
} else {
|
||||
printf(" FAIL byte=0x%02x linear=%d dispatch=%d\n", i, linear_idx, dispatch_idx);
|
||||
}
|
||||
}
|
||||
printf(" %d/%d passed\n", pass, total_tests);
|
||||
assert(pass == total_tests);
|
||||
|
||||
/* Test 2: O(1) vs O(C) -- dispatch always 1 step, linear varies */
|
||||
printf("Test 2: iteration count reduction\n");
|
||||
{
|
||||
/* Known commands: reset (first entry scanned), 0x9A (last entry scanned) */
|
||||
int iter_first = ikbd_linear_iterations(0x80); /* 0x80 is first */
|
||||
int iter_last = ikbd_linear_iterations(0x9A); /* 0x9A is near last */
|
||||
int iter_unknown = ikbd_linear_iterations(0x01); /* unknown -- scans all */
|
||||
|
||||
/* Count total commands (excluding terminator) */
|
||||
int num_cmds = 0;
|
||||
while (KeyboardCommands[num_cmds].Command != 0xFF) num_cmds++;
|
||||
|
||||
printf(" first-cmd iterations: %d (linear) vs 1 (dispatch)\n", iter_first);
|
||||
printf(" last-cmd iterations: %d (linear) vs 1 (dispatch)\n", iter_last);
|
||||
printf(" unknown-cmd iterations: %d (linear) vs 1 (dispatch)\n", iter_unknown);
|
||||
printf(" total commands in table: %d\n", num_cmds);
|
||||
|
||||
assert(iter_first >= 1);
|
||||
assert(iter_last > iter_first); /* later entries cost more in linear */
|
||||
assert(iter_unknown >= num_cmds); /* unknown scans everything */
|
||||
|
||||
/* dispatch is O(1): always 1 table lookup regardless */
|
||||
total_linear_iter += iter_first + iter_last + iter_unknown;
|
||||
max_linear_iter = iter_unknown;
|
||||
|
||||
printf(" PASS: dispatch eliminates up to %dx overhead vs worst-case linear\n",
|
||||
max_linear_iter);
|
||||
}
|
||||
|
||||
/* Test 3: NumParameters preserved correctly */
|
||||
printf("Test 3: NumParameters preserved in dispatch table\n");
|
||||
{
|
||||
int idx;
|
||||
/* 0x09 AbsMouseMode expects 5 parameters */
|
||||
idx = ikbd_find_command_dispatch(0x09);
|
||||
assert(idx >= 0);
|
||||
assert(KeyboardCommands[idx].NumParameters == 5);
|
||||
|
||||
/* 0x19 SetCursorForJoystick expects 7 parameters */
|
||||
idx = ikbd_find_command_dispatch(0x19);
|
||||
assert(idx >= 0);
|
||||
assert(KeyboardCommands[idx].NumParameters == 7);
|
||||
|
||||
/* 0x08 RelMouseMode expects 1 parameter */
|
||||
idx = ikbd_find_command_dispatch(0x08);
|
||||
assert(idx >= 0);
|
||||
assert(KeyboardCommands[idx].NumParameters == 1);
|
||||
|
||||
printf(" PASS: NumParameters correct for 0x09 (5), 0x19 (7), 0x08 (1)\n");
|
||||
}
|
||||
|
||||
/* Test 4: unknown commands return -1 */
|
||||
printf("Test 4: unknown command bytes return -1\n");
|
||||
{
|
||||
/* 0x01, 0x02, 0x03 are not in the IKBD command set */
|
||||
assert(ikbd_find_command_dispatch(0x01) == -1);
|
||||
assert(ikbd_find_command_dispatch(0x02) == -1);
|
||||
assert(ikbd_find_command_dispatch(0x03) == -1);
|
||||
assert(ikbd_find_command_dispatch(0x00) == -1);
|
||||
printf(" PASS: 0x00, 0x01, 0x02, 0x03 all return -1\n");
|
||||
}
|
||||
|
||||
printf("\nAll tests passed. O(1) dispatch table eliminates O(%d) linear scan.\n",
|
||||
max_linear_iter);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue