fix(interop): resolve native resource leaks in GTK and WebKit interop
All checks were successful
CI / Build (Linux) (push) Successful in 21s

Fix critical memory leaks identified in architecture review: Add signal handler disconnection in WebKitNative (load-changed and script-dialog signals now properly cleaned up), implement GTK idle callback cleanup with automatic removal on completion, add dlclose() calls for WebKit library handles, track GTK signal IDs in GtkSkiaSurfaceWidget for proper disposal. Replace empty catch blocks in GestureManager with logged exception handling. Add WebKitNative.Cleanup() and GtkNative.ClearCallbacks() methods for application shutdown.
This commit is contained in:
2026-03-06 23:14:53 -05:00
parent c5221ba580
commit 3412cb982e
22 changed files with 1208 additions and 50 deletions

View File

@@ -99,8 +99,9 @@ public class AppInfoService : IAppInfo
UseShellExecute = true
});
}
catch
catch (Exception ex)
{
DiagnosticLog.Debug("AppInfoService", "Settings launch fallback failed", ex);
}
}
}

View File

@@ -129,8 +129,9 @@ public class ConnectivityService : IConnectivity, IDisposable
}
}
}
catch
catch (Exception ex)
{
DiagnosticLog.Debug("ConnectivityService", "Gateway check failed", ex);
}
return false;
}

View File

@@ -137,8 +137,9 @@ public class DeviceDisplayService : IDeviceDisplay
});
}
}
catch
catch (Exception ex)
{
DiagnosticLog.Debug("DeviceDisplayService", "Display info refresh failed", ex);
}
}

View File

@@ -37,8 +37,9 @@ public class DeviceInfoService : IDeviceInfo
return result;
}
}
catch
catch (Exception ex)
{
DiagnosticLog.Debug("DeviceInfoService", "OS version parsing failed", ex);
}
return new Version(1, 0);
}

View File

@@ -43,6 +43,17 @@ public static class DiagnosticLog
System.Console.WriteLine($"[{tag}] {message}");
}
/// <summary>
/// Logs a debug diagnostic message with exception details.
/// Only compiled in DEBUG builds.
/// </summary>
[Conditional("DEBUG")]
public static void Debug(string tag, string message, Exception ex)
{
if (IsEnabled)
System.Console.WriteLine($"[{tag}] {message}: {ex.Message}");
}
/// <summary>
/// Logs an informational diagnostic message (always writes when enabled, not conditional on DEBUG).
/// Use for important operational messages that should appear in release builds when logging is enabled.

View File

@@ -133,7 +133,7 @@ public class Fcitx5InputMethodService : IInputMethodService, IDisposable
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("Fcitx5InputMethodService", "Commit signal processing failed", ex); }
}
private async Task ProcessPreeditSignal(StreamReader reader)
@@ -160,7 +160,7 @@ public class Fcitx5InputMethodService : IInputMethodService, IDisposable
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("Fcitx5InputMethodService", "Preedit signal processing failed", ex); }
}
public void SetFocus(IInputContext? context)
@@ -284,7 +284,7 @@ public class Fcitx5InputMethodService : IInputMethodService, IDisposable
_dBusMonitor?.Kill();
_dBusMonitor?.Dispose();
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("Fcitx5InputMethodService", "D-Bus monitor cleanup failed", ex); }
if (!string.IsNullOrEmpty(_inputContextPath))
{

View File

@@ -51,6 +51,13 @@ public static class GtkThemeService
return;
}
// Unreference previous CSS provider to prevent leak
if (_currentCssProvider != IntPtr.Zero)
{
GtkNative.g_object_unref(_currentCssProvider);
_currentCssProvider = IntPtr.Zero;
}
// Create new CSS provider
IntPtr newProvider = GtkNative.gtk_css_provider_new();
if (newProvider == IntPtr.Zero)
@@ -63,6 +70,7 @@ public static class GtkThemeService
if (!GtkNative.gtk_css_provider_load_from_data(newProvider, css, -1, IntPtr.Zero))
{
DiagnosticLog.Error("GtkThemeService", "Failed to load CSS data");
GtkNative.g_object_unref(newProvider);
return;
}

View File

@@ -464,7 +464,7 @@ public class HiDpiService
return textScale;
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("HiDpiService", "Font scale factor detection failed", ex); }
return _scaleFactor;
}

View File

@@ -61,7 +61,7 @@ public class NotificationService
_dBusMonitor?.Dispose();
_dBusMonitor = null;
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("NotificationService", "D-Bus monitor cleanup failed", ex); }
}
private async Task MonitorNotificationSignals()
@@ -155,7 +155,7 @@ public class NotificationService
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("NotificationService", "Action invoked processing failed", ex); }
}
private async Task ProcessNotificationClosed(StreamReader reader)
@@ -192,7 +192,7 @@ public class NotificationService
context?.Tag));
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("NotificationService", "Notification closed processing failed", ex); }
}
/// <summary>
@@ -270,7 +270,7 @@ public class NotificationService
_activeNotifications.TryRemove(notificationId, out _);
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("NotificationService", "Notification cancel failed", ex); }
}
/// <summary>

View File

@@ -160,7 +160,7 @@ public class SystemThemeService
if (output.ToLowerInvariant().Contains("dark"))
return SystemTheme.Dark;
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "GNOME theme detection failed", ex); }
return null;
}
@@ -186,7 +186,7 @@ public class SystemThemeService
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "KDE theme detection failed", ex); }
return null;
}
@@ -199,7 +199,7 @@ public class SystemThemeService
if (output.ToLowerInvariant().Contains("dark"))
return SystemTheme.Dark;
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "XFCE theme detection failed", ex); }
return DetectGtkTheme();
}
@@ -212,7 +212,7 @@ public class SystemThemeService
if (output.ToLowerInvariant().Contains("dark"))
return SystemTheme.Dark;
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "Cinnamon theme detection failed", ex); }
return null;
}
@@ -247,7 +247,7 @@ public class SystemThemeService
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "GTK theme file read failed", ex); }
return null;
}
@@ -317,7 +317,7 @@ public class SystemThemeService
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "KDE accent color parsing failed", ex); }
return new SKColor(0x21, 0x96, 0xF3);
}
@@ -373,7 +373,7 @@ public class SystemThemeService
_settingsWatcher.Changed += OnSettingsChanged;
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemThemeService", "Settings watcher setup failed", ex); }
}
private void SetupPolling()

View File

@@ -134,7 +134,7 @@ public class SystemTrayService : IDisposable
}
}
}
catch { }
catch (Exception ex) { DiagnosticLog.Debug("SystemTrayService", "Tray output reading failed", ex); }
});
return Task.FromResult(true);