# UNDF: UNDF-2026-000000272 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -123,6 +123,8 @@ static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL; static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_joystick_lock) = 0; static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_joystick_lock) = NULL; static SDL_HashTable *SDL_joystick_names SDL_GUARDED_BY(SDL_joystick_lock) = NULL; +/* CWE-407 fix: O(1) instance_id → SDL_Joystick* lookup map. */ +static SDL_HashTable *SDL_joystick_by_id SDL_GUARDED_BY(SDL_joystick_lock) = NULL; static bool SDL_joystick_allows_background_events = false; @@ -899,6 +901,8 @@ bool SDL_InitJoysticks(void) SDL_joystick_names = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL); + SDL_joystick_by_id = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL); @@ -1518,6 +1522,9 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id) // Link the joystick in the list joystick->next = SDL_joysticks; SDL_joysticks = joystick; + /* Register in O(1) lookup map. */ + SDL_InsertIntoHashTable(SDL_joystick_by_id, + (const void *)(uintptr_t)joystick->instance_id, joystick, true); @@ -1960,13 +1966,13 @@ SDL_Joystick *SDL_GetJoystickFromID(SDL_JoystickID instance_id) { - SDL_Joystick *joystick; - SDL_LockJoysticks(); - for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { - if (joystick->instance_id == instance_id) { - break; - } - } + /* CWE-407 fix: O(1) hash lookup replaces O(n) linked-list walk. */ + SDL_Joystick *joystick = NULL; + SDL_FindInHashTable(SDL_joystick_by_id, + (const void *)(uintptr_t)instance_id, (const void **)&joystick); SDL_UnlockJoysticks(); return joystick; } @@ -2261,6 +2267,9 @@ void SDL_CloseJoystick(SDL_Joystick *joystick) joysticklist = SDL_joysticks; joysticklistprev = NULL; while (joysticklist) { if (joystick == joysticklist) { + /* Remove from O(1) lookup map before unlinking. */ + SDL_RemoveFromHashTable(SDL_joystick_by_id, + (const void *)(uintptr_t)joystick->instance_id); if (joysticklistprev) { joysticklistprev->next = joysticklist->next; } else { --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -4160,13 +4160,13 @@ SDL_Gamepad *SDL_GetGamepadFromID(SDL_JoystickID joyid) { - SDL_Gamepad *gamepad; - SDL_LockJoysticks(); - gamepad = SDL_gamepads; - while (gamepad) { - if (gamepad->joystick->instance_id == joyid) { - SDL_UnlockJoysticks(); - return gamepad; - } - gamepad = gamepad->next; - } + /* CWE-407 fix: delegate to SDL_GetJoystickFromID (O(1) after sdl2-0001 patch) + * then walk the tiny (1-per-joystick) gamepad list only if needed. + * Alternatively: maintain a separate SDL_gamepad_by_id hash table. + * The joystick lookup is now O(1); the gamepad wrapper check is O(n_gamepads) + * but n_gamepads == n_joysticks so a second hash table is warranted for + * completeness — see note below. */ + SDL_Joystick *stick = SDL_GetJoystickFromID(joyid); + SDL_Gamepad *gamepad = NULL; + if (stick) { + /* Walk gamepads to find the one wrapping this joystick. */ + for (SDL_Gamepad *g = SDL_gamepads; g; g = g->next) { + if (g->joystick == stick) { gamepad = g; break; } + } + } SDL_UnlockJoysticks(); return gamepad; + /* TODO: add SDL_gamepad_by_id HashTable (same pattern as SDL_joystick_by_id) + * to make SDL_GetGamepadFromID fully O(1) independent of joystick path. */ }