A zeroed control map matches gamepad South, and a NULL handler_off segfaults on release #81
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Source: found sweeping for stale
TODO.mdreferences; the tutorials warn about both, and neither had an issue (atad71072)Two defects in
akgl_controller_handle_event(src/controller.c) that a caller meets together,because both are properties of filling in an
akgl_ControlMapentry.1. A zeroed
buttonfield is a real button. The two arms of the match are evaluated as oneexpression (
src/controller.c:312-321):SDL_GAMEPAD_BUTTON_SOUTHis 0. So a keyboard-only binding, declared as a stack local andzeroed the way every example does it, also matches every press of A/Cross on any gamepad --
jsid == 0matches any device, andbutton == 0matches the south face button. The bindingfires for an input its author never named.
The tutorial already documents the workaround, which is what says this is a real trap rather
than a theoretical one: Chapter 21 tells the reader to "set
buttonto
SDL_GAMEPAD_BUTTON_INVALID" because "the keyboard and gamepad arms of the match areevaluated together, and 0 is a real button." A default that has to be written out in prose is a
default in the wrong place.
Fix, and it is a decision rather than an obvious patch.
SDL_GAMEPAD_BUTTON_INVALIDis -1,so the field cannot simply default to it in a zeroed struct. Either the match requires the event
kind to have been declared (an explicit
kindon the control), or the arms test the field thatidentifies the binding rather than trusting a sentinel. The wildcard-device work took the first
approach for
jsid/kbidby spending 0 deliberately; that reasoning does not carry here,because 0 is not free on
button.2.
handler_onandhandler_offare called without a NULL check (src/controller.c:323and
:326):A control that acts on press and has nothing to do on release is the ordinary case, and it
segfaults on the first key release. The tutorial's answer is to install
jrpg_cmhf_ignore, ahandler that does nothing -- so every consumer writes the same empty function.
Fix: check both pointers, and treat a NULL handler as "nothing to do" rather than as an
error. That is what the caller means by leaving it NULL, and it deletes the do-nothing handler
from every consumer.
Tests:
tests/controller.cdispatches a gamepad south-button press at a keyboard-onlybinding and asserts it does not fire; and dispatches a key release at a control with a NULL
handler_offand asserts it returns rather than crashing. Both fail against the current code.Filed by Tachikoma (Claude Code, Opus 5, 1M context)