Summary
The hotplug callback documentation added in #790 specifies:
The device->next pointer is always NULL. Each callback invocation describes exactly one device; compound or composite devices that expose multiple interfaces produce multiple callback invocations (typically delivered in quick succession).
The current implementation does not enforce this on all backends. The libusb backend has an explicit TODO acknowledging it — https://github.com/libusb/hidapi/blob/connection-callback/libusb/hid.c#L1123 — and when the enumerated list is iterated each entry is passed to the callback with its sibling `next` pointer still set, exposing the internal list layout to user code.
Proposed fix
In each backend's callback dispatch path, copy the `hid_device_info` into a local struct with `.next = NULL` before invoking the user callback:
```c
struct hid_device_info info_copy = *info;
info_copy.next = NULL;
callback(handle, &info_copy, event, user_data);
```
No strings need to be duplicated (they remain valid for the duration of the callback). This prevents user code from traversing HIDAPI's internal list and keeps the public contract honest.
Scope
- `libusb/hid.c` (`hid_internal_invoke_callbacks` and the `HID_API_HOTPLUG_ENUMERATE` path in `hid_hotplug_register_callback`).
- `linux/hid.c`, `mac/hid.c`, `windows/hid.c` — same audit.
Related
Drafted with Claude Code.
Summary
The hotplug callback documentation added in #790 specifies:
The current implementation does not enforce this on all backends. The libusb backend has an explicit TODO acknowledging it — https://github.com/libusb/hidapi/blob/connection-callback/libusb/hid.c#L1123 — and when the enumerated list is iterated each entry is passed to the callback with its sibling `next` pointer still set, exposing the internal list layout to user code.
Proposed fix
In each backend's callback dispatch path, copy the `hid_device_info` into a local struct with `.next = NULL` before invoking the user callback:
```c
struct hid_device_info info_copy = *info;
info_copy.next = NULL;
callback(handle, &info_copy, event, user_data);
```
No strings need to be duplicated (they remain valid for the duration of the callback). This prevents user code from traversing HIDAPI's internal list and keeps the public contract honest.
Scope
Related
Drafted with Claude Code.