NVML device handle cached at discovery → native access violation (0xc0000005) when the GPU is restarted
Stale NVML device handle causes access violation when NVIDIA GPU is restarted or removed
Description
NvidiaGpu acquires its NVML device handle once during construction and stores it in _nvmlDevice. Update() subsequently passes this cached handle to NvidiaML.NvmlDeviceGetPowerUsage.
If the NVIDIA GPU is restarted or removed while LibreHardwareMonitor is polling it (for example, via pnputil /restart-device or during hybrid/eject transitions), the cached handle can become stale. The subsequent native call may then fault inside nvml.dll.
This results in an uncatchable access violation that terminates the host process. The try/catch inside NvidiaML.NvmlDeviceGetPowerUsage cannot intercept the native fault.
Environment
- Windows 11
- .NET 9
- LibreHardwareMonitorLib (
net9.0) - NVIDIA dGPU
Steps to Reproduce
Start LibreHardwareMonitor, or another host that polls LibreHardwareMonitor at approximately 1-second intervals.
Restart the NVIDIA GPU using:
pnputil /restart-device "<gpuInstanceId>"Observe the process during the device removal/reinitialization window.
Expected Behavior
Sensor updates are skipped while the NVIDIA device is temporarily unavailable, and polling resumes once the device becomes available again.
Actual Behavior
The host process terminates due to an access violation in the NVML native call.
Evidence
Application Error:
Faulting module: coreclr.dll
Exception code: 0xc0000005.NET Runtime:
The process was terminated due to an unhandled exception.Relevant stack:
at LibreHardwareMonitor.Interop.NvidiaML.NvmlDeviceGetPowerUsage(NvmlDevice)
at LibreHardwareMonitor.Hardware.Gpu.NvidiaGpu.Update()Root Cause
In Hardware/Gpu/NvidiaGpu.cs, _nvmlDevice is assigned once in the constructor using an NVML device lookup such as:
NvmlDeviceGetHandleByPciBusIdNvmlDeviceGetHandleByIndex
The cached handle is then used by Update() without revalidation.
When the GPU is restarted or temporarily removed, the previously acquired NVML handle may no longer be valid. Although NVML can return a failure NvmlReturn when a device is currently absent, passing a stale handle can instead cause the native code to fault before a return value is produced.
Therefore, the exception cannot reliably be handled by the managed try/catch surrounding the NVML call.
Suggested Fix
Re-acquire the NVML device handle immediately before using it rather than relying on the handle acquired during construction.
The device's PCI bus ID can be captured during construction and used to re-acquire the handle before each update, with adapter index as a fallback if necessary.
If re-acquisition fails or returns null, skip the NVML-dependent sensors for that update instead of calling NVML with the stale handle.
A short-term mitigation could also invalidate _nvmlDevice during Close().
This would make a temporarily missing GPU result in a clean no-op rather than a stale-handle native access violation.
The approach mirrors the existing handle re-acquisition pattern in:
Hardware/Battery/Battery.csSee commit 9e54127.
Source: LibreHardwareMonitor/LibreHardwareMonitor