diff options
author | AlexTate <0xalextate@gmail.com> | 2022-12-04 19:37:55 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-04 19:37:55 (GMT) |
commit | 72ec518203c3f3577a5e888b12f10bb49060e6c2 (patch) | |
tree | 08f93da53cbb5efaeaefce304798548a97c686fa /Lib/unittest | |
parent | 1012dc1b4367e05b92d67ea6925a39d50dce31b7 (diff) | |
download | cpython-72ec518203c3f3577a5e888b12f10bb49060e6c2.zip cpython-72ec518203c3f3577a5e888b12f10bb49060e6c2.tar.gz cpython-72ec518203c3f3577a5e888b12f10bb49060e6c2.tar.bz2 |
gh-98458: unittest: bugfix for infinite loop while handling chained exceptions that contain cycles (#98459)
* Bugfix addressing infinite loop while handling self-referencing chained exception in TestResult._clean_tracebacks()
* Bugfix extended to properly handle exception cycles in _clean_tracebacks. The "seen" set follows the approach used in the TracebackException class (thank you @iritkatriel for pointing it out)
* adds a test for a single chained exception that holds a self-loop in its __cause__ and __context__ attributes
Diffstat (limited to 'Lib/unittest')
-rw-r--r-- | Lib/unittest/result.py | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py index 3da7005..5ca4c23 100644 --- a/Lib/unittest/result.py +++ b/Lib/unittest/result.py @@ -196,6 +196,7 @@ class TestResult(object): ret = None first = True excs = [(exctype, value, tb)] + seen = {id(value)} # Detect loops in chained exceptions. while excs: (exctype, value, tb) = excs.pop() # Skip test runner traceback levels @@ -214,8 +215,9 @@ class TestResult(object): if value is not None: for c in (value.__cause__, value.__context__): - if c is not None: + if c is not None and id(c) not in seen: excs.append((type(c), c, c.__traceback__)) + seen.add(id(c)) return ret def _is_relevant_tb_level(self, tb): |