Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix leaking udev reference in LinuxUsbDevice #1678

Merged
merged 2 commits into from Jul 7, 2021

Conversation

mattmacleod
Copy link
Contributor

This change fixes a leaking device reference in the Linux USB device implementation. When an interface device is encountered (i.e. devtype is "usb_device") the rest of the loop was skipped and the allocated device would never be unreferenced. This change adds an additional explicit unreference in this case.

This was the underlying leak causing the issue reported by @botto in #1670

@dbwiddis
Copy link
Member

dbwiddis commented Jul 6, 2021

Gah, good find. I should have seen that when looking at #1670.

Your fix doesn't handle the case where udev_device_new_from_syspath returns null (which would be caught in the existing conditional check) and you'd try to unref that. I suppose the native code wouldn't care but it's still somewhat sloppy.

This whole class could use a refactoring, if you wouldn't mind putting in a bit more work here:

  • I'd prefer to use a try - finally approach to defensively handle references with exceptions (and continue and return)
  • I wrote this code 5 years ago and since then I've contributed a more object-oriented front end to JNA. See the LinuxHWDiskStore class getDisks() method, code starting at line 168.

At a minimum please change your PR to do something like this pattern:

UdevDevice dev = Udev.INSTANCE.udev_device_new_from_syspath(udev, path);
if (dev != null) {
    try {
        // existing code between new and unref
    } finally {
        Udev.INSTANCE.udev_device_unref(dev);
    }
}

However, if you can refactor to the example in LinuxHWDiskStore it'd be even better.

This change fixes a leaking udev device reference when enumerating
devices. Devices with a devtype that was not "usb_device" were never
freed during the enumeration.

The enumeration process has been refactored (in line with the
implementation in LinuxHWDiskStore) to use the more object-oriented
API for udev that's now available from JNA.
@mattmacleod
Copy link
Contributor Author

Thanks for the pointers @dbwiddis – I have updated the PR to reflect the approach used in LinuxHWDiskStore as suggested. Confirmed that this still functions as expected in my use-case, and that it doesn't leak any more. Please let me know if you'd like any tweaks.

@dbwiddis dbwiddis linked an issue Jul 7, 2021 that may be closed by this pull request
Copy link
Member

@dbwiddis dbwiddis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This looks great and I'll go ahead and merge it.

for (UdevListEntry dev_list_entry = devices; dev_list_entry != null; dev_list_entry = Udev.INSTANCE
.udev_list_entry_get_next(dev_list_entry)) {
// Enumerate all usb devices and build information maps
Udev.UdevContext udev = Udev.INSTANCE.udev_new();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I see that it's possible to return null if the native call fails, but of the four times we call this, we only null check one of them. No need to change this PR for that but I'll have to think about whether we should update all of them.

// Enumerate all usb devices and build information maps
Udev.UdevContext udev = Udev.INSTANCE.udev_new();
try {
UdevEnumerate enumerate = udev.enumerateNew();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to udev_new this can theoretically return null but probably never will. Something to think about for a future fix.

@dbwiddis dbwiddis merged commit d6e49c4 into oshi:master Jul 7, 2021
@mattmacleod mattmacleod deleted the fix-usb-memory-leak branch July 8, 2021 14:16
dbwiddis pushed a commit that referenced this pull request Jul 18, 2021
* Refactor LinuxUsbDevice to fix leaking reference

This change fixes a leaking udev device reference when enumerating
devices. Devices with a devtype that was not "usb_device" were never
freed during the enumeration.

The enumeration process has been refactored (in line with the
implementation in LinuxHWDiskStore) to use the more object-oriented
API for udev that's now available from JNA.

* Update changelog
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Memory leak in getUsbDevices
2 participants