Утечка памяти с Libusb
Я портировал библиотеку с Linux на Windows, и во время отладки я обнаружил, что в Windows (по крайней мере, на моей машине) функция горячего подключения не поддерживается.
Итак, я решил создать обходной путь, вместо того, чтобы сильно изменять библиотеку, я взял на себя задачу эмулировать события hotplug.
Я почти завершил свою программу, но обнаружил, что у меня утечка памяти (монитор ресурсов VS2015 показывает постоянное увеличение использования оперативной памяти). Я сузился до цикла hm_monitor, но я не могу найти, где ошибка.
Средства диагностики показали, что утечка памяти происходит из Libusb-dll. образ
int delete_device(libusb_device* dev, libusb_device** list, size_t* count) {
libusb_unref_device(dev);
size_t i;
int res = 0;
for (i = 0; i < *count; i++)
if (list[i] == dev) {
list[i] = list[(*count) - 1];
list[*count] = 0;
(*count)--;
res = 1;
break;
}
return res;
}
int add_device(libusb_device* dev, libusb_device** list, size_t* count) {
libusb_ref_device(dev);
if (*count >= MAX_DEVICES)
return 0;
list[*count] = dev;
(*count)++;
return 1;
}
thrd_start_t hm_monitor(void* data) {
int r; //for return values
size_t i; //user for for loops
ssize_t cnt; //holding number of devices in list
hm_data_t d = (hm_data_t)data;
libusb_device *old_devs[MAX_DEVICES] = { 0 };
size_t old_count = 0;
libusb_device **devs; //pointer to pointer of device, used to retrieve a list of devices
//while hm_stop is not called
while (!d->stop) {
//getting connected device list
cnt = libusb_get_device_list(d->ctx, &devs);
if (cnt < 0) {
stop_thread(-1);//end monitor prematurely because error
}
//loop devs to find new devices
for (i = 0; i < cnt; i++) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(devs[i], &desc);
if (r < 0) //if device descriptor is unaccessable
continue; //ignore it
if (desc.idVendor == 0 || desc.idProduct == 0) //ghost device
continue; //ignore it;
if (!find_device(devs[i], old_devs, old_count)) { //if the device was just connected
//add device to the old_devs
r = add_device(devs[i], old_devs, &old_count);
if (!r) //if we could not add a device
stop_thread(-6);
//Call on_arrived callbacks
int c;
for (c = 0; c < hm_state.cb_count; c++) {
if (hm_state.callbacks[c].fn && (hm_state.callbacks[c].dev_class == (int)desc.bDeviceClass || hm_state.callbacks[c].dev_class == -1)
&& (hm_state.callbacks[c].vendor_id == (int)desc.idVendor || hm_state.callbacks[c].vendor_id == -1)
&& (hm_state.callbacks[c].product_id == (int)desc.idProduct || hm_state.callbacks[c].product_id == -1))
if (hm_state.callbacks[c].events | LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
hm_state.callbacks[c].fn(d->ctx, devs[i], LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, data);
}
}
}
for (i = 0; i < old_count; i++) {
struct libusb_device_descriptor desc;
r = libusb_get_device_descriptor(old_devs[i], &desc);
if (r < 0) // if somehow a device like this ended up in old_dev, delete it
{
delete_device(old_devs[i], old_devs, &old_count);
continue;
}
if (desc.idVendor == 0 || desc.idProduct == 0)
{
delete_device(old_devs[i], old_devs, &old_count);
continue;
}
if (!find_device(old_devs[i], devs, cnt)) {
int c;
for (c = 0; c < hm_state.cb_count; c++) {
if (hm_state.callbacks[c].fn && (hm_state.callbacks[c].dev_class == (int)desc.bDeviceClass || hm_state.callbacks[c].dev_class == -1)
&& (hm_state.callbacks[c].vendor_id == (int)desc.idVendor || hm_state.callbacks[c].vendor_id == -1)
&& (hm_state.callbacks[c].product_id == (int)desc.idProduct || hm_state.callbacks[c].product_id == -1))
if (hm_state.callbacks[c].events | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
hm_state.callbacks[c].fn(d->ctx, old_devs[i], LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, data);
}
//remove device from the list
delete_device(old_devs[i], old_devs, &old_count);
}
}
libusb_free_device_list(devs, 1); //free the list, do not unref devices becuase we unref them when they leave.
}//END LOOP HERE
}
Список источников: страница gitlab.
Изменить: добавлен соответствующий код к вопросу.