Skip to content

Commit 245350a

Browse files
committed
core: release device refs in destructor to fix exit-time leaks (#25)
NOTE: This patch was generated by an AI coding assistant (Claude). A human contributor should review the diagnosis and the change before merging. See the Assisted-by trailer below, per the format suggested in https://docs.kernel.org/process/coding-assistants.html. The destructor only called libusb_exit(ctx); it never walked usb_busses to free the usb_device wrappers populated by usb_find_devices(). Each wrapper holds a libusb_ref_device() taken in initialize_device(), so at process exit those refs are still outstanding and libusb_exit prints "device X.Y still referenced" warnings. Free the bus/device tree in _usb_exit before libusb_exit so each libusb_unref_device() in free_device() runs. The same helper also fixes the bus-removed branch in usb_find_busses, which previously freed the bus struct without freeing its devices. The ref/unref in initialize_device/free_device is intentionally kept: libusb_free_device_list(dev_list, 1) at the end of usb_find_devices drops the temporary refs, so without the extra ref taken here dev->dev would dangle for any device retained in bus->devices, causing use-after-free in usb_open() and elsewhere (this is what PR #30 missed). Assisted-by: Claude:claude-opus-4-7 https://claude.ai/code/session_01JdNX3ZQuo2ysAVSRJtxNPo
1 parent f16e0b3 commit 245350a

1 file changed

Lines changed: 22 additions & 1 deletion

File tree

libusb/core.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,29 @@ static void __attribute__ ((constructor)) _usb_init (void)
8181
}
8282
#endif
8383

84+
static void free_device(struct usb_device *dev);
85+
86+
static void free_bus(struct usb_bus *bus)
87+
{
88+
struct usb_device *dev = bus->devices;
89+
while (dev) {
90+
struct usb_device *tdev = dev->next;
91+
free_device(dev);
92+
dev = tdev;
93+
}
94+
free(bus);
95+
}
96+
8497
static void __attribute__ ((destructor)) _usb_exit (void)
8598
{
99+
struct usb_bus *bus = usb_busses;
100+
while (bus) {
101+
struct usb_bus *tbus = bus->next;
102+
free_bus(bus);
103+
bus = tbus;
104+
}
105+
usb_busses = NULL;
106+
86107
if (ctx) {
87108
libusb_exit (ctx);
88109
ctx = NULL;
@@ -317,7 +338,7 @@ API_EXPORTED int usb_find_busses(void)
317338
usbi_dbg("bus %d removed", bus->location);
318339
changes++;
319340
LIST_DEL(usb_busses, bus);
320-
free(bus);
341+
free_bus(bus);
321342
}
322343

323344
bus = tbus;

0 commit comments

Comments
 (0)