From 785aa4bc9d5989ad0653549d3949d280037f829a Mon Sep 17 00:00:00 2001 From: Rocker Zhang Date: Fri, 5 Jun 2026 00:55:35 +0800 Subject: [PATCH] Fix udev enumerator leaks and a NULL-check bug nvtop_device_get_hwmon() and the intel/v3d gpuinfo_*_get_device_handles() functions return early when a udev enumerator API call fails, but those early returns never release the enumerator, leaking the udev handle and the udev_enumerate object. In nvtop_device_get_hwmon() the no-hwmon path is reached for every device without an hwmon node, so it leaks on a normal startup, not just on error. Route the early exits through a single nvtop_enumerator_unref() using the goto-cleanup pattern already used in nvtop_enumerator_new(). nvtop_enumerator_new() also tested the address of the caller's pointer, which is never NULL, instead of the calloc() result. An allocation failure would therefore fall through and dereference a NULL pointer instead of returning -1; check *enumerator instead. --- src/device_discovery_linux.c | 12 +++++++----- src/extract_gpuinfo_intel.c | 13 ++++++++----- src/extract_gpuinfo_v3d.c | 13 ++++++++----- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/device_discovery_linux.c b/src/device_discovery_linux.c index 1c5e5df4..9661a4ce 100644 --- a/src/device_discovery_linux.c +++ b/src/device_discovery_linux.c @@ -97,7 +97,7 @@ int nvtop_device_get_syspath(nvtop_device *device, const char **sysPath) { int nvtop_enumerator_new(nvtop_device_enumerator **enumerator) { *enumerator = calloc(1, sizeof(**enumerator)); - if (!enumerator) + if (!*enumerator) return -1; (*enumerator)->refCount = 1; (*enumerator)->udev = udev_new(); @@ -342,16 +342,18 @@ nvtop_device *nvtop_device_get_hwmon(nvtop_device *dev) { int ret = nvtop_enumerator_new(&enumerator); if (ret < 0) return NULL; + nvtop_device *hwmon = NULL; ret = nvtop_device_enumerator_add_match_subsystem(enumerator, "hwmon", true); if (ret < 0) - return NULL; + goto out; ret = nvtop_device_enumerator_add_match_parent(enumerator, dev); if (ret < 0) - return NULL; - nvtop_device *hwmon = nvtop_enumerator_get_device_first(enumerator); + goto out; + hwmon = nvtop_enumerator_get_device_first(enumerator); if (!hwmon) - return NULL; + goto out; nvtop_device_ref(hwmon); +out: nvtop_enumerator_unref(enumerator); return hwmon; } diff --git a/src/extract_gpuinfo_intel.c b/src/extract_gpuinfo_intel.c index b80b4f0a..8ff2eb97 100644 --- a/src/extract_gpuinfo_intel.c +++ b/src/extract_gpuinfo_intel.c @@ -130,13 +130,14 @@ bool gpuinfo_intel_get_device_handles(struct list_head *devices_list, unsigned * if (nvtop_enumerator_new(&enumerator) < 0) return false; + bool ret = false; + unsigned num_devices = 0; if (nvtop_device_enumerator_add_match_subsystem(enumerator, "drm", true) < 0) - return false; + goto out; if (nvtop_device_enumerator_add_match_property(enumerator, "DEVNAME", "/dev/dri/*") < 0) - return false; + goto out; - unsigned num_devices = 0; for (nvtop_device *device = nvtop_enumerator_get_device_first(enumerator); device; device = nvtop_enumerator_get_device_next(enumerator)) { num_devices++; @@ -144,7 +145,7 @@ bool gpuinfo_intel_get_device_handles(struct list_head *devices_list, unsigned * gpu_infos = calloc(num_devices, sizeof(*gpu_infos)); if (!gpu_infos) - return false; + goto out; for (nvtop_device *device = nvtop_enumerator_get_device_first(enumerator); device; device = nvtop_enumerator_get_device_next(enumerator)) { @@ -157,8 +158,10 @@ bool gpuinfo_intel_get_device_handles(struct list_head *devices_list, unsigned * } } + ret = true; +out: nvtop_enumerator_unref(enumerator); - return true; + return ret; } void gpuinfo_intel_populate_static_info(struct gpu_info *_gpu_info) { diff --git a/src/extract_gpuinfo_v3d.c b/src/extract_gpuinfo_v3d.c index c92757c0..6fc06c9e 100644 --- a/src/extract_gpuinfo_v3d.c +++ b/src/extract_gpuinfo_v3d.c @@ -220,13 +220,14 @@ bool gpuinfo_v3d_get_device_handles(struct list_head *devices_list, unsigned *co if (nvtop_enumerator_new(&enumerator) < 0) return false; + bool ret = false; + unsigned num_devices = 0; if (nvtop_device_enumerator_add_match_subsystem(enumerator, "drm", true) < 0) - return false; + goto out; if (nvtop_device_enumerator_add_match_property(enumerator, "DEVNAME", "/dev/dri/*") < 0) - return false; + goto out; - unsigned num_devices = 0; for (nvtop_device *device = nvtop_enumerator_get_device_first(enumerator); device; device = nvtop_enumerator_get_device_next(enumerator)) { num_devices++; @@ -234,7 +235,7 @@ bool gpuinfo_v3d_get_device_handles(struct list_head *devices_list, unsigned *co gpu_infos = calloc(num_devices, sizeof(*gpu_infos)); if (!gpu_infos) - return false; + goto out; for (nvtop_device *device = nvtop_enumerator_get_device_first(enumerator); device; device = nvtop_enumerator_get_device_next(enumerator)) { @@ -247,8 +248,10 @@ bool gpuinfo_v3d_get_device_handles(struct list_head *devices_list, unsigned *co } } + ret = true; +out: nvtop_enumerator_unref(enumerator); - return true; + return ret; } void gpuinfo_v3d_populate_static_info(struct gpu_info *_gpu_info) {