Skip to content

Commit

Permalink
Merge 23d22f5 into ecfd960
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Dec 10, 2020
2 parents ecfd960 + 23d22f5 commit 7ce65b9
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
4 changes: 4 additions & 0 deletions docs/changes/1704.bugfix
@@ -0,0 +1,4 @@
Make error reporting when a greenlet suffers a `RecursionError` more
reliable.

Reported by Dan Milon.
15 changes: 13 additions & 2 deletions src/gevent/greenlet.py
Expand Up @@ -565,7 +565,12 @@ def exc_info(self):
"""
ei = self._exc_info
if ei is not None and ei[0] is not None:
return (ei[0], ei[1], load_traceback(ei[2]))
return (
ei[0],
ei[1],
# The pickled traceback may be None if we couldn't pickle it.
load_traceback(ei[2]) if ei[2] else None
)

def throw(self, *args):
"""Immediately switch into the greenlet and raise an exception in it.
Expand Down Expand Up @@ -834,7 +839,13 @@ def __report_error(self, exc_info):
self.__report_result(exc_info[1])
return

self._exc_info = exc_info[0], exc_info[1], dump_traceback(exc_info[2])
# Depending on the error, we may not be able to pickle it.
# In particular, RecursionError can be a problem.
try:
tb = dump_traceback(exc_info[2])
except: # pylint:disable=bare-except
tb = None
self._exc_info = exc_info[0], exc_info[1], tb

hub = get_my_hub(self) # pylint:disable=undefined-variable
if self._links and not self._notifier:
Expand Down
41 changes: 41 additions & 0 deletions src/gevent/tests/test__greenlet.py
Expand Up @@ -598,6 +598,47 @@ def test_exc_info_no_error(self):
g.join()
self.assertFalse(g.exc_info)

def test_recursion_error(self):
# https://github.com/gevent/gevent/issues/1704
# A RuntimeError: recursion depth exceeded
# does not break things.
def recur():
recur() # This is expected to raise RecursionError

errors = []
def handle_error(glet, t, v, tb):
errors.append((glet, t, v, tb))

try:
gevent.get_hub().handle_error = handle_error

g = gevent.spawn(recur)
def wait():
return gevent.joinall([g])

g2 = gevent.spawn(wait)

gevent.joinall([g2])
finally:
del gevent.get_hub().handle_error

try:
expected_exc = RecursionError
except NameError:
expected_exc = RuntimeError
with self.assertRaises(expected_exc):
g.get()

self.assertFalse(g.successful())
self.assertTrue(g.dead)

self.assertTrue(errors)
self.assertEqual(1, len(errors))
self.assertIs(errors[0][0], g)
self.assertEqual(errors[0][1], expected_exc)
del errors[:]


def test_tree_locals(self):
g = g2 = None
def func():
Expand Down

0 comments on commit 7ce65b9

Please sign in to comment.