Commit 4f57e3f1 authored by Jeremy Hylton's avatar Jeremy Hylton

Fix cc_oid_unreferenced() so that it works with a Python debug build.

In the TRACE_REFS version of the code, call _Py_NewReference() instead
of INCREF to bump the refcount from zero to one.

When exiting the function, don't DECREF the object back to zero
refcount, as that will reinvoke the object's deallocation function.
XXX Why did this ever work?
parent aa887d42
...@@ -88,7 +88,7 @@ process must skip such objects, rather than deactivating them. ...@@ -88,7 +88,7 @@ process must skip such objects, rather than deactivating them.
static char cPickleCache_doc_string[] = static char cPickleCache_doc_string[] =
"Defines the PickleCache used by ZODB Connection objects.\n" "Defines the PickleCache used by ZODB Connection objects.\n"
"\n" "\n"
"$Id: cPickleCache.c,v 1.65 2002/05/02 14:03:07 fdrake Exp $\n"; "$Id: cPickleCache.c,v 1.66 2002/06/10 22:35:08 jeremy Exp $\n";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
...@@ -427,9 +427,9 @@ cc_invalidate(ccobject *self, PyObject *args) ...@@ -427,9 +427,9 @@ cc_invalidate(ccobject *self, PyObject *args)
PyObject *inv, *key, *v; PyObject *inv, *key, *v;
int i; int i;
/* XXX The code supports invalidation of all objects, but I don't /* XXX The code supports invalidation of all objects, but it's
think it's possible for a Connection object to pass None. If impossible for a Connection object to pass None. The code could be
this is correct, the code could be simplied. simplied.
*/ */
if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) {
...@@ -604,22 +604,26 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid) ...@@ -604,22 +604,26 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
*/ */
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
#error "this code path has not been tested - Toby Dickenson" /* This is called from the deallocation function after the
/* not tested, but it should still work. I would appreciate interpreter has untracked the reference. Track it again.
reports of success */ */
_Py_NewReference(v); _Py_NewReference(v);
/* it may be a problem that v->ob_type is still NULL? */ /* XXX it may be a problem that v->ob_type is still NULL?
I don't understand what this comment means. --jeremy */
assert(v->ob_type);
#else #else
Py_INCREF(v); Py_INCREF(v);
#endif #endif
assert(v->ob_refcnt == 1);
/* Incremement the refcount again, because delitem is going to /* Incremement the refcount again, because delitem is going to
DECREF it. If it's refcount reached zero again, we'd call back to DECREF it. If it's refcount reached zero again, we'd call back to
the dealloc function that called us. the dealloc function that called us.
*/ */
Py_INCREF(v); Py_INCREF(v);
/* XXX what if this fails? */ /* XXX Should we call _Py_ForgetReference() on error exit? */
PyDict_DelItem(self->data, oid); if (PyDict_DelItem(self->data, oid) < 0)
return -1;
if (v->ob_refcnt != 1) { if (v->ob_refcnt != 1) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
...@@ -627,12 +631,12 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid) ...@@ -627,12 +631,12 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
return -1; return -1;
} }
/* undo the temporary resurrection */ /* Undo the temporary resurrection.
#ifdef Py_TRACE_REFS Don't DECREF the object, because this function is called from
the object's dealloc function. If the refcnt reaches zero, it
will all be invoked recursively.
*/
_Py_ForgetReference(v); _Py_ForgetReference(v);
#else
v->ob_refcnt = 0;
#endif
return 0; return 0;
} }
......
...@@ -88,7 +88,7 @@ process must skip such objects, rather than deactivating them. ...@@ -88,7 +88,7 @@ process must skip such objects, rather than deactivating them.
static char cPickleCache_doc_string[] = static char cPickleCache_doc_string[] =
"Defines the PickleCache used by ZODB Connection objects.\n" "Defines the PickleCache used by ZODB Connection objects.\n"
"\n" "\n"
"$Id: cPickleCache.c,v 1.65 2002/05/02 14:03:07 fdrake Exp $\n"; "$Id: cPickleCache.c,v 1.66 2002/06/10 22:35:08 jeremy Exp $\n";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
...@@ -427,9 +427,9 @@ cc_invalidate(ccobject *self, PyObject *args) ...@@ -427,9 +427,9 @@ cc_invalidate(ccobject *self, PyObject *args)
PyObject *inv, *key, *v; PyObject *inv, *key, *v;
int i; int i;
/* XXX The code supports invalidation of all objects, but I don't /* XXX The code supports invalidation of all objects, but it's
think it's possible for a Connection object to pass None. If impossible for a Connection object to pass None. The code could be
this is correct, the code could be simplied. simplied.
*/ */
if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) {
...@@ -604,22 +604,26 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid) ...@@ -604,22 +604,26 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
*/ */
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
#error "this code path has not been tested - Toby Dickenson" /* This is called from the deallocation function after the
/* not tested, but it should still work. I would appreciate interpreter has untracked the reference. Track it again.
reports of success */ */
_Py_NewReference(v); _Py_NewReference(v);
/* it may be a problem that v->ob_type is still NULL? */ /* XXX it may be a problem that v->ob_type is still NULL?
I don't understand what this comment means. --jeremy */
assert(v->ob_type);
#else #else
Py_INCREF(v); Py_INCREF(v);
#endif #endif
assert(v->ob_refcnt == 1);
/* Incremement the refcount again, because delitem is going to /* Incremement the refcount again, because delitem is going to
DECREF it. If it's refcount reached zero again, we'd call back to DECREF it. If it's refcount reached zero again, we'd call back to
the dealloc function that called us. the dealloc function that called us.
*/ */
Py_INCREF(v); Py_INCREF(v);
/* XXX what if this fails? */ /* XXX Should we call _Py_ForgetReference() on error exit? */
PyDict_DelItem(self->data, oid); if (PyDict_DelItem(self->data, oid) < 0)
return -1;
if (v->ob_refcnt != 1) { if (v->ob_refcnt != 1) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
...@@ -627,12 +631,12 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid) ...@@ -627,12 +631,12 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
return -1; return -1;
} }
/* undo the temporary resurrection */ /* Undo the temporary resurrection.
#ifdef Py_TRACE_REFS Don't DECREF the object, because this function is called from
the object's dealloc function. If the refcnt reaches zero, it
will all be invoked recursively.
*/
_Py_ForgetReference(v); _Py_ForgetReference(v);
#else
v->ob_refcnt = 0;
#endif
return 0; return 0;
} }
......
...@@ -88,7 +88,7 @@ process must skip such objects, rather than deactivating them. ...@@ -88,7 +88,7 @@ process must skip such objects, rather than deactivating them.
static char cPickleCache_doc_string[] = static char cPickleCache_doc_string[] =
"Defines the PickleCache used by ZODB Connection objects.\n" "Defines the PickleCache used by ZODB Connection objects.\n"
"\n" "\n"
"$Id: cPickleCache.c,v 1.65 2002/05/02 14:03:07 fdrake Exp $\n"; "$Id: cPickleCache.c,v 1.66 2002/06/10 22:35:08 jeremy Exp $\n";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
...@@ -427,9 +427,9 @@ cc_invalidate(ccobject *self, PyObject *args) ...@@ -427,9 +427,9 @@ cc_invalidate(ccobject *self, PyObject *args)
PyObject *inv, *key, *v; PyObject *inv, *key, *v;
int i; int i;
/* XXX The code supports invalidation of all objects, but I don't /* XXX The code supports invalidation of all objects, but it's
think it's possible for a Connection object to pass None. If impossible for a Connection object to pass None. The code could be
this is correct, the code could be simplied. simplied.
*/ */
if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) {
...@@ -604,22 +604,26 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid) ...@@ -604,22 +604,26 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
*/ */
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
#error "this code path has not been tested - Toby Dickenson" /* This is called from the deallocation function after the
/* not tested, but it should still work. I would appreciate interpreter has untracked the reference. Track it again.
reports of success */ */
_Py_NewReference(v); _Py_NewReference(v);
/* it may be a problem that v->ob_type is still NULL? */ /* XXX it may be a problem that v->ob_type is still NULL?
I don't understand what this comment means. --jeremy */
assert(v->ob_type);
#else #else
Py_INCREF(v); Py_INCREF(v);
#endif #endif
assert(v->ob_refcnt == 1);
/* Incremement the refcount again, because delitem is going to /* Incremement the refcount again, because delitem is going to
DECREF it. If it's refcount reached zero again, we'd call back to DECREF it. If it's refcount reached zero again, we'd call back to
the dealloc function that called us. the dealloc function that called us.
*/ */
Py_INCREF(v); Py_INCREF(v);
/* XXX what if this fails? */ /* XXX Should we call _Py_ForgetReference() on error exit? */
PyDict_DelItem(self->data, oid); if (PyDict_DelItem(self->data, oid) < 0)
return -1;
if (v->ob_refcnt != 1) { if (v->ob_refcnt != 1) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
...@@ -627,12 +631,12 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid) ...@@ -627,12 +631,12 @@ cc_oid_unreferenced(ccobject *self, PyObject *oid)
return -1; return -1;
} }
/* undo the temporary resurrection */ /* Undo the temporary resurrection.
#ifdef Py_TRACE_REFS Don't DECREF the object, because this function is called from
the object's dealloc function. If the refcnt reaches zero, it
will all be invoked recursively.
*/
_Py_ForgetReference(v); _Py_ForgetReference(v);
#else
v->ob_refcnt = 0;
#endif
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment