Guard against registry values that disappear mid-read - #76
Open
dcalonego wants to merge 1 commit into
Open
Conversation
Rem0o
reviewed
Aug 28, 2026
|
|
||
| internal HWInfoRegistryUpdateResult UpdateValues(HWInfoPluginSensor[] sensors) | ||
| { | ||
| // The key can be closed between two update cycles, for instance when Close() |
Owner
There was a problem hiding this comment.
Update() after Close() is technically impossible, as it is done under lock upstream.
Contributor
Author
There was a problem hiding this comment.
Removed, thanks. I inferred that race from reading the plugin in isolation, with no visibility into the locking upstream.
The other two guards are a different race: GetValueNames() and GetValue() are separate calls, so GetValue can return null for a name listed a moment earlier and GetSensorType calls Trim() on it. Happy to drop those too if you'd rather not carry the check.
HWiNFO rewrites the VSB key on every polling cycle, so a value name returned by GetValueNames() can already be gone when GetValue() runs a moment later. - GetSensorType cast the result to string and called Trim() on it. When the value had disappeared the cast produced null and the call threw a NullReferenceException, which propagated out of Load(). - GetId has the same race on the same value, through .ToString(). GetId falls back to an empty unit, which is the same string the existing "?? string.Empty" produces for a value with no unit, so sensor ids stay byte-identical and references in saved configurations keep resolving. Also drops the unused exception variable in IsActive() (warning CS0168).
dcalonego
force-pushed
the
fix/null-safety
branch
from
August 29, 2026 10:04
bef3704 to
97e136e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three null dereferences that can each take down the plugin, plus one compiler warning.
The races
HWiNFO rewrites the VSB key on every polling cycle. A value name returned by
GetValueNames()can already be gone by the timeGetValue()runs a moment later.GetSensorTypecast the result tostringand immediately calledTrim():The cast yields
nullrather than throwing, so the exception surfaces on the next line and propagates out ofLoad().GetIdhas the same race on the same value, via.ToString().UpdateValuesdereferenced_keywith no check.Dispose()sets_key = null, so an update cycle overlapping aClose()throws inside FanControl's update loop.On sensor ids
GetIdnow falls back to an empty unit. That is the same string the existing?? string.Emptyalready produces for a value with no unit, so ids stay byte-identical and references stored in user configurations keep resolving. This mattered enough to double-check, since a changed id silently orphans a fan curve.Also
Drops the unused
exceptionvariable inIsActive().mastercurrently builds with one warning:After this change the project builds clean.
Testing
Built against
master, exercised through a harness against a live HWiNFO instance: 47 sensors, 15 update cycles, 0 exceptions. The races themselves are timing-dependent and I did not manage to reproduce them on demand — these are guards against a failure mode visible in the code, not a fix for an observed crash.