diff -r 99ef4501205b Lib/test/test_exceptions.py --- a/Lib/test/test_exceptions.py Thu May 10 16:11:12 2012 +0100 +++ b/Lib/test/test_exceptions.py Sat May 12 13:34:05 2012 +0300 @@ -6,6 +6,7 @@ import pickle import weakref import errno +import abc from test.support import (TESTFN, unlink, run_unittest, captured_output, gc_collect, cpython_only, no_tracing) @@ -444,6 +445,26 @@ return -1 self.assertRaises(RuntimeError, g) + def testExceptionIsSubclass(self): + # Test that exceptions that register with abc are properly caught + # as a base of the original exception. See #12029. + class MyException(Exception, metaclass=abc.ABCMeta): + pass + + class MyOriginalException(Exception): + pass + + MyException.register(MyOriginalException) + caught = False + try: + raise MyOriginalException() + except MyException: + caught = True + except: + pass + + self.assertTrue(caught) + def test_str(self): # Make sure both instances and classes have a str representation. self.assertTrue(str(Exception)) diff -r 99ef4501205b Lib/test/test_sys.py --- a/Lib/test/test_sys.py Thu May 10 16:11:12 2012 +0100 +++ b/Lib/test/test_sys.py Sat May 12 13:34:05 2012 +0300 @@ -215,6 +215,18 @@ self.assertEqual(sys.getrecursionlimit(), 10000) sys.setrecursionlimit(oldlimit) + self.assertRaises(OverflowError, sys.setrecursionlimit, 1 << 31) + try: + sys.setrecursionlimit((1 << 31) - 5) + try: + # issue13546: isinstance(e, ValueError) used to fail + # when the recursion limit is close to 1<<31 + raise ValueError() + except ValueError as e: + pass + finally: + sys.setrecursionlimit(oldlimit) + @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(), 'fatal error if run with a trace function') def test_recursionlimit_recovery(self): diff -r 99ef4501205b Python/errors.c --- a/Python/errors.c Thu May 10 16:11:12 2012 +0100 +++ b/Python/errors.c Sat May 12 13:34:05 2012 +0300 @@ -166,12 +166,18 @@ err = PyExceptionInstance_Class(err); if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) { - int res = 0; + int res = 0, reclimit; PyObject *exception, *value, *tb; PyErr_Fetch(&exception, &value, &tb); - /* PyObject_IsSubclass() can recurse and therefore is - not safe (see test_bad_getattr in test.pickletester). */ - res = PyType_IsSubtype((PyTypeObject *)err, (PyTypeObject *)exc); + /* Temporarily bump the recursion limit, so that in the most + common case PyObject_IsSubclass will not raise a recursion + error we have to ignore anyway. Don't do it when the limit + is already insanely high, to avoid overflow */ + reclimit = Py_GetRecursionLimit(); + if (reclimit < (1 << 30)) + Py_SetRecursionLimit(reclimit + 5); + res = PyObject_IsSubclass(err, exc); + Py_SetRecursionLimit(reclimit); /* This function must not fail, so print the error here */ if (res == -1) { PyErr_WriteUnraisable(err);