Index: Lib/pickle.py =================================================================== --- Lib/pickle.py (revision 67065) +++ Lib/pickle.py (working copy) @@ -345,6 +345,9 @@ else: self.write(PERSID + str(pid).encode("ascii") + b'\n') + def _isiter(self, obj): + return hasattr(obj, '__next__') and hasattr(obj, '__iter__') + def save_reduce(self, func, args, state=None, listitems=None, dictitems=None, obj=None): # This API is called by some subclasses @@ -357,6 +360,16 @@ if not hasattr(func, '__call__'): raise PicklingError("func from save_reduce() should be callable") + # Assert that listitems is an iterator + if listitems is not None and not self._isiter(listitems): + raise PicklingError("listitems from save_reduce() should be an " + "iterator") + + # Assert that dictitems is an iterator + if dictitems is not None and not self._isiter(dictitems): + raise PicklingError("dictitems from save_reduce() should be an " + "iterator") + save = self.save write = self.write Index: Modules/_pickle.c =================================================================== --- Modules/_pickle.c (revision 67065) +++ Modules/_pickle.c (working copy) @@ -1963,7 +1963,6 @@ PyObject *state = NULL; PyObject *listitems = Py_None; PyObject *dictitems = Py_None; - Py_ssize_t size; int use_newobj = self->proto >= 2; @@ -1971,13 +1970,6 @@ 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; @@ -2154,6 +2146,7 @@ PyObject *reduce_value = NULL; PyObject *memo_key = NULL; int status = 0; + Py_ssize_t size; if (Py_EnterRecursiveCall(" while pickling an object") < 0) return -1; @@ -2332,6 +2325,13 @@ goto error; } + size = PyTuple_Size(reduce_value); + if (size < 2 || size > 5) { + PyErr_SetString(PicklingError, "tuple returned by " + "__reduce__ must contain 2 through 5 elements"); + goto error; + } + status = save_reduce(self, reduce_value, obj); if (0) {