From 4d6c0c0cce05befa06e0cad7351b1303ac048277 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 22 Nov 2021 16:56:23 +0000 Subject: bpo-45871: Refactor except matcher validation into a separate function so that it can be reused. Add missing unit test. (GH-29711) --- Lib/test/test_exceptions.py | 15 ++++++++++++ Python/ceval.c | 56 ++++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4c18a59..eee178c 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2401,6 +2401,21 @@ class SyntaxErrorTests(unittest.TestCase): self.assertRaises(TypeError, SyntaxError, "bad bad", args) +class TestInvalidExceptionMatcher(unittest.TestCase): + def test_except_star_invalid_exception_type(self): + with self.assertRaises(TypeError): + try: + raise ValueError + except 42: + pass + + with self.assertRaises(TypeError): + try: + raise ValueError + except (ValueError, 42): + pass + + class PEP626Tests(unittest.TestCase): def lineno_after_raise(self, f, *expected): diff --git a/Python/ceval.c b/Python/ceval.c index 9e56b50..1d69708 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -93,6 +93,7 @@ static int import_all_from(PyThreadState *, PyObject *, PyObject *); static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyObject *); static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg); static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg); +static int check_except_type_valid(PyThreadState *tstate, PyObject* right); static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs); static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); @@ -3715,31 +3716,11 @@ check_eval_breaker: } TARGET(JUMP_IF_NOT_EXC_MATCH) { - const char *cannot_catch_msg = "catching classes that do not " - "inherit from BaseException is not " - "allowed"; PyObject *right = POP(); PyObject *left = TOP(); - if (PyTuple_Check(right)) { - Py_ssize_t i, length; - length = PyTuple_GET_SIZE(right); - for (i = 0; i < length; i++) { - PyObject *exc = PyTuple_GET_ITEM(right, i); - if (!PyExceptionClass_Check(exc)) { - _PyErr_SetString(tstate, PyExc_TypeError, - cannot_catch_msg); - Py_DECREF(right); - goto error; - } - } - } - else { - if (!PyExceptionClass_Check(right)) { - _PyErr_SetString(tstate, PyExc_TypeError, - cannot_catch_msg); - Py_DECREF(right); - goto error; - } + if (check_except_type_valid(tstate, right) < 0) { + Py_DECREF(right); + goto error; } int res = PyErr_GivenExceptionMatches(left, right); Py_DECREF(right); @@ -6892,6 +6873,35 @@ import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v) return err; } + +#define CANNOT_CATCH_MSG "catching classes that do not inherit from "\ + "BaseException is not allowed" + +static int +check_except_type_valid(PyThreadState *tstate, PyObject* right) +{ + if (PyTuple_Check(right)) { + Py_ssize_t i, length; + length = PyTuple_GET_SIZE(right); + for (i = 0; i < length; i++) { + PyObject *exc = PyTuple_GET_ITEM(right, i); + if (!PyExceptionClass_Check(exc)) { + _PyErr_SetString(tstate, PyExc_TypeError, + CANNOT_CATCH_MSG); + return -1; + } + } + } + else { + if (!PyExceptionClass_Check(right)) { + _PyErr_SetString(tstate, PyExc_TypeError, + CANNOT_CATCH_MSG); + return -1; + } + } + return 0; +} + static int check_args_iterable(PyThreadState *tstate, PyObject *func, PyObject *args) { -- cgit v0.12