diff -r 95d09ba14aa7 Lib/test/pickletester.py --- a/Lib/test/pickletester.py Wed Apr 15 18:34:17 2015 -0400 +++ b/Lib/test/pickletester.py Thu Apr 16 08:51:31 2015 -0500 @@ -906,7 +906,6 @@ y = self.loads(s) self.assertEqual(y._proto, proto) - @unittest.skip("FIXME: max recursion") def test_reduce_calls_base(self): for proto in protocols: x = REX_five() @@ -1093,7 +1092,6 @@ self.module.Pickler(f, -1) self.module.Pickler(f, protocol=-1) - @unittest.skip("FIXME: not working.") def test_incomplete_input(self): s = StringIO.StringIO("X''.") self.assertRaises(EOFError, self.module.load, s) @@ -1108,7 +1106,6 @@ exec teststr in {'__builtins__': builtins}, d d['f']() - @unittest.skip("FIXME: not working.") def test_bad_input(self): # Test issue4298 s = '\x58\0\0\0\x54' diff -r 95d09ba14aa7 src/org/python/core/PyObject.java --- a/src/org/python/core/PyObject.java Wed Apr 15 18:34:17 2015 -0400 +++ b/src/org/python/core/PyObject.java Thu Apr 16 08:51:31 2015 -0500 @@ -125,7 +125,7 @@ throw Py.TypeError(String.format("Can't instantiate abstract class %s with abstract " + "methods %s", subtype.fastGetName(), methods)); } - + return new_.for_type == subtype ? new PyObject() : new PyObjectDerived(subtype); } @@ -3950,6 +3950,25 @@ } /** + * A common helper method, use to prevent infinite recursion + * when a Python object implements __reduce__ and sometimes calls + * object.__reduce__. Trying to do it all in __reduce__ex__ caused + # this problem. See http://bugs.jython.org/issue2323. + */ + private PyObject commonReduce(int proto) { + PyObject res; + + if (proto >= 2) { + res = reduce_2(); + } else { + PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); + PyObject copyreg_reduce = copyreg.__findattr__("_reduce_ex"); + res = copyreg_reduce.__call__(this, new PyInteger(proto)); + } + return res; + } + + /** * Used for pickling. Default implementation calls object___reduce__. * * @return a tuple of (class, tuple) @@ -3960,7 +3979,7 @@ @ExposedMethod(doc = BuiltinDocs.object___reduce___doc) final PyObject object___reduce__() { - return object___reduce_ex__(0); + return commonReduce(0); } /** Used for pickling. If the subclass specifies __reduce__, it will @@ -3987,12 +4006,8 @@ if (clsreduce != objreduce) { res = this.__reduce__(); - } else if (arg >= 2) { - res = reduce_2(); } else { - PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); - PyObject copyreg_reduce = copyreg.__findattr__("_reduce_ex"); - res = copyreg_reduce.__call__(this, new PyInteger(arg)); + res = commonReduce(arg); } return res; } diff -r 95d09ba14aa7 src/org/python/modules/cPickle.java --- a/src/org/python/modules/cPickle.java Wed Apr 15 18:34:17 2015 -0400 +++ b/src/org/python/modules/cPickle.java Thu Apr 16 08:51:31 2015 -0500 @@ -610,7 +610,6 @@ return dumps(object, 0); } - /** * Shorthand function which pickles and returns the string representation. * @param object a data object which should be pickled. @@ -623,7 +622,6 @@ return file.getvalue(); } - /** * Shorthand function which unpickles a object from the file and returns * the new object. @@ -633,7 +631,16 @@ * @return a new object. */ public static Object load(PyObject file) { - return new Unpickler(file).load(); + try { + return new Unpickler(file).load(); + } + catch (ArrayIndexOutOfBoundsException e) { + // invalid data, bad stack + throw Py.IndexError(e.getMessage()); + } catch (StringIndexOutOfBoundsException e) { + // short data + throw Py.EOFError(e.getMessage()); + } } @@ -646,13 +653,13 @@ */ public static Object loads(PyObject str) { cStringIO.StringIO file = cStringIO.StringIO(str.toString()); - return new Unpickler(file).load(); + return load(file); } // Factory for creating PyIOFile representation. - + /** * The Pickler object * @see cPickle#Pickler(PyObject)