diff options
author | Bram Moolenaar <Bram@vim.org> | 2023-05-09 21:15:30 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2023-05-09 21:15:30 +0100 |
commit | ab9a2d884b3a4abe319606ea95a5a6d6b01cd73a (patch) | |
tree | 4677ba8a843e5bddcb87ee8b0a6a5ed62997b700 | |
parent | d1ae8366aff286d41e7f5bc513cc0a1af5130aad (diff) | |
download | vim-git-ab9a2d884b3a4abe319606ea95a5a6d6b01cd73a.tar.gz |
patch 9.0.1532: crash when expanding "~" in substitute causes very long textv9.0.1532
Problem: Crash when expanding "~" in substitute causes very long text.
Solution: Limit the text length to MAXCOL.
-rw-r--r-- | src/regexp.c | 30 | ||||
-rw-r--r-- | src/testdir/test_substitute.vim | 14 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 35 insertions, 11 deletions
diff --git a/src/regexp.c b/src/regexp.c index 33b36d11a..0e6c746df 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 7491b6163..32e2f2785 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 7ee9f575f..3fb73b25e 100644 --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1532, +/**/ 1531, /**/ 1530, |