summaryrefslogtreecommitdiff
path: root/Lib/traceback.py
diff options
context:
space:
mode:
authorBenjamin Peterson <benjamin@python.org>2018-09-05 22:57:02 -0700
committerBenjamin Peterson <benjamin@python.org>2018-09-09 22:26:27 -0700
commit59936ae7b56db8798b37bfb313558b43008c9cae (patch)
treea9df6c3ffc0a1c1ce443f278cf15dfc999f9a02c /Lib/traceback.py
parent0afada163c7ef25c3a9d46ed445481fb69f2ecaf (diff)
downloadcpython-git-benjamin-traceback-obo.tar.gz
bpo-34588: Fix an off-by-one error in traceback formatting.benjamin-traceback-obo
The recursive frame pruning code always undercounted the number of elided frames by one. That is, in the "[Previous line repeated N more times]" message, N would always be one too few. Near the recursive pruning cutoff, one frame could be silently dropped. That situation is demonstrated in the OP of the bug report. The fix is to start the identical frame counter at 1.
Diffstat (limited to 'Lib/traceback.py')
-rw-r--r--Lib/traceback.py29
1 files changed, 19 insertions, 10 deletions
diff --git a/Lib/traceback.py b/Lib/traceback.py
index afab0a4b91..4e7605d15f 100644
--- a/Lib/traceback.py
+++ b/Lib/traceback.py
@@ -310,6 +310,8 @@ def walk_tb(tb):
tb = tb.tb_next
+_RECURSIVE_CUTOFF = 3 # Also hardcoded in traceback.c.
+
class StackSummary(list):
"""A stack of frames."""
@@ -398,18 +400,21 @@ class StackSummary(list):
last_name = None
count = 0
for frame in self:
- if (last_file is not None and last_file == frame.filename and
- last_line is not None and last_line == frame.lineno and
- last_name is not None and last_name == frame.name):
- count += 1
- else:
- if count > 3:
- result.append(f' [Previous line repeated {count-3} more times]\n')
+ if (last_file is None or last_file != frame.filename or
+ last_line is None or last_line != frame.lineno or
+ last_name is None or last_name != frame.name):
+ if count > _RECURSIVE_CUTOFF:
+ count -= _RECURSIVE_CUTOFF
+ result.append(
+ f' [Previous line repeated {count} more '
+ f'time{"s" if count > 1 else ""}]\n'
+ )
last_file = frame.filename
last_line = frame.lineno
last_name = frame.name
count = 0
- if count >= 3:
+ count += 1
+ if count > _RECURSIVE_CUTOFF:
continue
row = []
row.append(' File "{}", line {}, in {}\n'.format(
@@ -420,8 +425,12 @@ class StackSummary(list):
for name, value in sorted(frame.locals.items()):
row.append(' {name} = {value}\n'.format(name=name, value=value))
result.append(''.join(row))
- if count > 3:
- result.append(f' [Previous line repeated {count-3} more times]\n')
+ if count > _RECURSIVE_CUTOFF:
+ count -= _RECURSIVE_CUTOFF
+ result.append(
+ f' [Previous line repeated {count} more '
+ f'time{"s" if count > 1 else ""}]\n'
+ )
return result