About dialog: UpdateCheckWorker QThread destroyed if dialog closes mid-check (crash) #32

Closed
opened 2026-07-12 12:43:53 -04:00 by the_og · 0 comments
Owner

Found in audit of main @ 06326e5.

MainWindow._show_about() runs AboutDialog(self).exec() on a temporary. AboutDialog._check_for_updates() stores the running worker only on the dialog (self._worker = UpdateCheckWorker()). If the user clicks Check for updates and closes the dialog before the network call finishes (timeout is 4 s, so the window is real on a slow connection), the dialog — and with it the running QThread — is garbage-collected. Qt aborts the process with QThread: Destroyed while thread is still running.

Anchors: bcc.py_show_about (~L1503), AboutDialog._check_for_updates (~L1397), UpdateCheckWorker (~L166).

Also: _on_check_done sets self._worker = None from the worker's own done signal; the thread may not have fully finished when the last reference drops. Same crash class.

Proposed fix

  • Parent the worker to the MainWindow (or keep it on a longer-lived owner), or
  • in AboutDialog.closeEvent/done(), if a worker is running: disconnect the signal and wait() (bounded) before dropping the reference; and in _on_check_done, self._worker.deleteLater() after finished rather than dropping the Python reference immediately.

Acceptance

  • Open About → Check for updates → immediately close the dialog, with the network artificially slowed (e.g. monkeypatched fetch_latest_release sleeping 3 s): no QThread: Destroyed while thread is still running, no crash.
  • Normal check flow still updates the label and shows the release button.
**Found in audit of `main` @ 06326e5.** `MainWindow._show_about()` runs `AboutDialog(self).exec()` on a temporary. `AboutDialog._check_for_updates()` stores the running worker only on the dialog (`self._worker = UpdateCheckWorker()`). If the user clicks **Check for updates** and closes the dialog before the network call finishes (timeout is 4 s, so the window is real on a slow connection), the dialog — and with it the running `QThread` — is garbage-collected. Qt aborts the process with `QThread: Destroyed while thread is still running`. Anchors: `bcc.py` — `_show_about` (~L1503), `AboutDialog._check_for_updates` (~L1397), `UpdateCheckWorker` (~L166). **Also**: `_on_check_done` sets `self._worker = None` from the worker's own `done` signal; the thread may not have fully finished when the last reference drops. Same crash class. **Proposed fix** - Parent the worker to the MainWindow (or keep it on a longer-lived owner), or - in `AboutDialog.closeEvent`/`done()`, if a worker is running: disconnect the signal and `wait()` (bounded) before dropping the reference; and in `_on_check_done`, `self._worker.deleteLater()` after `finished` rather than dropping the Python reference immediately. **Acceptance** - Open About → Check for updates → immediately close the dialog, with the network artificially slowed (e.g. monkeypatched `fetch_latest_release` sleeping 3 s): no `QThread: Destroyed while thread is still running`, no crash. - Normal check flow still updates the label and shows the release button.
the_og added the P1 label 2026-07-12 12:43:53 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: the_og/better-claude-config#32