Repository navigation
Post jobs_changed to the scheduler instead of a dangling singleShot - #2629
Merged
Merged
Conversation
`QTimer.singleShot(0, scheduler.jobs_changed.emit)` does not keep the scheduler alive. When a scheduler is freed before the event loop runs the call, `emit` dereferences the freed QObject and segfaults, or reads garbage. The unit tests hit this on macOS: `init_db` teardown releases test-created schedulers with an announcement still queued, and the next `waitSignal` delivers it (#2595, macOS job of #2621). Queue the emit with `QMetaObject.invokeMethod` on the scheduler, so Qt discards it together with the scheduler.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
SchedulerState._announce_jobqueuedjobs_changedwithQTimer.singleShot(0, self.scheduler.jobs_changed.emit). The pending call does not keep the scheduler alive. If the scheduler is freed before the event loop delivers the call,emitruns on a freed QObject: a segfault, orAttributeError: 'VortaScheduler' does not have a signal with the signature jobs_changed()when the memory has been reused._announce_jobnow queues the signal withQMetaObject.invokeMethod(self.scheduler, 'jobs_changed', QueuedConnection). The event is posted to the scheduler itself, so Qt discards it if the scheduler is deleted first.Related Issue
Root cause of #2595. Also the macOS failure of #2621.
Motivation and Context
The app's own scheduler lives as long as the app, so users are very unlikely to hit this. The unit tests hit it on macOS:
init_dbteardown drops thebackup_finished_eventconnection that keeps each test-createdVortaScheduleralive, while one of its announcements is still queued. A later GC pass frees the scheduler, and the next test'sqtbot.waitSignaldelivers the call. That's why the crash always showed up inside a later test's event loop and moved with GC timing (test_recording_a_skip_emits_jobs_changedin #2595,test_create_backup_records_a_running_jobin #2621, 2 of 2 attempts each).The Python traceback only showed the event loop. A native crash report from a diagnostic CI run (
.ipsfrom~/Library/Logs/DiagnosticReports) showed the main thread insendPostedEvents→PyQtSlotProxy::unislot→PyQtSlot::call→cfunction_call, faulting at0x45. A standalone script reproduces it 3 of 3 times:The same script with
invokeMethoddoesn't crash, and still delivers the signal once when the object is alive.How Has This Been Tested?
tests/unit/test_scheduler.py::test_announced_job_outlives_its_schedulerqueues an announcement on a scheduler, frees the scheduler and spins the event loop. 3 of 3 passed with the fix. 3 of 3 failed without it (one segfault, two of theAttributeErrorabove).tests/unitlocally on macOS, Python 3.12, Borg 1.4.3: 626 passed, 8 skipped.make linthooks pass on the changed files.Types of changes
Checklist:
I provide my contribution under the terms of the license of this repository and I affirm the Developer Certificate of Origin.