[Python-checkins] CVS: python/dist/src/Objects object.c,2.67,2.68
Jeremy Hylton
python-dev@python.org
Fri, 14 Apr 2000 15:13:26 -0400 (EDT)
Update of /projects/cvsroot/python/dist/src/Objects
In directory bitdiddle:/home/jhylton/python/src/Objects
Modified Files:
object.c
Log Message:
Fix PR#7 comparisons of recursive objects
Note that comparisons of deeply nested objects can still dump core in
extreme cases.
Index: object.c
===================================================================
RCS file: /projects/cvsroot/python/dist/src/Objects/object.c,v
retrieving revision 2.67
retrieving revision 2.68
diff -C2 -r2.67 -r2.68
*** object.c 2000/04/10 13:42:33 2.67
--- object.c 2000/04/14 19:13:23 2.68
***************
*** 299,302 ****
--- 299,356 ----
}
+ PyObject *_PyCompareState_Key;
+
+ /* _PyCompareState_nesting is incremented beforing call compare (for
+ some types) and decremented on exit. If the count exceeds the
+ nesting limit, enable code to detect circular data structures.
+ */
+ #define NESTING_LIMIT 500
+ int _PyCompareState_nesting = 0;
+
+ static PyObject*
+ get_inprogress_dict()
+ {
+ PyObject *tstate_dict, *inprogress;
+
+ tstate_dict = PyThreadState_GetDict();
+ if (tstate_dict == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ inprogress = PyDict_GetItem(tstate_dict, _PyCompareState_Key);
+ if (inprogress == NULL) {
+ PyErr_Clear();
+ inprogress = PyDict_New();
+ if (inprogress == NULL)
+ return NULL;
+ if (PyDict_SetItem(tstate_dict, _PyCompareState_Key,
+ inprogress) == -1) {
+ Py_DECREF(inprogress);
+ return NULL;
+ }
+ }
+ return inprogress;
+ }
+
+ static PyObject *
+ make_pair(v, w)
+ PyObject *v, *w;
+ {
+ PyObject *pair;
+
+ pair = PyTuple_New(2);
+ if (pair == NULL) {
+ return NULL;
+ }
+ if ((long)v <= (long)w) {
+ PyTuple_SET_ITEM(pair, 0, PyLong_FromVoidPtr((void *)v));
+ PyTuple_SET_ITEM(pair, 1, PyLong_FromVoidPtr((void *)w));
+ } else {
+ PyTuple_SET_ITEM(pair, 0, PyLong_FromVoidPtr((void *)w));
+ PyTuple_SET_ITEM(pair, 1, PyLong_FromVoidPtr((void *)v));
+ }
+ return pair;
+ }
+
int
PyObject_Compare(v, w)
***************
*** 304,307 ****
--- 358,363 ----
{
PyTypeObject *vtp, *wtp;
+ int result;
+
if (v == NULL || w == NULL) {
PyErr_BadInternalCall();
***************
*** 315,319 ****
if (!PyInstance_Check(v))
return -PyObject_Compare(w, v);
! res = do_cmp(v, w);
if (res == NULL)
return -1;
--- 371,400 ----
if (!PyInstance_Check(v))
return -PyObject_Compare(w, v);
! if (++_PyCompareState_nesting > NESTING_LIMIT) {
! PyObject *inprogress, *pair;
!
! inprogress = get_inprogress_dict();
! if (inprogress == NULL) {
! return -1;
! }
! pair = make_pair(v, w);
! if (PyDict_GetItem(inprogress, pair)) {
! /* already comparing these objects. assume
! they're equal until shown otherwise */
! Py_DECREF(pair);
! --_PyCompareState_nesting;
! return 0;
! }
! if (PyDict_SetItem(inprogress, pair, pair) == -1) {
! return -1;
! }
! res = do_cmp(v, w);
! _PyCompareState_nesting--;
! /* XXX DelItem shouldn't fail */
! PyDict_DelItem(inprogress, pair);
! Py_DECREF(pair);
! } else {
! res = do_cmp(v, w);
! }
if (res == NULL)
return -1;
***************
*** 370,376 ****
return strcmp(vname, wname);
}
! if (vtp->tp_compare == NULL)
return (v < w) ? -1 : 1;
! return (*vtp->tp_compare)(v, w);
}
--- 451,485 ----
return strcmp(vname, wname);
}
! if (vtp->tp_compare == NULL) {
return (v < w) ? -1 : 1;
! }
! if (++_PyCompareState_nesting > NESTING_LIMIT
! && (vtp->tp_as_mapping
! || (vtp->tp_as_sequence && !PyString_Check(v)))) {
! PyObject *inprogress, *pair;
!
! inprogress = get_inprogress_dict();
! if (inprogress == NULL) {
! return -1;
! }
! pair = make_pair(v, w);
! if (PyDict_GetItem(inprogress, pair)) {
! /* already comparing these objects. assume
! they're equal until shown otherwise */
! _PyCompareState_nesting--;
! Py_DECREF(pair);
! return 0;
! }
! if (PyDict_SetItem(inprogress, pair, pair) == -1) {
! return -1;
! }
! result = (*vtp->tp_compare)(v, w);
! _PyCompareState_nesting--;
! PyDict_DelItem(inprogress, pair); /* XXX shouldn't fail */
! Py_DECREF(pair);
! } else {
! result = (*vtp->tp_compare)(v, w);
! }
! return result;
}