Skip to content

fix: audit findings — memory leaks, silent catches, UI flicker, consistency#601

Merged
laurentiu021 merged 2 commits into
mainfrom
fix/audit-findings
May 29, 2026
Merged

fix: audit findings — memory leaks, silent catches, UI flicker, consistency#601
laurentiu021 merged 2 commits into
mainfrom
fix/audit-findings

Conversation

@laurentiu021
Copy link
Copy Markdown
Owner

@laurentiu021 laurentiu021 commented May 29, 2026

Summary

Fixes all High and Medium findings from the full audit run:

  • AboutViewModel (5 locations) — ManagementObject instances in foreach loops now disposed via using (mo). Prevents COM object leaks.
  • ThemeService (2 locations) — empty catch { } blocks now log errors via Serilog. Prevents silent disk/permission failures.
  • DashboardViewModel (4 locations) — bare catch (Exception) in alert scanners now log the exception message for diagnostics.
  • BulkInstallerViewModelFilteredApps converted from ObservableCollection to BulkObservableCollection with ReplaceWith(). Eliminates N+1 change notifications (UI flicker on filter).
  • ShortcutCleanerView — DataGrid now has Background="Transparent" and BorderThickness="0" matching all other views in the app.

Test plan

  • About tab: "Copy environment info" still works (WMI queries complete without error)
  • Theme switching: change theme, restart app — settings persist (ThemeService save/load works)
  • Dashboard: system alerts still load (no regression from catch changes)
  • Bulk Installer: filter text works without visible flicker
  • Shortcut Cleaner: DataGrid blends with dark background (no white border/bg)

Summary by CodeRabbit

  • Bug Fixes

    • Fixed memory leaks in system information queries that could accumulate during extended application runtime
    • Improved installer UI responsiveness by optimizing how filtered application lists are updated during bulk package operations
    • Enhanced error handling and diagnostics across theme persistence, GPU detection, and system health scans
  • Style

    • Minor visual refinements to shortcut cleaner interface

Review Change Stack

…stency

- AboutViewModel: dispose ManagementObject in all 5 WMI loops
- ThemeService: log errors instead of empty catch blocks
- DashboardViewModel: replace bare catch(Exception) with logged exceptions
- BulkInstallerViewModel: FilteredApps → BulkObservableCollection
- ShortcutCleanerView: DataGrid Background/BorderThickness fix
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

📝 Walkthrough

Walkthrough

Version 1.17.2 patch adds exception logging to theme service and dashboard alert scanners, wraps WMI ManagementObject queries in using blocks to fix memory leaks, converts BulkInstallerViewModel.FilteredApps to BulkObservableCollection with batch update support, and updates build metadata and changelog documentation.

Changes

Release 1.17.2 maintenance patch

Layer / File(s) Summary
Exception logging in services and view models
SysManager/SysManager/Services/ThemeService.cs, SysManager/SysManager/ViewModels/DashboardViewModel.cs
ThemeService adds Serilog import and replaces silent catch blocks in Save() and Load() with debug log calls. DashboardViewModel adds exception capture and debug logging in UpdateGpuUsage() and alert scan methods (ScanAppUpdatesAsync(), ScanEventLogAsync(), ScanWindowsFeaturesAsync()), preserving existing UI fallback behavior.
WMI ManagementObject resource cleanup in AboutViewModel
SysManager/SysManager/ViewModels/AboutViewModel.cs
All WMI enumeration loops for CPU, RAM, GPU, display resolution, and Windows information collection now wrap each ManagementObject in using (mo) blocks; field extraction, formatting, and break-on-match logic remain unchanged.
BulkObservableCollection refactor in BulkInstallerViewModel
SysManager/SysManager/ViewModels/BulkInstallerViewModel.cs
FilteredApps property retyped from ObservableCollection<InstallableApp> to BulkObservableCollection<InstallableApp>. ApplyFilter() switches to ReplaceWith(filtered) for batch updates instead of clearing and re-adding items individually.
Version bump and documentation updates
SysManager/SysManager/SysManager.csproj, CHANGELOG.md, SysManager/SysManager/Views/ShortcutCleanerView.xaml
Version properties (Version, FileVersion, AssemblyVersion) updated from 1.17.1 to 1.17.2. CHANGELOG documents all fixes: WMI disposal, exception logging, ObservableCollection conversion, and DataGrid styling. ShortcutCleanerView XAML realigned with no property changes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A rabbit's tale of 1.17.2:
Where WMI objects now safely dispose,
Exceptions are logged, no silent throes,
And UI collections batch their flows—
Less memory leaks, less flickering shows!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes all major categories of fixes: memory leaks (WMI disposal), silent catches (logging), UI flicker (BulkObservableCollection), and consistency (styling). It is concise, specific, and directly reflects the changeset content.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/audit-findings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link
Copy Markdown

