← All releases
v1.1.3

Stability Refactor & Crash Prevention Update

This update is a comprehensive stability and code quality release, derived from three independent code review reports. It focuses on eliminating crash risks, memory leaks, performance bottlenecks, and security vulnerabilities without changing any UI functionality.

Critical Fixes:

  • Unified _tray_instance Architecture: Resolved a critical global variable conflict where _tray_instance was defined in two places (ui.py and ui_utils.py) with different references, causing cleanup_tray_icon() and cleanup_on_exit() to silently fail. Now a single centralized reference in ui_utils.py is used, ensuring reliable tray icon and server process cleanup on application exit or crash.
  • Removed Fragile sys.modules Access: Eliminated all race-condition-prone dynamic module lookups via sys.modules['LlamaTray.ui'] in cleanup_tray_icon(), cleanup_on_exit(), and AboutDialog. All components now use the centralized ui_utils._tray_instance reference directly.
  • Duplicate Cleanup Registration Prevented: Removed the duplicate atexit.register(cleanup_on_exit) mechanism. Cleanup is now handled exclusively through the Qt aboutToQuit signal, preventing double-execution and potential crashes.
  • closeEvent NoneType Crash Prevention: Added callable(original_close_event) check and safe QMainWindow.closeEvent(self.window, event) delegation to prevent TypeError: 'NoneType' object is not callable crashes when closing the window.
  • QComboBox Validator Fix: Fixed QComboBox.setValidator() which silently fails in PyQt6. Now correctly uses self.context_size_combobox.lineEdit().setValidator(QIntValidator(512, 1000000)) to properly validate context size input.

Server Process Management Hardening:

  • Shell Injection Prevention: Replaced ["bash", "-c", f"lsof -ti:{port} | xargs kill -9"] with safe list-based subprocess.run(["lsof", "-ti", str(port)]) calls, eliminating shell injection risk.
  • Graceful Process Termination: Port cleanup now sends SIGTERM first, polls for port release with 0.5s intervals (up to 3 seconds), and only falls back to SIGKILL if the process doesn’t respond gracefully.
  • find_llama_server() Caching: Results of shutil.which("llama-server") are now cached at module level, eliminating redundant which lookups in start_server().

Performance Optimizations:

  • Non-blocking CPU Monitoring: Changed psutil.cpu_percent(interval=0.1) to interval=0, removing the 100ms UI thread blockage that occurred every second during system monitor updates.
  • NVML Resource Leak Fix: Added pynvml.nvmlShutdown() call in SystemMonitor.__del__() and a dedicated _shutdown_gpu() method, preventing NVIDIA driver resource leaks on application exit.

Desktop Environment Compatibility:

  • Dynamic QT Theme Detection: Replaced hardcoded os.environ["QT_QPA_PLATFORM_THEME"] = "kde" with dynamic detection using XDG_CURRENT_DESKTOP. Now correctly sets the theme for KDE, GNOME, or falls back to Qt defaults for other environments (XFCE, i3, Sway, etc.).

Code Quality Cleanup:

  • Removed Unused Imports: Cleaned up unused import json and import os in profile_manager.py.
  • Version Bump: All version strings updated to v1.1.3.