From: Christian Brabandt Date: Sun, 3 May 2026 18:32:11 +0000 (+0000) Subject: patch 9.2.0436: Buffer overflow when parsing overlong errorformat lines X-Git-Tag: v9.2.0436^0 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=77677c33dec485aadd371da75cce55d449b51798;p=thirdparty%2Fvim.git patch 9.2.0436: Buffer overflow when parsing overlong errorformat lines Problem: When an error line in a file passed to :cfile / :cgetfile is longer than IOSIZE, qf_parse_file_pfx() copies the tail into the fixed-size IObuff with STRMOVE(), overflowing the heap buffer. The same code path can also loop indefinitely because qf_parse_file_pfx() always returns QF_MULTISCAN when a tail is present, and qf_init_ext() unconditionally goes to "restofline" without bounding the tail length (Nabih). Solution: Remove the STRMOVE() into IObuff. In the QF_MULTISCAN branch, alias linebuf into the tail directly and update linelen, requiring strict progress (new length less than the previous length) before retrying; otherwise ignore the line. closes: #20126 Supported by AI Signed-off-by: Christian Brabandt --- diff --git a/src/quickfix.c b/src/quickfix.c index 902c4e6f66..feeec18125 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -1412,7 +1412,6 @@ qf_parse_file_pfx( *fields->namebuf = NUL; if (tail && *tail) { - STRMOVE(IObuff, skipwhite(tail)); qfl->qf_multiscan = TRUE; return QF_MULTISCAN; } @@ -1579,7 +1578,15 @@ restofline: { // global file names status = qf_parse_file_pfx(idx, fields, qfl, tail); if (status == QF_MULTISCAN) + { + char_u *s = skipwhite(tail); + int new_linelen = (int)STRLEN(s); + if (new_linelen >= linelen) + return QF_IGNORE_LINE; + linebuf = s; + linelen = new_linelen; goto restofline; + } } if (fmt_ptr->flags == '-') // generally exclude this line { diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 69a4f6dafa..64ec97f504 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -7006,4 +7006,26 @@ func Test_quickfix_longline_noeol() call assert_equal(['okay'], readfile("XDONE")) endfunc +func Test_efm_overlongline() + let save_efm = &efm + " %r captures the tail. + set efm=%+O(%.%#)%r,%f:%l:%m + + " First line is longer than IOSIZE (1025) so the parser puts it in + " growbuf; the %r tail then far exceeds IObuff. + let lines = ['(short)' .. repeat('x', 4000), 'Xfile:10:msg'] + call writefile(lines, 'Xqferrlong', 'D') + + " Must complete without hanging or crashing. + cgetfile Xqferrlong + + " The well-formed line that follows is still parsed. + let well_formed = filter(getqflist(), 'v:val.lnum == 10') + call assert_equal(1, len(well_formed)) + call assert_equal('msg', well_formed[0].text) + + let &efm = save_efm + call setqflist([], 'f') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 2691f438b0..f377ae58ee 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 436, /**/ 435, /**/