From 66aa6453d641cfce82108825f9e9e29654851cb8 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 2 May 2020 21:12:48 -0700 Subject: [PATCH 1/2] Remove the exc_value NULL check and add a failing test. --- Lib/test/test_generators.py | 19 +++++++++++++++++++ Objects/genobject.c | 6 ++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 4d96f44b150622..ccd13ff42b59b9 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -332,6 +332,25 @@ def f(): context = cm.exception.__context__ self.assertEqual((type(context), context.args), (KeyError, ('a',))) + def test_throw_after_none_exc_type(self): + def g(): + try: + raise KeyError + except KeyError: + pass + + try: + yield + except Exception: + # This line causes a crash ("Segmentation fault (core dumped)") + # on e.g. Fedora 32. + raise RuntimeError + + gen = g() + gen.send(None) + with self.assertRaises(RuntimeError) as cm: + gen.throw(ValueError) + class YieldFromTests(unittest.TestCase): def test_generator_gi_yieldfrom(self): diff --git a/Objects/genobject.c b/Objects/genobject.c index 41a63ae2e666aa..65ad9d4d3d07b0 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -512,11 +512,9 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, } PyErr_Restore(typ, val, tb); - /* XXX Should we also handle the case where exc_type is true and - exc_value is false? */ - if (gen->gi_exc_state.exc_type && gen->gi_exc_state.exc_value) { + if (gen->gi_exc_state.exc_type) { Py_INCREF(gen->gi_exc_state.exc_type); - Py_INCREF(gen->gi_exc_state.exc_value); + Py_XINCREF(gen->gi_exc_state.exc_value); Py_XINCREF(gen->gi_exc_state.exc_traceback); _PyErr_ChainExceptions(gen->gi_exc_state.exc_type, gen->gi_exc_state.exc_value, gen->gi_exc_state.exc_traceback); From 66ae854acbeacc30553e20812b50d9f731bec3a7 Mon Sep 17 00:00:00 2001 From: Chris Jerdonek Date: Sat, 2 May 2020 21:20:18 -0700 Subject: [PATCH 2/2] Check that exc_type doesn't equal Py_None. --- Lib/test/test_generators.py | 5 +++-- Objects/genobject.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index ccd13ff42b59b9..5824ecd7c37e88 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -342,8 +342,9 @@ def g(): try: yield except Exception: - # This line causes a crash ("Segmentation fault (core dumped)") - # on e.g. Fedora 32. + # Without the `gi_exc_state.exc_type != Py_None` in + # _gen_throw(), this line was causing a crash ("Segmentation + # fault (core dumped)") on e.g. Fedora 32. raise RuntimeError gen = g() diff --git a/Objects/genobject.c b/Objects/genobject.c index 65ad9d4d3d07b0..b27fa929a26258 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -512,7 +512,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, } PyErr_Restore(typ, val, tb); - if (gen->gi_exc_state.exc_type) { + /* XXX It seems like we shouldn't have to check not equal to Py_None + here because exc_type should only ever be a class. But not including + this check was causing crashes on certain tests e.g. on Fedora. */ + if (gen->gi_exc_state.exc_type && gen->gi_exc_state.exc_type != Py_None) { Py_INCREF(gen->gi_exc_state.exc_type); Py_XINCREF(gen->gi_exc_state.exc_value); Py_XINCREF(gen->gi_exc_state.exc_traceback);