Skip to content

Commit

Permalink
closes bpo-39091: Fix segfault when Exception constructor returns non…
Browse files Browse the repository at this point in the history
…-exception for gen.throw. (#17658)

Co-authored-by: Benjamin Peterson <benjamin@python.org>
  • Loading branch information
coolreader18 and benjaminp committed Aug 3, 2021
1 parent 54f185b commit 83ca46b
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 4 deletions.
26 changes: 26 additions & 0 deletions Lib/test/test_generators.py
Expand Up @@ -270,6 +270,32 @@ def gen():
self.assertEqual(next(g), "done")
self.assertEqual(sys.exc_info(), (None, None, None))

def test_except_throw_bad_exception(self):
class E(Exception):
def __new__(cls, *args, **kwargs):
return cls

def boring_generator():
yield

gen = boring_generator()

err_msg = 'should have returned an instance of BaseException'

with self.assertRaisesRegex(TypeError, err_msg):
gen.throw(E)

self.assertRaises(StopIteration, next, gen)

def generator():
with self.assertRaisesRegex(TypeError, err_msg):
yield

gen = generator()
next(gen)
with self.assertRaises(StopIteration):
gen.throw(E)

def test_stopiteration_error(self):
# See also PEP 479.

Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Expand Up @@ -1300,6 +1300,7 @@ Peter Otten
Michael Otteneder
Richard Oudkerk
Russel Owen
Noah Oxer
Joonas Paalasmaa
Yaroslav Pankovych
Martin Packman
Expand Down
@@ -0,0 +1 @@
Fix crash when using passing a non-exception to a generator's ``throw()`` method. Patch by Noah Oxer
20 changes: 16 additions & 4 deletions Python/errors.c
Expand Up @@ -85,17 +85,29 @@ _PyErr_GetTopmostException(PyThreadState *tstate)
}

static PyObject*
_PyErr_CreateException(PyObject *exception, PyObject *value)
_PyErr_CreateException(PyObject *exception_type, PyObject *value)
{
PyObject *exc;

if (value == NULL || value == Py_None) {
return _PyObject_CallNoArg(exception);
exc = _PyObject_CallNoArg(exception_type);
}
else if (PyTuple_Check(value)) {
return PyObject_Call(exception, value, NULL);
exc = PyObject_Call(exception_type, value, NULL);
}
else {
return PyObject_CallOneArg(exception, value);
exc = PyObject_CallOneArg(exception_type, value);
}

if (exc != NULL && !PyExceptionInstance_Check(exc)) {
PyErr_Format(PyExc_TypeError,
"calling %R should have returned an instance of "
"BaseException, not %s",
exception_type, Py_TYPE(exc)->tp_name);
Py_CLEAR(exc);
}

return exc;
}

void
Expand Down

0 comments on commit 83ca46b

Please sign in to comment.