Index: Lib/test/test_exceptions.py =================================================================== --- Lib/test/test_exceptions.py (revision 54643) +++ Lib/test/test_exceptions.py (working copy) @@ -339,7 +339,25 @@ self.failUnless(str(Exception('a'))) self.failUnless(unicode(Exception(u'a'))) + def testUserExceptionPickling(self): + # Pickling used to fail when an Exception class required + # an argument in the constructor, but didn't call its base + # class' constructor. + e = E("message") + def test(e): + self.assertEquals(e.message, "") + self.assertEquals(e.args, ("message",)) + self.assertEquals(e.something, "message") + test(e) + for p in pickle, cPickle: + for protocol in range(p.HIGHEST_PROTOCOL + 1): + new = p.loads(p.dumps(e, protocol)) + test(new) +class E(Exception): + def __init__(self, something): + self.something = something + def test_main(): run_unittest(ExceptionTests) Index: Objects/exceptions.c =================================================================== --- Objects/exceptions.c (revision 54643) +++ Objects/exceptions.c (working copy) @@ -36,11 +36,8 @@ /* 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; - } + Py_INCREF(args); + self->args = args; self->message = PyString_FromString(""); if (!self->message) { @@ -1998,7 +1995,7 @@ PyMODINIT_FUNC _PyExc_Init(void) { - PyObject *m, *bltinmod, *bdict; + PyObject *m, *bltinmod, *bdict, *args; PRE_INIT(BaseException) PRE_INIT(Exception) @@ -2121,7 +2118,11 @@ POST_INIT(ImportWarning) POST_INIT(UnicodeWarning) - PyExc_MemoryErrorInst = BaseException_new(&_PyExc_MemoryError, NULL, NULL); + args = PyTuple_New(0); + if (args == NULL) + Py_FatalError("Cannot pre-allocate MemoryError instance's args\n"); + PyExc_MemoryErrorInst = BaseException_new(&_PyExc_MemoryError, args, NULL); + Py_DECREF(args); if (!PyExc_MemoryErrorInst) Py_FatalError("Cannot pre-allocate MemoryError instance\n");