diff Objects/classobject.c @ 14653:3d6fe64bcd21 legacy-trunk

Fix for SF bug 110688: Instance deallocation neglected to account for that Py_INCREF boosts global _Py_RefTotal when Py_REF_DEBUG is defined but Py_TRACE_REFS isn't. There are, IMO, way too many preprocessor gimmicks in use for refcount debugging (at least 3 distinct true/false symbols, but not all 8 combos are supported by the code, etc etc), and no coherent documentation of this stuff -- 'twas too painful to track this one down.
author Tim Peters <tim.peters@gmail.com>
date Sun, 17 Sep 2000 14:40:17 +0000
parents 8ad9bd9ca60c
children c5cf6fba54dd
line wrap: on
line diff
--- a/Objects/classobject.c	Sun Sep 17 00:54:58 2000 +0000
+++ b/Objects/classobject.c	Sun Sep 17 14:40:17 2000 +0000
@@ -487,37 +487,52 @@
 	PyObject *error_type, *error_value, *error_traceback;
 	PyObject *del;
 	static PyObject *delstr;
-#ifdef Py_TRACE_REFS
+#ifdef Py_REF_DEBUG
 	extern long _Py_RefTotal;
 #endif
-	/* Call the __del__ method if it exists.  First temporarily
-	   revive the object and save the current exception, if any. */
+	/* Temporarily resurrect the object. */
 #ifdef Py_TRACE_REFS
+#ifndef Py_REF_DEBUG
+#   error "Py_TRACE_REFS defined but Py_REF_DEBUG not."
+#endif
 	/* much too complicated if Py_TRACE_REFS defined */
 	inst->ob_type = &PyInstance_Type;
 	_Py_NewReference((PyObject *)inst);
-	_Py_RefTotal--;		/* compensate for increment in NEWREF */
 #ifdef COUNT_ALLOCS
-	inst->ob_type->tp_alloc--; /* ditto */
+	/* compensate for boost in _Py_NewReference; note that
+	 * _Py_RefTotal was also boosted; we'll knock that down later.
+	 */
+	inst->ob_type->tp_alloc--;
 #endif
 #else /* !Py_TRACE_REFS */
+	/* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */
 	Py_INCREF(inst);
 #endif /* !Py_TRACE_REFS */
+
+	/* Save the current exception, if any. */
 	PyErr_Fetch(&error_type, &error_value, &error_traceback);
+	/* Execute __del__ method, if any. */
 	if (delstr == NULL)
 		delstr = PyString_InternFromString("__del__");
 	if ((del = instance_getattr2(inst, delstr)) != NULL) {
 		PyObject *res = PyEval_CallObject(del, (PyObject *)NULL);
-		if (res == NULL) {
+		if (res == NULL)
 			PyErr_WriteUnraisable(del);
-		}
 		else
 			Py_DECREF(res);
 		Py_DECREF(del);
 	}
-	/* Restore the saved exception and undo the temporary revival */
+	/* Restore the saved exception. */
 	PyErr_Restore(error_type, error_value, error_traceback);
-	/* Can't use DECREF here, it would cause a recursive call */
+	/* Undo the temporary resurrection; can't use DECREF here, it would
+	 * cause a recursive call.
+	 */
+#ifdef Py_REF_DEBUG
+	/* _Py_RefTotal was boosted either by _Py_NewReference or
+	 * Py_INCREF above.
+	 */
+	_Py_RefTotal--;
+#endif
 	if (--inst->ob_refcnt > 0) {
 #ifdef COUNT_ALLOCS
 		inst->ob_type->tp_free--;
@@ -525,14 +540,15 @@
 		return; /* __del__ added a reference; don't delete now */
 	}
 #ifdef Py_TRACE_REFS
+	_Py_ForgetReference((PyObject *)inst);
 #ifdef COUNT_ALLOCS
-	inst->ob_type->tp_free--;	/* compensate for increment in UNREF */
+	/* compensate for increment in _Py_ForgetReference */
+	inst->ob_type->tp_free--;
 #endif
-	_Py_ForgetReference((PyObject *)inst);
 #ifndef WITH_CYCLE_GC
 	inst->ob_type = NULL;
 #endif
-#endif /* Py_TRACE_REFS */
+#endif
 	PyObject_GC_Fini(inst);
 	Py_DECREF(inst->in_class);
 	Py_XDECREF(inst->in_dict);