|
Daniel Drake |
bafa5fa |
From 92aca4416a7930e5870b8d1a4016bae8140462ee Mon Sep 17 00:00:00 2001
|
|
Daniel Drake |
bafa5fa |
From: Daniel Drake <dsd@laptop.org>
|
|
Daniel Drake |
bafa5fa |
Date: Fri, 3 Jun 2011 16:59:15 +0100
|
|
Daniel Drake |
bafa5fa |
Subject: [PATCH] Fix GC-related crash during PyGObject deallocation
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
Python-2.7.1's GC source has the following comment:
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
/* Python's cyclic gc should never see an incoming refcount
|
|
Daniel Drake |
bafa5fa |
* of 0: if something decref'ed to 0, it should have been
|
|
Daniel Drake |
bafa5fa |
* deallocated immediately at that time.
|
|
Daniel Drake |
bafa5fa |
* Possible cause (if the assert triggers): a tp_dealloc
|
|
Daniel Drake |
bafa5fa |
* routine left a gc-aware object tracked during its teardown
|
|
Daniel Drake |
bafa5fa |
* phase, and did something-- or allowed something to happen --
|
|
Daniel Drake |
bafa5fa |
* that called back into Python. gc can trigger then, and may
|
|
Daniel Drake |
bafa5fa |
* see the still-tracked dying object. Before this assert
|
|
Daniel Drake |
bafa5fa |
* was added, such mistakes went on to allow gc to try to
|
|
Daniel Drake |
bafa5fa |
* delete the object again. In a debug build, that caused
|
|
Daniel Drake |
bafa5fa |
* a mysterious segfault, when _Py_ForgetReference tried
|
|
Daniel Drake |
bafa5fa |
* to remove the object from the doubly-linked list of all
|
|
Daniel Drake |
bafa5fa |
* objects a second time. In a release build, an actual
|
|
Daniel Drake |
bafa5fa |
* double deallocation occurred, which leads to corruption
|
|
Daniel Drake |
bafa5fa |
* of the allocator's internal bookkeeping pointers. That's
|
|
Daniel Drake |
bafa5fa |
* so serious that maybe this should be a release-build
|
|
Daniel Drake |
bafa5fa |
* check instead of an assert?
|
|
Daniel Drake |
bafa5fa |
*/
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
As shown in a backtrace at
|
|
Daniel Drake |
bafa5fa |
https://bugzilla.redhat.com/show_bug.cgi?id=640972 , pygobject is making
|
|
Daniel Drake |
bafa5fa |
this exact mistake. Before untracking its object, pygobject_dealloc
|
|
Daniel Drake |
bafa5fa |
calls PyObject_ClearWeakRefs() which can call back into python, create
|
|
Daniel Drake |
bafa5fa |
new allocations, and trigger the GC.
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
This is causing Sugar (based on pygobject2 + pygtk2 static bindings) to
|
|
Daniel Drake |
bafa5fa |
crash on a regular basis while interacting with widgets or launching
|
|
Daniel Drake |
bafa5fa |
applications.
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
Fix this by untracking the object early. Also fix the same issue spotted
|
|
Daniel Drake |
bafa5fa |
in the GSource wrapper.
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
Thanks to Bernie Innocenti for initial diagnosis.
|
|
Daniel Drake |
bafa5fa |
---
|
|
Daniel Drake |
bafa5fa |
glib/pygsource.c | 6 ++++--
|
|
Daniel Drake |
bafa5fa |
gobject/pygobject.c | 8 +++++++-
|
|
Daniel Drake |
bafa5fa |
2 files changed, 11 insertions(+), 3 deletions(-)
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
diff --git a/glib/pygsource.c b/glib/pygsource.c
|
|
Daniel Drake |
bafa5fa |
index 684711e..d0176ab 100644
|
|
Daniel Drake |
bafa5fa |
--- a/glib/pygsource.c
|
|
Daniel Drake |
bafa5fa |
+++ b/glib/pygsource.c
|
|
Daniel Drake |
bafa5fa |
@@ -387,10 +387,12 @@ pyg_source_clear(PyGSource *self)
|
|
Daniel Drake |
bafa5fa |
static void
|
|
Daniel Drake |
bafa5fa |
pyg_source_dealloc(PyGSource *self)
|
|
Daniel Drake |
bafa5fa |
{
|
|
Daniel Drake |
bafa5fa |
- PyObject_ClearWeakRefs((PyObject *)self);
|
|
Daniel Drake |
bafa5fa |
-
|
|
Daniel Drake |
bafa5fa |
+ /* Must be done first, so that there is no chance of Python's GC being
|
|
Daniel Drake |
bafa5fa |
+ * called while tracking this half-deallocated object */
|
|
Daniel Drake |
bafa5fa |
PyObject_GC_UnTrack((PyObject *)self);
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
+ PyObject_ClearWeakRefs((PyObject *)self);
|
|
Daniel Drake |
bafa5fa |
+
|
|
Daniel Drake |
bafa5fa |
pyg_source_clear(self);
|
|
Daniel Drake |
bafa5fa |
|
|
Daniel Drake |
bafa5fa |
PyObject_GC_Del(self);
|
|
Daniel Drake |
bafa5fa |
diff --git a/gobject/pygobject.c b/gobject/pygobject.c
|
|
Daniel Drake |
bafa5fa |
index 0faf221..3193890 100644
|
|
Daniel Drake |
bafa5fa |
--- a/gobject/pygobject.c
|
|
Daniel Drake |
bafa5fa |
+++ b/gobject/pygobject.c
|
|
Daniel Drake |
bafa5fa |
@@ -1028,8 +1028,14 @@ PYGLIB_DEFINE_TYPE("gobject.GObject", PyGObject_Type, PyGObject);
|
|
Daniel Drake |
bafa5fa |
static void
|
|
Daniel Drake |
bafa5fa |
pygobject_dealloc(PyGObject *self)
|
|
Daniel Drake |
bafa5fa |
{
|
|
Daniel Drake |
bafa5fa |
- PyObject_ClearWeakRefs((PyObject *)self);
|
|
Daniel Drake |
bafa5fa |
+ /* Untrack must be done first. This is because followup calls such as
|
|
Daniel Drake |
bafa5fa |
+ * ClearWeakRefs could call into Python and cause new allocations to
|
|
Daniel Drake |
bafa5fa |
+ * happen, which could in turn could trigger the garbage collector,
|
|
Daniel Drake |
bafa5fa |
+ * which would then get confused as it is tracking this half-deallocated
|
|
Daniel Drake |
bafa5fa |
+ * object. */
|
|
Daniel Drake |
bafa5fa |
PyObject_GC_UnTrack((PyObject *)self);
|
|
Daniel Drake |
bafa5fa |
+
|
|
Daniel Drake |
bafa5fa |
+ PyObject_ClearWeakRefs((PyObject *)self);
|
|
Daniel Drake |
bafa5fa |
/* this forces inst_data->type to be updated, which could prove
|
|
Daniel Drake |
bafa5fa |
* important if a new wrapper has to be created and it is of a
|
|
Daniel Drake |
bafa5fa |
* unregistered type */
|
|
Daniel Drake |
bafa5fa |
--
|
|
Daniel Drake |
bafa5fa |
1.7.5.2
|
|
Daniel Drake |
bafa5fa |
|