Fix GamepadUSBHostListener::unmount() not checking dev_addr#1680
Merged
arntsonl merged 1 commit intoJul 20, 2026
Merged
Conversation
arntsonl
approved these changes
Jul 20, 2026
Contributor
There was a problem hiding this comment.
Nice catch! Yep that's a bug in the gamepad usb host listener, we should absolutely be looking for this,
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GamepadUSBHostListener::unmount()shuts down and deletes_controller_hostwhenever it's non-null, without ever checking that thedev_addrbeing unmounted is the one it's actually hosting. Every other callback in this class (report_received,set_report_complete,get_report_complete) does compare_controller_dev_addr == dev_addrbefore touching the host, so this one method is the odd one out.The reason this actually bites:
USBHostManagerbroadcasts every HID/XInput unmount callback to all registered listeners, not just the one that owns that device. If someone has both the Keyboard Host addon and the Gamepad USB Host addon enabled (e.g. a hub feeding a keyboard/mouse plus a PS4/PS5/Switch Pro controller into the same host port), unplugging the keyboard firesunmount(keyboard_dev_addr)on every listener, includingGamepadUSBHostListener. Since it never checks the address, it tears down its own still-connected controller session in response to an unrelated device going away — the controller has to be physically replugged to come back.KeyboardHostListener::unmount()already handles this correctly by comparing against its own_keyboard_dev_addr/_mouse_dev_addr, and there's precedent for this exact class of bug being fixed there before (#1177).GamepadUSBHostListeneris a newer file (from the USB Host Rework in #1672) that just never got the same guard added.Fix is one line, adding the same address check the sibling methods already use:
I don't have the pico-sdk/arm-none-eabi toolchain set up locally to build the full firmware, so I verified this with a small native harness instead: copied the current
unmount()body and theUSBHostManagerbroadcast loop verbatim into a standalone C++ program, mounted a fake keyboard and a fake controller with different dev_addrs, then fed the keyboard's dev_addr through the same broadcast-to-all-listeners path the real firmware uses. With the current code the controller host gets destroyed even though it wasn't the device that unmounted; with the one-line fix it's left alone, and unmounting the controller's own dev_addr still tears it down correctly.