Fix #2702, with a correct accounting of recursion.
authorFacundo Batista <facundobatista@gmail.com>
Mon, 30 Jun 2008 01:10:55 +0000 (01:10 +0000)
committerFacundo Batista <facundobatista@gmail.com>
Mon, 30 Jun 2008 01:10:55 +0000 (01:10 +0000)
Lib/test/test_cpickle.py
Modules/cPickle.c

index 7d3fc97df93c88c0e544d1afa628664e14d79b7c..0b02b624734002cf7fc7b5c838604fe2ac42302f 100644 (file)
@@ -94,23 +94,19 @@ class Node(object):
     pass
 
 class cPickleDeepRecursive(unittest.TestCase):
-#    I commented out, because the patch that fixes this was reverted, as
-#    it broke the next test case. Check the issues for full history.
-#     def test_issue2702(self):
-#         '''This should raise a RecursionLimit but in some
-#         platforms (FreeBSD, win32) sometimes raises KeyError instead,
-#         or just silently terminates the interpreter (=crashes).
-#         '''
-#         nodes = [Node() for i in range(500)]
-#         for n in nodes:
-#             n.connections = list(nodes)
-#             n.connections.remove(n)
-#         self.assertRaises(RuntimeError, cPickle.dumps, n)
+    def test_issue2702(self):
+        # This should raise a RecursionLimit but in some
+        # platforms (FreeBSD, win32) sometimes raises KeyError instead,
+        # or just silently terminates the interpreter (=crashes).
+        nodes = [Node() for i in range(500)]
+        for n in nodes:
+            n.connections = list(nodes)
+            n.connections.remove(n)
+        self.assertRaises(RuntimeError, cPickle.dumps, n)
 
     def test_issue3179(self):
-        '''Safe test, because of I broken this case when fixing the
-        behaviour for the previous test.
-        '''
+        # Safe test, because I broke this case when fixing the
+        # behaviour for the previous test.
         res=[]
         for x in range(1,2000):
             res.append(dict(doc=x, similar=[]))
index afa75fd5fe36ff2931e91cc26340c78a429f411c..7f4ad7eb870d0ebe4e1611402c75efb32d4defcb 100644 (file)
@@ -339,7 +339,6 @@ typedef struct Picklerobject {
        int bin;
 
        int fast; /* Fast mode doesn't save in memo, don't use if circ ref */
-        int nesting;
        int (*write_func)(struct Picklerobject *, const char *, Py_ssize_t);
        char *write_buf;
        int buf_size;
@@ -1630,7 +1629,12 @@ save_list(Picklerobject *self, PyObject *args)
        iter = PyObject_GetIter(args);
        if (iter == NULL)
                goto finally;
-       res = batch_list(self, iter);
+
+       if (Py_EnterRecursiveCall(" while pickling an object") == 0)
+       {
+               res = batch_list(self, iter);
+               Py_LeaveRecursiveCall();
+       }
        Py_DECREF(iter);
 
   finally:
@@ -1786,7 +1790,11 @@ save_dict(Picklerobject *self, PyObject *args)
        iter = PyObject_CallMethod(args, "iteritems", "()");
        if (iter == NULL)
                goto finally;
-       res = batch_dict(self, iter);
+       if (Py_EnterRecursiveCall(" while pickling an object") == 0)
+       {
+               res = batch_dict(self, iter);
+               Py_LeaveRecursiveCall();
+       }
        Py_DECREF(iter);
 
   finally:
@@ -2306,11 +2314,8 @@ save(Picklerobject *self, PyObject *args, int pers_save)
        int res = -1;
        int tmp, size;
 
-        if (self->nesting++ > Py_GetRecursionLimit()){
-               PyErr_SetString(PyExc_RuntimeError,
-                               "maximum recursion depth exceeded");
-               goto finally;
-       }
+       if (Py_EnterRecursiveCall(" while pickling an object"))
+               return -1;
 
        if (!pers_save && self->pers_func) {
                if ((tmp = save_pers(self, args, self->pers_func)) != 0) {
@@ -2559,7 +2564,7 @@ save(Picklerobject *self, PyObject *args, int pers_save)
        res = save_reduce(self, t, args);
 
   finally:
-       self->nesting--;
+       Py_LeaveRecursiveCall();
        Py_XDECREF(py_ob_id);
        Py_XDECREF(__reduce__);
        Py_XDECREF(t);
@@ -2801,7 +2806,6 @@ newPicklerobject(PyObject *file, int proto)
        self->inst_pers_func = NULL;
        self->write_buf = NULL;
        self->fast = 0;
-        self->nesting = 0;
        self->fast_container = 0;
        self->fast_memo = NULL;
        self->buf_size = 0;