diff -r da3f4774b939 Lib/test/pickletester.py --- a/Lib/test/pickletester.py Mon Mar 11 09:14:09 2013 +0200 +++ b/Lib/test/pickletester.py Mon Mar 11 23:00:56 2013 +0530 @@ -1060,6 +1060,18 @@ MyStr, MyUnicode, MyTuple, MyList, MyDict] +class MyException(Exception): + """Extension with values, args not set.""" + def __init__(self, foo): + self.foo = foo + +class MyException2(Exception): + """Extension with values, init called with no args.""" + def __init__(self, foo): + self.foo = foo + Exception.__init__(self) + + class SlotList(MyList): __slots__ = ["foo"] @@ -1111,6 +1123,15 @@ self.module.Pickler(f, -1) self.module.Pickler(f, protocol=-1) + def test_unpickle_exceptions_requiring_args(self): + # Test issue1692335 + c = MyException('testing') + c2 = self.module.loads(self.module.dumps(c)) + self.assertEqual(c2.foo, c.foo) + d = MyException2('testing') + d2 = self.module.loads(self.module.dumps(d)) + self.assertEqual(d2.foo, d.foo) + def test_incomplete_input(self): s = StringIO.StringIO("X''.") self.assertRaises(EOFError, self.module.load, s) diff -r da3f4774b939 Objects/exceptions.c --- a/Objects/exceptions.c Mon Mar 11 09:14:09 2013 +0200 +++ b/Objects/exceptions.c Mon Mar 11 23:00:56 2013 +0530 @@ -35,13 +35,7 @@ if (!self) return NULL; /* the dict is created on the fly in PyObject_GenericSetAttr */ - self->message = self->dict = NULL; - - self->args = PyTuple_New(0); - if (!self->args) { - Py_DECREF(self); - return NULL; - } + self->dict = NULL; self->message = PyString_FromString(""); if (!self->message) { @@ -49,18 +43,38 @@ return NULL; } + if(args){ + self->args = args; + Py_INCREF(args); + /* Since the args can be overwritten in __init__, we have to store + the original args somewhere for pickling. */ + if (PyObject_SetAttrString((PyObject *)self, "__newargs__", args) < 0) { + Py_DECREF(self); + return NULL; + } + } + else{ + self->args = PyTuple_New(0); + if (!self->args) { + Py_DECREF(self); + return NULL; + } + } + return (PyObject *)self; } static int BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) { + PyObject *tmp; if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) return -1; - Py_DECREF(self->args); + tmp = self->args; self->args = args; Py_INCREF(self->args); + Py_XDECREF(tmp); if (PyTuple_GET_SIZE(self->args) == 1) { Py_CLEAR(self->message); @@ -183,10 +197,23 @@ static PyObject * BaseException_reduce(PyBaseExceptionObject *self) { + PyObject *result; + PyObject *newargs = PyObject_GetAttrString((PyObject *)self, "__newargs__"); + if (!newargs) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_SetString(PyExc_AttributeError, + "To pickle exceptions via BaseException.__reduce__, " + "you need to set the __newargs__ attribute in your " + "custom __new__ method."); + } + return NULL; + } if (self->args && self->dict) - return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict); + result = PyTuple_Pack(3, Py_TYPE(self), newargs, self->dict); else - return PyTuple_Pack(2, Py_TYPE(self), self->args); + result = PyTuple_Pack(2, Py_TYPE(self), newargs); + Py_DECREF(newargs); + return result; } /*