]> granicus.if.org Git - python/commitdiff
cleanup_helper(): Make sure we invalidate all reference objects
authorFred Drake <fdrake@acm.org>
Fri, 13 Apr 2001 17:15:47 +0000 (17:15 +0000)
committerFred Drake <fdrake@acm.org>
Fri, 13 Apr 2001 17:15:47 +0000 (17:15 +0000)
                   before calling any callbacks.  This is important
                   since the callback objects only look at themselves
                   to determine that they are invalide.  This change
                   avoids a segfault when callbacks use a different
                   reference to an object in the process of being
                   deallocated.

This fixes SF bug #415660.

Modules/_weakref.c

index 399b4fe67b55da0646c6446ebf90391b8fe35633..71fe5a3ac4b8506de1ab562c3f779346a2b04974 100644 (file)
@@ -740,15 +740,22 @@ cleanup_helper(PyObject *object)
         return;
     }
     list = GET_WEAKREFS_LISTPTR(object);
-    while (*list != NULL) {
-        PyWeakReference *current = *list;
-        PyObject *callback = current->wr_callback;
+    /* Remove the callback-less basic and proxy references */
+    if (*list != NULL && (*list)->wr_callback == NULL) {
+        clear_weakref(*list);
+        if (*list != NULL && (*list)->wr_callback == NULL)
+            clear_weakref(*list);
+    }
+    if (*list != NULL) {
+        int count = getweakrefcount(*list);
 
-        Py_XINCREF(callback);
-        clear_weakref(current);
-        if (callback != NULL) {
+        if (count == 1) {
+            PyWeakReference *current = *list;
+            PyObject *callback = current->wr_callback;
             PyObject *cbresult;
 
+            Py_INCREF(callback);
+            clear_weakref(current);
             cbresult = PyObject_CallFunction(callback, "O", current);
             if (cbresult == NULL)
                 PyErr_WriteUnraisable(callback);
@@ -756,6 +763,34 @@ cleanup_helper(PyObject *object)
                 Py_DECREF(cbresult);
             Py_DECREF(callback);
         }
+        else {
+            PyObject *tuple = PyTuple_New(count * 2);
+            PyWeakReference *current = *list;
+            int i = 0;
+
+            for (i = 0; i < count; ++i) {
+                PyWeakReference *next = current->wr_next;
+
+                Py_INCREF(current);
+                PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
+                PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
+                current->wr_callback = NULL;
+                next = current->wr_next;
+                clear_weakref(current);
+                current = next;
+            }
+            for (i = 0; i < count; ++i) {
+                PyObject *current = PyTuple_GET_ITEM(tuple, i * 2);
+                PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
+                PyObject *cbresult = PyObject_CallFunction(callback, "O",
+                                                           current);
+                if (cbresult == NULL)
+                    PyErr_WriteUnraisable(callback);
+                else
+                    Py_DECREF(cbresult);
+            }
+            Py_DECREF(tuple);
+        }
     }
     return;
 }