8000 Fix crash when restarting OSX single shot timer by dopplershift · Pull Request #9662 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Fix crash when restarting OSX single shot timer #9662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 7, 2017
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.
  • Loading branch information
dopplershift committed Nov 2, 2017
commit 6c7715876d4322df4afede6a146c8412eb15cd57
22 changes: 8 additions & 14 deletions src/_macosx.m
Original file line number Diff line number Diff line change
Expand Up @@ -2887,6 +2887,11 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
PyGILState_Release(gstate);
}

static void context_cleanup(const void* info)
{
Py_DECREF((PyObject*)info);
}

static PyObject*
Timer__timer_start(Timer* self, PyObject* args)
{
Expand All @@ -2904,7 +2909,7 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
}
context.version = 0;
context.retain = 0;
context.release = 0;
context.release = context_cleanup;
context.copyDescription = 0;
attribute = PyObject_GetAttrString((PyObject*)self, "_interval");
if (attribute==NULL)
Expand Down Expand Up @@ -2958,10 +2963,7 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
}
Py_INCREF(attribute);
if (self->timer) {
CFRunLoopTimerGetContext(self->timer, &context);
attribute = context.info;
Py_DECREF(attribute);
CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
CFRunLoopTimerInvalidate(self->timer);
CFRelease(self->timer);
}
CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes);
Expand All @@ -2977,15 +2979,7 @@ static void timer_callback(CFRunLoopTimerRef timer, void* info)
Timer__timer_stop(Timer* self)
{
if (self->timer) {
PyObject* attribute;
CFRunLoopTimerContext context;
CFRunLoopTimerGetContext(self->timer, &context);
attribute = context.info;
Py_DECREF(attribute);
CFRunLoopRef runloop = CFRunLoopGetCurrent();
if (runloop) {
CFRunLoopRemoveTimer(runloop, self->timer, kCFRunLoopCommonModes);
}
CFRunLoopTimerInvalidate(self->timer);
CFRelease(self->timer);
self->timer = NULL;
}
Expand Down
0