[Python-3000-checkins] r67059 - in python/branches/py3k: Lib/test/pickletester.py Misc/NEWS Modules/_pickle.c

amaury.forgeotdarc python-3000-checkins at python.org
Fri Oct 31 00:47:48 CET 2008


Author: amaury.forgeotdarc
Date: Thu Oct 30 23:25:31 2008
New Revision: 67059

Log:
Merged revisions 67049 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r67049 | amaury.forgeotdarc | 2008-10-30 22:18:34 +0100 (jeu., 30 oct. 2008) | 8 lines
  
  Issue #4176: Pickle would crash the interpreter when a __reduce__ function
  does not return an iterator for the 4th and 5th items.
  (sequence-like and mapping-like state)
  
  A list is not an iterator...
  
  Will backport to 2.6 and 2.5.
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Lib/test/pickletester.py
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/_pickle.c

Modified: python/branches/py3k/Lib/test/pickletester.py
==============================================================================
--- python/branches/py3k/Lib/test/pickletester.py	(original)
+++ python/branches/py3k/Lib/test/pickletester.py	Thu Oct 30 23:25:31 2008
@@ -876,6 +876,22 @@
         d = self.dumps(x, 2)
         self.assertRaises(RuntimeError, self.loads, d)
 
+    def test_reduce_bad_iterator(self):
+        # Issue4176: crash when 4th and 5th items of __reduce__()
+        # are not iterators
+        class C(object):
+            def __reduce__(self):
+                # 4th item is not an iterator
+                return list, (), None, [], None
+        class D(object):
+            def __reduce__(self):
+                # 5th item is not an iterator
+                return dict, (), None, None, []
+
+        for proto in protocols:
+            self.assertRaises(pickle.PickleError, self.dumps, C(), proto)
+            self.assertRaises(pickle.PickleError, self.dumps, D(), proto)
+
 # Test classes for reduce_ex
 
 class REX_one(object):

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Thu Oct 30 23:25:31 2008
@@ -15,6 +15,9 @@
 Core and Builtins
 -----------------
 
+- Issue #4176: Fixed a crash when pickling an object which ``__reduce__``
+  method does not return iterators for the 4th and 5th items.
+
 - Issue 3723: Fixed initialization of subinterpreters.
 
 - Issue #4213: The file system encoding is now normalized by the

Modified: python/branches/py3k/Modules/_pickle.c
==============================================================================
--- python/branches/py3k/Modules/_pickle.c	(original)
+++ python/branches/py3k/Modules/_pickle.c	Thu Oct 30 23:25:31 2008
@@ -1961,8 +1961,9 @@
     PyObject *callable;
     PyObject *argtup;
     PyObject *state = NULL;
-    PyObject *listitems = NULL;
-    PyObject *dictitems = NULL;
+    PyObject *listitems = Py_None;
+    PyObject *dictitems = Py_None;
+    Py_ssize_t size;
 
     int use_newobj = self->proto >= 2;
 
@@ -1970,27 +1971,48 @@
     const char build_op = BUILD;
     const char newobj_op = NEWOBJ;
 
+    size = PyTuple_Size(args);
+    if (size < 2 || size > 5) {
+        PyErr_SetString(PicklingError, "tuple returned by "
+                        "__reduce__ must contain 2 through 5 elements");
+        return -1;
+    }
+
     if (!PyArg_UnpackTuple(args, "save_reduce", 2, 5,
                            &callable, &argtup, &state, &listitems, &dictitems))
         return -1;
 
     if (!PyCallable_Check(callable)) {
-        PyErr_SetString(PicklingError,
-                        "first argument of save_reduce() must be callable");
+        PyErr_SetString(PicklingError, "first item of the tuple "
+                        "returned by __reduce__ must be callable");
         return -1;
     }
     if (!PyTuple_Check(argtup)) {
-        PyErr_SetString(PicklingError,
-                        "second argument of save_reduce() must be a tuple");
+        PyErr_SetString(PicklingError, "second item of the tuple "
+                        "returned by __reduce__ must be a tuple");
         return -1;
     }
 
     if (state == Py_None)
         state = NULL;
+
     if (listitems == Py_None)
         listitems = NULL;
+    else if (!PyIter_Check(listitems)) {
+        PyErr_Format(PicklingError, "Fourth element of tuple"
+                     "returned by __reduce__ must be an iterator, not %s",
+                     Py_TYPE(listitems)->tp_name);
+        return -1;
+    }
+
     if (dictitems == Py_None)
         dictitems = NULL;
+    else if (!PyIter_Check(dictitems)) {
+        PyErr_Format(PicklingError, "Fifth element of tuple"
+                     "returned by __reduce__ must be an iterator, not %s",
+                     Py_TYPE(dictitems)->tp_name);
+        return -1;
+    }
 
     /* Protocol 2 special case: if callable's name is __newobj__, use
        NEWOBJ. */
@@ -2309,16 +2331,6 @@
                         "__reduce__ must return a string or tuple");
         goto error;
     }
-    if (Py_SIZE(reduce_value) < 2 || Py_SIZE(reduce_value) > 5) {
-        PyErr_SetString(PicklingError, "tuple returned by __reduce__ "
-                        "must contain 2 through 5 elements");
-        goto error;
-    }
-    if (!PyTuple_Check(PyTuple_GET_ITEM(reduce_value, 1))) {
-        PyErr_SetString(PicklingError, "second item of the tuple "
-                        "returned by __reduce__ must be a tuple");
-        goto error;
-    }
 
     status = save_reduce(self, reduce_value, obj);
 


More information about the Python-3000-checkins mailing list