Skip to content

Commit bae12e9

Browse files
committed
Fix possible SystemError on throw to new greenlets
1 parent 9091d4c commit bae12e9

File tree

2 files changed

+19
-0
lines changed

2 files changed

+19
-0
lines changed

greenlet.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,13 +584,21 @@ static void GREENLET_NOINLINE(g_initialstub)(void* mark)
584584
{
585585
int err;
586586
PyObject* o;
587+
PyObject *exc, *val, *tb;
587588

589+
/* save exception in case getattr clears it */
590+
PyErr_Fetch(&exc, &val, &tb);
588591
/* ts_target.run is the object to call in the new greenlet */
589592
PyObject* run = PyObject_GetAttrString((PyObject*) ts_target, "run");
590593
if (run == NULL) {
591594
g_passaround_clear();
595+
Py_XDECREF(exc);
596+
Py_XDECREF(val);
597+
Py_XDECREF(tb);
592598
return;
593599
}
600+
/* restore saved exception */
601+
PyErr_Restore(exc, val, tb);
594602
/* now use run_info to store the statedict */
595603
o = ts_target->run_info;
596604
ts_target->run_info = green_statedict(ts_target->parent);

tests/test_greenlet.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,14 @@ def test_parent_return_failure(self):
320320
g2 = greenlet(lambda: None, parent=g1)
321321
# AttributeError should propagate to us, no fatal errors
322322
self.assertRaises(AttributeError, g2.switch)
323+
324+
def test_throw_exception_not_lost(self):
325+
class mygreenlet(greenlet):
326+
def __getattribute__(self, name):
327+
try:
328+
raise Exception()
329+
except:
330+
pass
331+
return greenlet.__getattribute__(self, name)
332+
g = mygreenlet(lambda: None)
333+
self.assertRaises(SomeError, g.throw, SomeError())

0 commit comments

Comments
 (0)