From ab9a2d884b3a4abe319606ea95a5a6d6b01cd73a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 9 May 2023 21:15:30 +0100 Subject: [PATCH] patch 9.0.1532: crash when expanding "~" in substitute causes very long text Problem: Crash when expanding "~" in substitute causes very long text. Solution: Limit the text length to MAXCOL. --- src/regexp.c | 30 +++++++++++++++++++----------- src/testdir/test_substitute.vim | 14 ++++++++++++++ src/version.c | 2 ++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/regexp.c b/src/regexp.c index 33b36d11a8be1..0e6c746df8197 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -1767,10 +1767,7 @@ do_Lower(int *d, int c) regtilde(char_u *source, int magic) { char_u *newsub = source; - char_u *tmpsub; char_u *p; - int len; - int prevlen; for (p = newsub; *p; ++p) { @@ -1779,24 +1776,35 @@ regtilde(char_u *source, int magic) if (reg_prev_sub != NULL) { // length = len(newsub) - 1 + len(prev_sub) + 1 - prevlen = (int)STRLEN(reg_prev_sub); - tmpsub = alloc(STRLEN(newsub) + prevlen); + // Avoid making the text longer than MAXCOL, it will cause + // trouble at some point. + size_t prevsublen = STRLEN(reg_prev_sub); + size_t newsublen = STRLEN(newsub); + if (prevsublen > MAXCOL || newsublen > MAXCOL + || newsublen + prevsublen > MAXCOL) + { + emsg(_(e_resulting_text_too_long)); + break; + } + + char_u *tmpsub = alloc(newsublen + prevsublen); if (tmpsub != NULL) { // copy prefix - len = (int)(p - newsub); // not including ~ - mch_memmove(tmpsub, newsub, (size_t)len); + size_t prefixlen = p - newsub; // not including ~ + mch_memmove(tmpsub, newsub, prefixlen); // interpret tilde - mch_memmove(tmpsub + len, reg_prev_sub, (size_t)prevlen); + mch_memmove(tmpsub + prefixlen, reg_prev_sub, + prevsublen); // copy postfix if (!magic) ++p; // back off backslash - STRCPY(tmpsub + len + prevlen, p + 1); + STRCPY(tmpsub + prefixlen + prevsublen, p + 1); - if (newsub != source) // already allocated newsub + if (newsub != source) // allocated newsub before vim_free(newsub); newsub = tmpsub; - p = newsub + len + prevlen; + p = newsub + prefixlen + prevsublen; } } else if (magic) diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim index 7491b6163dc82..32e2f2785479d 100644 --- a/src/testdir/test_substitute.vim +++ b/src/testdir/test_substitute.vim @@ -1414,6 +1414,20 @@ func Test_substitute_short_cmd() bw! endfunc +" Check handling expanding "~" resulting in extremely long text. +func Test_substitute_tilde_too_long() + enew! + + s/.*/ixxx + s//~~~~~~~~~AAAAAAA@( + + " Either fails with "out of memory" or "text too long". + " This can take a long time. + call assert_fails('sil! norm &&&&&&&&&', ['E1240:\|E342:']) + + bwipe! +endfunc + " This should be done last to reveal a memory leak when vim_regsub_both() is " called to evaluate an expression but it is not used in a second call. func Test_z_substitute_expr_leak() diff --git a/src/version.c b/src/version.c index 7ee9f575f9bd9..3fb73b25ea337 100644 --- a/src/version.c +++ b/src/version.c @@ -695,6 +695,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1532, /**/ 1531, /**/