vim-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.

ab9a2d884b

Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
zeertzjq 2023-11-17 06:55:08 +08:00
parent a388c852c4
commit d2f2e2725c
2 changed files with 36 additions and 17 deletions

View File

@ -1642,41 +1642,46 @@ static void do_lower(int *d, int c)
char *regtilde(char *source, int magic, bool preview) char *regtilde(char *source, int magic, bool preview)
{ {
char *newsub = source; char *newsub = source;
char *tmpsub;
char *p;
int len;
int prevlen;
for (p = newsub; *p; p++) { for (char *p = newsub; *p; p++) {
if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic)) { if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic)) {
if (reg_prev_sub != NULL) { if (reg_prev_sub != NULL) {
// length = len(newsub) - 1 + len(prev_sub) + 1 // length = len(newsub) - 1 + len(prev_sub) + 1
prevlen = (int)strlen(reg_prev_sub); // Avoid making the text longer than MAXCOL, it will cause
tmpsub = xmalloc(strlen(newsub) + (size_t)prevlen); // 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 *tmpsub = xmalloc(newsublen + prevsublen);
// copy prefix // copy prefix
len = (int)(p - newsub); // not including ~ size_t prefixlen = (size_t)(p - newsub); // not including ~
memmove(tmpsub, newsub, (size_t)len); memmove(tmpsub, newsub, prefixlen);
// interpret tilde // interpret tilde
memmove(tmpsub + len, reg_prev_sub, (size_t)prevlen); memmove(tmpsub + prefixlen, reg_prev_sub, prevsublen);
// copy postfix // copy postfix
if (!magic) { if (!magic) {
p++; // back off backslash 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
xfree(newsub); xfree(newsub);
} }
newsub = tmpsub; newsub = tmpsub;
p = newsub + len + prevlen; p = newsub + prefixlen + prevsublen;
} else if (magic) { } else if (magic) {
STRMOVE(p, p + 1); // remove '~' STRMOVE(p, p + 1); // remove '~'
} else { } else {
STRMOVE(p, p + 2); // remove '\~' STRMOVE(p, p + 2); // remove '\~'
} }
p--; p--;
} else { } else {
if (*p == '\\' && p[1]) { // skip escaped characters if (*p == '\\' && p[1]) { // skip escaped characters
p++; p++;
} }
p += utfc_ptr2len(p) - 1; p += utfc_ptr2len(p) - 1;

View File

@ -1415,6 +1415,20 @@ func Test_substitute_short_cmd()
bw! bw!
endfunc 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 " 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. " called to evaluate an expression but it is not used in a second call.
func Test_z_substitute_expr_leak() func Test_z_substitute_expr_leak()