From 026b5c626d37b1fdfb06da381d92f23fdb2f608f Mon Sep 17 00:00:00 2001 From: Scyllinice Date: Mon, 9 Nov 2026 22:45:55 -0600 Subject: [PATCH] fix(viewer): destroy the Qt objects before interpreter exit Every quit of the Console Hub ended in a segfault or a 'corrupted double-linked list' abort. PySide's interpreter-exit cleanup (PySide::destroyQCoreApplication -> visitAllPyObjects) destroys a QObject that was already gone, leaving a ~13 MB core dump each time. Capture has already shut down cleanly by then, so nothing is lost apart from the core dump. After app.exec() returns, hide the tray icon and window, delete the window through the event loop, and flush the deferred deletes while Python still owns the objects. Then exit. Reproduced off-screen (QT_QPA_PLATFORM=offscreen, quitting through the tray Quit path after 4 s): 3/3 crashes before, 5/5 clean exits after, plus 2/2 clean exits when started with --tray. --- CHANGELOG.md | 7 +++++++ tools/everlive/everlive_viewer.py | 24 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca06e96..cf521f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [Unreleased] + +### Fixed +- The Console Hub no longer crashes on exit (segfault or `corrupted double-linked list` abort in `PySide::destroyQCoreApplication`, leaving a core dump on every quit). The window and tray icon are now destroyed before Python shuts down. + +--- + ## [1.4.0] - 2026-11-06 ### Added diff --git a/tools/everlive/everlive_viewer.py b/tools/everlive/everlive_viewer.py index 1b1e60e..e3d3ffd 100755 --- a/tools/everlive/everlive_viewer.py +++ b/tools/everlive/everlive_viewer.py @@ -5020,6 +5020,25 @@ def closeEvent(self, event): event.accept() +def _destroy_qt_objects(app, window): + """Tear the Qt object tree down while Python still owns it. + + Leaving it to PySide's interpreter-exit cleanup destroys some QObjects + twice (segfault or "corrupted double-linked list" abort in + PySide::destroyQCoreApplication on every quit). + """ + try: + tray = getattr(window, "tray_icon", None) + if tray is not None: + tray.hide() + window.hide() + window.deleteLater() + app.sendPostedEvents(None, QEvent.Type.DeferredDelete) + app.processEvents() + except Exception: + pass + + def main(): parser = argparse.ArgumentParser(description="EverLive - Live Gamer 4K Console Gaming Screen") parser.add_argument("-f", "--fullscreen", action="store_true", help="Launch directly in fullscreen") @@ -5193,7 +5212,10 @@ def sig_handler(sig, frame): headless_start=args.headless, v4l2_device=args.v4l2) if not args.tray: window.show() - sys.exit(app.exec()) + code = app.exec() + _destroy_qt_objects(app, window) + del window + sys.exit(code) if __name__ == "__main__":