⚠️ JUnit XML file not found

The CLI was unable to find any JUnit XML files to upload.
For more help, visit our troubleshooting guide.

File.WriteAllText(SettingsPath, json);
}
catch { }
catch (Exception ex) { Log.Debug("Theme save failed: {Error}", ex.Message); }
}
}
catch { }
catch (Exception ex) { Log.Debug("Theme load failed: {Error}", ex.Message); }
}
catch (Exception)
catch (Exception ex) { Log.Debug("Alert scan failed: {Error}", ex.Message); }//
{
}
catch (Exception)
catch (Exception ex) { Log.Debug("Alert scan failed: {Error}", ex.Message); }//
{
}
catch (Exception)
catch (Exception ex) { Log.Debug("Alert scan failed: {Error}", ex.Message); }//
{
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
SysManager/SysManager/ViewModels/DashboardViewModel.cs (3)

461-468: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical syntax error: fallback block is not inside the catch.

Identical issue to lines 373 and 428. The catch at line 461 contains only the Log.Debug call; lines 462-468 form an unconditional block that always runs, forcing the Windows features alert to "unavailable" even when the scan succeeds.

🐛 Proposed fix: move fallback code inside catch block
-        catch (Exception ex) { Log.Debug("Alert scan failed: {Error}", ex.Message); }//
-        {
+        catch (Exception ex)
+        {
+            Log.Debug("Alert scan failed: {Error}", ex.Message);
             System.Windows.Application.Current?.Dispatcher.BeginInvoke(() =>
             {
                 alert.Title = "Feature check unavailable";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/ViewModels/DashboardViewModel.cs` around lines 461 -
468, The fallback block that sets alert.Title and alert.Severity is currently
outside the catch and always executes; move that Dispatcher.BeginInvoke block
inside the catch for the exception handler so the fallback runs only when the
catch in DashboardViewModel (the catch handling "Alert scan failed") is
triggered—i.e., ensure the catch block contains both Log.Debug("Alert scan
failed: {Error}", ex.Message) and the
System.Windows.Application.Current?.Dispatcher.BeginInvoke(...) block so the
"Feature check unavailable" alert is only set on exceptions.

428-435: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical syntax error: fallback block is not inside the catch.

Identical issue to line 373. The catch at line 428 contains only the Log.Debug call; lines 429-435 form an unconditional block that always runs, forcing the Event Log alert to "unavailable" even when the scan succeeds.

🐛 Proposed fix: move fallback code inside catch block
-        catch (Exception ex) { Log.Debug("Alert scan failed: {Error}", ex.Message); }//
-        {
+        catch (Exception ex)
+        {
+            Log.Debug("Alert scan failed: {Error}", ex.Message);
             System.Windows.Application.Current?.Dispatcher.BeginInvoke(() =>
             {
                 alert.Title = "Event Log check unavailable";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/ViewModels/DashboardViewModel.cs` around lines 428 -
435, The fallback block that sets alert.Title and alert.Severity is placed
outside the catch and thus always executes; move the block currently after the
catch (the System.Windows.Application.Current?.Dispatcher.BeginInvoke(...) that
sets alert.Title = "Event Log check unavailable" and alert.Severity =
AlertSeverity.Green) inside the catch that contains Log.Debug("Alert scan
failed: {Error}", ex.Message) so that it only runs when an exception occurs, and
remove the stray unconditional braces; locate this in DashboardViewModel.cs
around the catch that logs via Log.Debug and wrap the Dispatcher.BeginInvoke
fallback inside that catch.

373-380: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical syntax error: fallback block is not inside the catch.

The catch statement at line 373 is a single-line catch containing only the Log.Debug call. The // comment terminates the statement. Lines 374-380 form a separate, unconditional block that always executes, overwriting successful scan results with "App update check unavailable."

This breaks the app update alert — it will never display actual update counts.

🐛 Proposed fix: move fallback code inside catch block
-        catch (Exception ex) { Log.Debug("Alert scan failed: {Error}", ex.Message); }//
-        {
+        catch (Exception ex)
+        {
+            Log.Debug("Alert scan failed: {Error}", ex.Message);
             System.Windows.Application.Current?.Dispatcher.BeginInvoke(() =>
             {
                 alert.Title = "App update check unavailable";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/ViewModels/DashboardViewModel.cs` around lines 373 -
380, The fallback block that sets alert.Title and alert.Severity is currently
outside the catch (the catch currently only contains Log.Debug("Alert scan
failed: {Error}", ex.Message);) so it always runs; move the
System.Windows.Application.Current?.Dispatcher.BeginInvoke(...) block (the lines
that set alert.Title = "App update check unavailable" and alert.Severity =
AlertSeverity.Green) into the catch(Exception ex) body (and remove the stray
trailing comment marker) so the fallback executes only when the alert scan
throws, keeping Log.Debug(...) and the dispatcher invocation together.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@SysManager/SysManager/ViewModels/AboutViewModel.cs`:
- Around line 278-292: The ManagementObjectCollection returned by
ManagementObjectSearcher.Get() is not disposed; change the pattern in the CPU
block (and the other WMI query blocks: RAM, GPU, Display, Windows) to capture
the collection into an IDisposable local (e.g., var coll = cpuSearch.Get()) and
wrap it in a using (or using var) so the collection is disposed after
enumeration, while still disposing each ManagementObject inside the loop; update
the code that currently calls cpuSearch.Get() directly in the foreach to use
this using-scoped collection for full cleanup of unmanaged WMI resources.

---

Outside diff comments:
In `@SysManager/SysManager/ViewModels/DashboardViewModel.cs`:
- Around line 461-468: The fallback block that sets alert.Title and
alert.Severity is currently outside the catch and always executes; move that
Dispatcher.BeginInvoke block inside the catch for the exception handler so the
fallback runs only when the catch in DashboardViewModel (the catch handling
"Alert scan failed") is triggered—i.e., ensure the catch block contains both
Log.Debug("Alert scan failed: {Error}", ex.Message) and the
System.Windows.Application.Current?.Dispatcher.BeginInvoke(...) block so the
"Feature check unavailable" alert is only set on exceptions.
- Around line 428-435: The fallback block that sets alert.Title and
alert.Severity is placed outside the catch and thus always executes; move the
block currently after the catch (the
System.Windows.Application.Current?.Dispatcher.BeginInvoke(...) that sets
alert.Title = "Event Log check unavailable" and alert.Severity =
AlertSeverity.Green) inside the catch that contains Log.Debug("Alert scan
failed: {Error}", ex.Message) so that it only runs when an exception occurs, and
remove the stray unconditional braces; locate this in DashboardViewModel.cs
around the catch that logs via Log.Debug and wrap the Dispatcher.BeginInvoke
fallback inside that catch.
- Around line 373-380: The fallback block that sets alert.Title and
alert.Severity is currently outside the catch (the catch currently only contains
Log.Debug("Alert scan failed: {Error}", ex.Message);) so it always runs; move
the System.Windows.Application.Current?.Dispatcher.BeginInvoke(...) block (the
lines that set alert.Title = "App update check unavailable" and alert.Severity =
AlertSeverity.Green) into the catch(Exception ex) body (and remove the stray
trailing comment marker) so the fallback executes only when the alert scan
throws, keeping Log.Debug(...) and the dispatcher invocation together.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4686e1df-293e-4e89-bdd6-0018c27e2f5a

📥 Commits

Reviewing files that changed from the base of the PR and between 23f4b4d and ff32535.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • SysManager/SysManager/Services/ThemeService.cs
  • SysManager/SysManager/SysManager.csproj
  • SysManager/SysManager/ViewModels/AboutViewModel.cs
  • SysManager/SysManager/ViewModels/BulkInstallerViewModel.cs
  • SysManager/SysManager/ViewModels/DashboardViewModel.cs
  • SysManager/SysManager/Views/ShortcutCleanerView.xaml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build & unit tests
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (8)
SysManager/SysManager/ViewModels/BulkInstallerViewModel.cs (1)

28-28: LGTM!

Also applies to: 347-347

SysManager/SysManager/SysManager.csproj (1)

13-15: LGTM!

SysManager/SysManager/Views/ShortcutCleanerView.xaml (1)

59-61: AI summary inconsistency with PR objectives.

The AI-generated summary for this file states "No property set changes or data-binding logic changes—this is an indentation/line-wrapping adjustment only," but the PR objectives explicitly describe functional changes: "ShortcutCleanerView: DataGrid updated to Background="Transparent" and BorderThickness="0" to match other views and avoid visible white background/border."

The PR objectives indicate these are deliberate property additions to fix visual consistency issues, not mere formatting changes.

CHANGELOG.md (1)

9-17: LGTM!

SysManager/SysManager/Services/ThemeService.cs (2)

220-220: LGTM!


251-251: LGTM!

SysManager/SysManager/ViewModels/DashboardViewModel.cs (1)

176-178: LGTM!

SysManager/SysManager/ViewModels/AboutViewModel.cs (1)

280-292: LGTM!

Also applies to: 301-309, 318-329, 346-359, 383-390

Comment on lines 278 to +292
using var cpuSearch = new System.Management.ManagementObjectSearcher(
"SELECT Name,NumberOfCores,NumberOfLogicalProcessors,MaxClockSpeed FROM Win32_Processor");
foreach (System.Management.ManagementObject mo in cpuSearch.Get())
{
var name = mo["Name"]?.ToString()?.Trim() ?? "unknown";
var cores = mo["NumberOfCores"];
var threads = mo["NumberOfLogicalProcessors"];
var mhz = mo["MaxClockSpeed"];
sb.Append("CPU: ").Append(name);
if (cores is not null) sb.Append($" ({cores}c/{threads}t)");
if (mhz is uint speed) sb.Append($" @ {speed / 1000.0:F1} GHz");
sb.AppendLine();
break;
}
using (mo)
{
var name = mo["Name"]?.ToString()?.Trim() ?? "unknown";
var cores = mo["NumberOfCores"];
var threads = mo["NumberOfLogicalProcessors"];
var mhz = mo["MaxClockSpeed"];
sb.Append("CPU: ").Append(name);
if (cores is not null) sb.Append($" ({cores}c/{threads}t)");
if (mhz is uint speed) sb.Append($" @ {speed / 1000.0:F1} GHz");
sb.AppendLine();
break;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Complete the resource cleanup by disposing ManagementObjectCollection.

The ManagementObjectSearcher.Get() method returns a ManagementObjectCollection which also implements IDisposable and holds unmanaged WMI resources. While disposing each ManagementObject addresses the immediate leak, not disposing the collection itself leaves the fix incomplete.

♻️ Recommended pattern for complete disposal

Apply this pattern to all five WMI queries (CPU, RAM, GPU, Display, Windows):

 using var cpuSearch = new System.Management.ManagementObjectSearcher(
     "SELECT Name,NumberOfCores,NumberOfLogicalProcessors,MaxClockSpeed FROM Win32_Processor");
-foreach (System.Management.ManagementObject mo in cpuSearch.Get())
+using var cpuResults = cpuSearch.Get();
+foreach (System.Management.ManagementObject mo in cpuResults)
     using (mo)
     {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/ViewModels/AboutViewModel.cs` around lines 278 - 292,
The ManagementObjectCollection returned by ManagementObjectSearcher.Get() is not
disposed; change the pattern in the CPU block (and the other WMI query blocks:
RAM, GPU, Display, Windows) to capture the collection into an IDisposable local
(e.g., var coll = cpuSearch.Get()) and wrap it in a using (or using var) so the
collection is disposed after enumeration, while still disposing each
ManagementObject inside the loop; update the code that currently calls
cpuSearch.Get() directly in the foreach to use this using-scoped collection for
full cleanup of unmanaged WMI resources.

@laurentiu021 laurentiu021 merged commit 760dd23 into main May 29, 2026
5 checks passed
@laurentiu021 laurentiu021 deleted the fix/audit-findings branch May 29, 2026 13:43
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.

3 participants