diff options
author | Benjamin Peterson <benjamin@python.org> | 2018-09-10 15:43:10 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-09-10 15:43:10 (GMT) |
commit | d545869d084e70d4838310e79b52a25a72a1ca56 (patch) | |
tree | 56b624b6b77b7db4a8f12952480e0224e228c72c /Python | |
parent | 54752533b2ed1c898ffe5ec2e795c6910ee46a39 (diff) | |
download | cpython-d545869d084e70d4838310e79b52a25a72a1ca56.zip cpython-d545869d084e70d4838310e79b52a25a72a1ca56.tar.gz cpython-d545869d084e70d4838310e79b52a25a72a1ca56.tar.bz2 |
bpo-34588: Fix an off-by-one error in traceback formatting. (GH-9077)
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 'Python')
-rw-r--r-- | Python/traceback.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/Python/traceback.c b/Python/traceback.c index 21fb034..5b5c715 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -511,16 +511,21 @@ tb_displayline(PyObject *f, PyObject *filename, int lineno, PyObject *name) return err; } +static const int TB_RECURSIVE_CUTOFF = 3; // Also hardcoded in traceback.py. + static int tb_print_line_repeated(PyObject *f, long cnt) { - int err; + cnt -= TB_RECURSIVE_CUTOFF; PyObject *line = PyUnicode_FromFormat( - " [Previous line repeated %ld more times]\n", cnt-3); + (cnt > 1) + ? " [Previous line repeated %ld more times]\n" + : " [Previous line repeated %ld more time]\n", + cnt); if (line == NULL) { return -1; } - err = PyFile_WriteObject(line, f, Py_PRINT_RAW); + int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); return err; } @@ -544,15 +549,11 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) tb = tb->tb_next; } while (tb != NULL && err == 0) { - if (last_file != NULL && - tb->tb_frame->f_code->co_filename == last_file && - last_line != -1 && tb->tb_lineno == last_line && - last_name != NULL && tb->tb_frame->f_code->co_name == last_name) - { - cnt++; - } - else { - if (cnt > 3) { + if (last_file == NULL || + tb->tb_frame->f_code->co_filename != last_file || + last_line == -1 || tb->tb_lineno != last_line || + last_name == NULL || tb->tb_frame->f_code->co_name != last_name) { + if (cnt > TB_RECURSIVE_CUTOFF) { err = tb_print_line_repeated(f, cnt); } last_file = tb->tb_frame->f_code->co_filename; @@ -560,7 +561,8 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) last_name = tb->tb_frame->f_code->co_name; cnt = 0; } - if (err == 0 && cnt < 3) { + cnt++; + if (err == 0 && cnt <= TB_RECURSIVE_CUTOFF) { err = tb_displayline(f, tb->tb_frame->f_code->co_filename, tb->tb_lineno, @@ -571,7 +573,7 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) } tb = tb->tb_next; } - if (err == 0 && cnt > 3) { + if (err == 0 && cnt > TB_RECURSIVE_CUTOFF) { err = tb_print_line_repeated(f, cnt); } return err; |