diff options
author | Amaury Forgeot d'Arc <amauryfa@gmail.com> | 2008-07-31 00:42:16 (GMT) |
---|---|---|
committer | Amaury Forgeot d'Arc <amauryfa@gmail.com> | 2008-07-31 00:42:16 (GMT) |
commit | 246daedd11b7b2155963ffc1bf2b77518fd9b2e0 (patch) | |
tree | bd2cda04804e59399b960689d9c49c10e1195d1a | |
parent | b8827c00b8f4c11e202a7c2401aca1c42531188c (diff) | |
download | cpython-246daedd11b7b2155963ffc1bf2b77518fd9b2e0.zip cpython-246daedd11b7b2155963ffc1bf2b77518fd9b2e0.tar.gz cpython-246daedd11b7b2155963ffc1bf2b77518fd9b2e0.tar.bz2 |
#2542: now that issubclass() may call arbitrary code,
make sure that PyErr_ExceptionMatches returns 0 when an exception occurs there.
-rw-r--r-- | Lib/test/test_exceptions.py | 35 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/errors.c | 15 |
3 files changed, 49 insertions, 4 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 8fa466c..5a0039e 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -6,13 +6,21 @@ import unittest import pickle, cPickle from test.test_support import (TESTFN, unlink, run_unittest, - catch_warning) + catch_warning, captured_output) from test.test_pep352 import ignore_message_warning # XXX This is not really enough, each *operation* should be tested! class ExceptionTests(unittest.TestCase): + def test00(self): + try: + sys.exit(ValueError('aaa')) + except SystemExit: + pass + finally: + pass + def testReload(self): # Reloading the built-in exceptions module failed prior to Py2.2, while it # should act the same as reloading built-in sys. @@ -344,6 +352,31 @@ class ExceptionTests(unittest.TestCase): self.failUnless(unicode(Exception(u'a'))) self.failUnless(unicode(Exception(u'\xe1'))) + def test_badisinstance(self): + # Bug #2542: if issubclass(e, MyException) raises an exception, + # it should be ignored + class Meta(type): + def __subclasscheck__(cls, subclass): + raise ValueError() + + class MyException(Exception): + __metaclass__ = Meta + pass + + with captured_output("stderr") as stderr: + try: + raise KeyError() + except MyException, e: + self.fail("exception should not be a MyException") + except KeyError: + pass + except: + self.fail("Should have raised TypeError") + else: + self.fail("Should have raised TypeError") + self.assertEqual(stderr.getvalue(), + "Exception ValueError: ValueError() in " + "<type 'exceptions.KeyError'> ignored\n") def test_main(): run_unittest(ExceptionTests) @@ -12,6 +12,9 @@ What's New in Python 2.6 beta 3? Core and Builtins ----------------- +- Issue #2542: Now that issubclass() may call arbitrary code, ensure that + PyErr_ExceptionMatches returns 0 when an exception occurs there. + - Issue #1819: function calls with several named parameters are now on average 35% faster (as measured by pybench). diff --git a/Python/errors.c b/Python/errors.c index 8951d57..5d9cab5 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -106,9 +106,18 @@ PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc) err = PyExceptionInstance_Class(err); if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) { - /* problems here!? not sure PyObject_IsSubclass expects to - be called with an exception pending... */ - return PyObject_IsSubclass(err, exc); + int res = 0; + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + res = PyObject_IsSubclass(err, exc); + /* This function must not fail, so print the error here */ + if (res == -1) { + PyErr_WriteUnraisable(err); + /* issubclass did not succeed */ + res = 0; + } + PyErr_Restore(exception, value, tb); + return res; } return err == exc; |