[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;
  }