summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2023-05-09 21:15:30 +0100
committerBram Moolenaar <Bram@vim.org>2023-05-09 21:15:30 +0100
commitab9a2d884b3a4abe319606ea95a5a6d6b01cd73a (patch)
tree4677ba8a843e5bddcb87ee8b0a6a5ed62997b700
parentd1ae8366aff286d41e7f5bc513cc0a1af5130aad (diff)
downloadvim-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.c30
-rw-r--r--src/testdir/test_substitute.vim14
-rw-r--r--src/version.c2
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,