Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6c77158

Browse files
committed
BUG: Fix crash when restarting OSX single shot timer (Fixes #9655)
Previously, if we had a pointer to an old timer when calling start(), we would manually get the context for the old timer and from there get a pointer to the attribute. The problem is that for a single-timer, the timer is automatically invalidated (and context cleared) at the end. This resulted in trying to Py_DECREF(0x0). To fix this, use the built-in support for a callback to run when the context is released. By doing so, we can also clean up a lot of code to release the reference in stop() as well.
1 parent c465993 commit 6c77158

1 file changed

Lines changed: 8 additions & 14 deletions

File tree

src/_macosx.m

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2887,6 +2887,11 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
28872887
PyGILState_Release(gstate);
28882888
}
28892889

2890+
static void context_cleanup(const void* info)
2891+
{
2892+
Py_DECREF((PyObject*)info);
2893+
}
2894+
28902895
static PyObject*
28912896
Timer__timer_start(Timer* self, PyObject* args)
28922897
{
@@ -2904,7 +2909,7 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
29042909
}
29052910
context.version = 0;
29062911
context.retain = 0;
2907-
context.release = 0;
2912+
context.release = context_cleanup;
29082913
context.copyDescription = 0;
29092914
attribute = PyObject_GetAttrString((PyObject*)self, "_interval");
29102915
if (attribute==NULL)
@@ -2958,10 +2963,7 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
29582963
}
29592964
Py_INCREF(attribute);
29602965
if (self->timer) {
2961-
CFRunLoopTimerGetContext(self->timer, &context);
2962-
attribute = context.info;
2963-
Py_DECREF(attribute);
2964-
CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
2966+
CFRunLoopTimerInvalidate(self->timer);
29652967
CFRelease(self->timer);
29662968
}
29672969
CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes);
@@ -2977,15 +2979,7 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
29772979
Timer__timer_stop(Timer* self)
29782980
{
29792981
if (self->timer) {
2980-
PyObject* attribute;
2981-
CFRunLoopTimerContext context;
2982-
CFRunLoopTimerGetContext(self->timer, &context);
2983-
attribute = context.info;
2984-
Py_DECREF(attribute);
2985-
CFRunLoopRef runloop = CFRunLoopGetCurrent();
2986-
if (runloop) {
2987-
CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
2988-
}
2982+
CFRunLoopTimerInvalidate(self->timer);
29892983
CFRelease(self->timer);
29902984
self->timer = NULL;
29912985
}

0 commit comments

Comments
 (0)