Patch 8.2.5046

7 views
Skip to first unread message

Bram Moolenaar

unread,
May 30, 2022, 4:02:01 PM5/30/22
to vim...@googlegroups.com

Patch 8.2.5046
Problem: vim_regsub() can overwrite the destination.
Solution: Pass the destination length, give an error when it doesn't fit.
Files: src/regexp.h, src/regexp.c, src/proto/regexp.pro, src/eval.c,
src/ex_cmds.c


*** ../vim-8.2.5045/src/regexp.h 2022-04-23 10:41:31.092696680 +0100
--- src/regexp.h 2022-05-30 19:15:22.277948283 +0100
***************
*** 177,180 ****
--- 177,185 ----
//char_u *expr;
};

+ // Flags used by vim_regsub() and vim_regsub_both()
+ #define REGSUB_COPY 1
+ #define REGSUB_MAGIC 2
+ #define REGSUB_BACKSLASH 4
+
#endif // _REGEXP_H
*** ../vim-8.2.5045/src/regexp.c 2022-05-05 13:52:59.416192105 +0100
--- src/regexp.c 2022-05-30 19:59:58.326309942 +0100
***************
*** 1649,1655 ****
*/
typedef void (*(*fptr_T)(int *, int));

! static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int copy, int magic, int backslash);

static fptr_T
do_upper(int *d, int c)
--- 1649,1655 ----
*/
typedef void (*(*fptr_T)(int *, int));

! static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, int destlen, int flags);

static fptr_T
do_upper(int *d, int c)
***************
*** 1822,1834 ****
* vim_regsub() - perform substitutions after a vim_regexec() or
* vim_regexec_multi() match.
*
! * If "copy" is TRUE really copy into "dest".
! * If "copy" is FALSE nothing is copied, this is just to find out the length
! * of the result.
*
! * If "backslash" is TRUE, a backslash will be removed later, need to double
! * them to keep them, and insert a backslash before a CR to avoid it being
! * replaced with a line break later.
*
* Note: The matched text must not change between the call of
* vim_regexec()/vim_regexec_multi() and vim_regsub()! It would make the back
--- 1822,1835 ----
* vim_regsub() - perform substitutions after a vim_regexec() or
* vim_regexec_multi() match.
*
! * If "flags" has REGSUB_COPY really copy into "dest[destlen]".
! * Oterwise nothing is copied, only compue the length of the result.
*
! * If "flags" has REGSUB_MAGIC then behave like 'magic' is set.
! *
! * If "flags" has REGSUB_BACKSLASH a backslash will be removed later, need to
! * double them to keep them, and insert a backslash before a CR to avoid it
! * being replaced with a line break later.
*
* Note: The matched text must not change between the call of
* vim_regexec()/vim_regexec_multi() and vim_regsub()! It would make the back
***************
*** 1842,1850 ****
char_u *source,
typval_T *expr,
char_u *dest,
! int copy,
! int magic,
! int backslash)
{
int result;
regexec_T rex_save;
--- 1843,1850 ----
char_u *source,
typval_T *expr,
char_u *dest,
! int destlen,
! int flags)
{
int result;
regexec_T rex_save;
***************
*** 1860,1866 ****
rex.reg_maxline = 0;
rex.reg_buf = curbuf;
rex.reg_line_lbr = TRUE;
! result = vim_regsub_both(source, expr, dest, copy, magic, backslash);

rex_in_use = rex_in_use_save;
if (rex_in_use)
--- 1860,1866 ----
rex.reg_maxline = 0;
rex.reg_buf = curbuf;
rex.reg_line_lbr = TRUE;
! result = vim_regsub_both(source, expr, dest, destlen, flags);

rex_in_use = rex_in_use_save;
if (rex_in_use)
***************
*** 1875,1883 ****
linenr_T lnum,
char_u *source,
char_u *dest,
! int copy,
! int magic,
! int backslash)
{
int result;
regexec_T rex_save;
--- 1875,1882 ----
linenr_T lnum,
char_u *source,
char_u *dest,
! int destlen,
! int flags)
{
int result;
regexec_T rex_save;
***************
*** 1894,1900 ****
rex.reg_firstlnum = lnum;
rex.reg_maxline = curbuf->b_ml.ml_line_count - lnum;
rex.reg_line_lbr = FALSE;
! result = vim_regsub_both(source, NULL, dest, copy, magic, backslash);

rex_in_use = rex_in_use_save;
if (rex_in_use)
--- 1893,1899 ----
rex.reg_firstlnum = lnum;
rex.reg_maxline = curbuf->b_ml.ml_line_count - lnum;
rex.reg_line_lbr = FALSE;
! result = vim_regsub_both(source, NULL, dest, destlen, flags);

rex_in_use = rex_in_use_save;
if (rex_in_use)
***************
*** 1908,1916 ****
char_u *source,
typval_T *expr,
char_u *dest,
! int copy,
! int magic,
! int backslash)
{
char_u *src;
char_u *dst;
--- 1907,1914 ----
char_u *source,
typval_T *expr,
char_u *dest,
! int destlen,
! int flags)
{
char_u *src;
char_u *dst;
***************
*** 1925,1930 ****
--- 1923,1929 ----
#ifdef FEAT_EVAL
static char_u *eval_result = NULL;
#endif
+ int copy = flags & REGSUB_COPY;

// Be paranoid...
if ((source == NULL && expr == NULL) || dest == NULL)
***************
*** 1945,1952 ****
#ifdef FEAT_EVAL
// To make sure that the length doesn't change between checking the
// length and copying the string, and to speed up things, the
! // resulting string is saved from the call with "copy" == FALSE to the
! // call with "copy" == TRUE.
if (copy)
{
if (eval_result != NULL)
--- 1944,1951 ----
#ifdef FEAT_EVAL
// To make sure that the length doesn't change between checking the
// length and copying the string, and to speed up things, the
! // resulting string is saved from the call with "flags & REGSUB_COPY"
! // == 0 to the // call with "flags & REGSUB_COPY" != 0.
if (copy)
{
if (eval_result != NULL)
***************
*** 2054,2060 ****
had_backslash = TRUE;
}
}
! if (had_backslash && backslash)
{
// Backslashes will be consumed, need to double them.
s = vim_strsave_escaped(eval_result, (char_u *)"\\");
--- 2053,2059 ----
had_backslash = TRUE;
}
}
! if (had_backslash && (flags & REGSUB_BACKSLASH))
{
// Backslashes will be consumed, need to double them.
s = vim_strsave_escaped(eval_result, (char_u *)"\\");
***************
*** 2077,2087 ****
else
while ((c = *src++) != NUL)
{
! if (c == '&' && magic)
no = 0;
else if (c == '\\' && *src != NUL)
{
! if (*src == '&' && !magic)
{
++src;
no = 0;
--- 2076,2086 ----
else
while ((c = *src++) != NUL)
{
! if (c == '&' && (flags & REGSUB_MAGIC))
no = 0;
else if (c == '\\' && *src != NUL)
{
! if (*src == '&' && !(flags & REGSUB_MAGIC))
{
++src;
no = 0;
***************
*** 2115,2120 ****
--- 2114,2124 ----
// Copy a special key as-is.
if (copy)
{
+ if (dst + 3 > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
*dst++ = c;
*dst++ = *src++;
*dst++ = *src++;
***************
*** 2141,2150 ****

// If "backslash" is TRUE the backslash will be removed
// later. Used to insert a literal CR.
! default: if (backslash)
{
if (copy)
*dst = '\\';
++dst;
}
c = *src++;
--- 2145,2161 ----

// If "backslash" is TRUE the backslash will be removed
// later. Used to insert a literal CR.
! default: if (flags & REGSUB_BACKSLASH)
{
if (copy)
+ {
+ if (dst + 1 > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
*dst = '\\';
+ }
++dst;
}
c = *src++;
***************
*** 2166,2175 ****
if (has_mbyte)
{
int totlen = mb_ptr2len(src - 1);

if (copy)
mb_char2bytes(cc, dst);
! dst += mb_char2len(cc) - 1;
if (enc_utf8)
{
int clen = utf_ptr2len(src - 1);
--- 2177,2194 ----
if (has_mbyte)
{
int totlen = mb_ptr2len(src - 1);
+ int charlen = mb_char2len(cc);

if (copy)
+ {
+ if (dst + charlen > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
mb_char2bytes(cc, dst);
! }
! dst += charlen - 1;
if (enc_utf8)
{
int clen = utf_ptr2len(src - 1);
***************
*** 2179,2193 ****
if (clen < totlen)
{
if (copy)
mch_memmove(dst + 1, src - 1 + clen,
(size_t)(totlen - clen));
dst += totlen - clen;
}
}
src += totlen - 1;
}
else if (copy)
! *dst = cc;
dst++;
}
else
--- 2198,2226 ----
if (clen < totlen)
{
if (copy)
+ {
+ if (dst + totlen - clen > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
mch_memmove(dst + 1, src - 1 + clen,
(size_t)(totlen - clen));
+ }
dst += totlen - clen;
}
}
src += totlen - 1;
}
else if (copy)
! {
! if (dst + 1 > dest + destlen)
! {
! iemsg("vim_regsub_both(): not enough space");
! return 0;
! }
! *dst = cc;
! }
dst++;
}
else
***************
*** 2226,2232 ****
--- 2259,2272 ----
if (rex.reg_mmatch->endpos[no].lnum == clnum)
break;
if (copy)
+ {
+ if (dst + 1 > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
*dst = CAR;
+ }
++dst;
s = reg_getline(++clnum);
if (rex.reg_mmatch->endpos[no].lnum == clnum)
***************
*** 2245,2251 ****
}
else
{
! if (backslash && (*s == CAR || *s == '\\'))
{
/*
* Insert a backslash in front of a CR, otherwise
--- 2285,2292 ----
}
else
{
! if ((flags & REGSUB_BACKSLASH)
! && (*s == CAR || *s == '\\'))
{
/*
* Insert a backslash in front of a CR, otherwise
***************
*** 2255,2260 ****
--- 2296,2306 ----
*/
if (copy)
{
+ if (dst + 2 > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
dst[0] = '\\';
dst[1] = *s;
}
***************
*** 2279,2284 ****
--- 2325,2331 ----
if (has_mbyte)
{
int l;
+ int charlen;

// Copy composing characters separately, one
// at a time.
***************
*** 2289,2300 ****

s += l;
len -= l;
if (copy)
mb_char2bytes(cc, dst);
! dst += mb_char2len(cc) - 1;
}
else if (copy)
! *dst = cc;
dst++;
}

--- 2336,2362 ----

s += l;
len -= l;
+ charlen = mb_char2len(cc);
if (copy)
+ {
+ if (dst + charlen > dest + destlen)
+ {
+ iemsg("vim_regsub_both(): not enough space");
+ return 0;
+ }
mb_char2bytes(cc, dst);
! }
! dst += charlen - 1;
}
else if (copy)
! {
! if (dst + 1 > dest + destlen)
! {
! iemsg("vim_regsub_both(): not enough space");
! return 0;
! }
! *dst = cc;
! }
dst++;
}

***************
*** 2711,2717 ****

/*
* Match a regexp against a string.
! * "rmp->regprog" is a compiled regexp as returned by vim_regcomp().
* Note: "rmp->regprog" may be freed and changed.
* Uses curbuf for line count and 'iskeyword'.
* When "nl" is TRUE consider a "\n" in "line" to be a line break.
--- 2773,2779 ----

/*
* Match a regexp against a string.
! * "rmp->regprog" must be a compiled regexp as returned by vim_regcomp().
* Note: "rmp->regprog" may be freed and changed.
* Uses curbuf for line count and 'iskeyword'.
* When "nl" is TRUE consider a "\n" in "line" to be a line break.
*** ../vim-8.2.5045/src/proto/regexp.pro 2021-01-04 11:41:49.507891351 +0000
--- src/proto/regexp.pro 2022-05-30 19:51:14.371762806 +0100
***************
*** 6,13 ****
reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
void unref_extmatch(reg_extmatch_T *em);
char_u *regtilde(char_u *source, int magic);
! int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, int copy, int magic, int backslash);
! int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int copy, int magic, int backslash);
char_u *reg_submatch(int no);
list_T *reg_submatch_list(int no);
int vim_regcomp_had_eol(void);
--- 6,13 ----
reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
void unref_extmatch(reg_extmatch_T *em);
char_u *regtilde(char_u *source, int magic);
! int vim_regsub(regmatch_T *rmp, char_u *source, typval_T *expr, char_u *dest, int destlen, int flags);
! int vim_regsub_multi(regmmatch_T *rmp, linenr_T lnum, char_u *source, char_u *dest, int destlen, int flags);
char_u *reg_submatch(int no);
list_T *reg_submatch_list(int no);
int vim_regcomp_had_eol(void);
*** ../vim-8.2.5045/src/eval.c 2022-05-27 17:26:50.542119974 +0100
--- src/eval.c 2022-05-30 19:48:08.336278016 +0100
***************
*** 6905,6911 ****
* - The substituted text.
* - The text after the match.
*/
! sublen = vim_regsub(&regmatch, sub, expr, tail, FALSE, TRUE, FALSE);
if (ga_grow(&ga, (int)((end - tail) + sublen -
(regmatch.endp[0] - regmatch.startp[0]))) == FAIL)
{
--- 6905,6911 ----
* - The substituted text.
* - The text after the match.
*/
! sublen = vim_regsub(&regmatch, sub, expr, tail, 0, REGSUB_MAGIC);
if (ga_grow(&ga, (int)((end - tail) + sublen -
(regmatch.endp[0] - regmatch.startp[0]))) == FAIL)
{
***************
*** 6917,6924 ****
i = (int)(regmatch.startp[0] - tail);
mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
// add the substituted text
! (void)vim_regsub(&regmatch, sub, expr, (char_u *)ga.ga_data
! + ga.ga_len + i, TRUE, TRUE, FALSE);
ga.ga_len += i + sublen - 1;
tail = regmatch.endp[0];
if (*tail == NUL)
--- 6917,6925 ----
i = (int)(regmatch.startp[0] - tail);
mch_memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i);
// add the substituted text
! (void)vim_regsub(&regmatch, sub, expr,
! (char_u *)ga.ga_data + ga.ga_len + i, sublen,
! REGSUB_COPY | REGSUB_MAGIC);
ga.ga_len += i + sublen - 1;
tail = regmatch.endp[0];
if (*tail == NUL)
*** ../vim-8.2.5045/src/ex_cmds.c 2022-05-27 17:26:50.542119974 +0100
--- src/ex_cmds.c 2022-05-30 19:50:30.599884093 +0100
***************
*** 4419,4425 ****
// get length of substitution part
sublen = vim_regsub_multi(&regmatch,
sub_firstlnum - regmatch.startpos[0].lnum,
! sub, sub_firstline, FALSE, magic_isset(), TRUE);
#ifdef FEAT_EVAL
--textlock;

--- 4419,4427 ----
// get length of substitution part
sublen = vim_regsub_multi(&regmatch,
sub_firstlnum - regmatch.startpos[0].lnum,
! sub, sub_firstline, 0,
! REGSUB_BACKSLASH
! | (magic_isset() ? REGSUB_MAGIC : 0));
#ifdef FEAT_EVAL
--textlock;

***************
*** 4528,4534 ****
#endif
(void)vim_regsub_multi(&regmatch,
sub_firstlnum - regmatch.startpos[0].lnum,
! sub, new_end, TRUE, magic_isset(), TRUE);
#ifdef FEAT_EVAL
--textlock;
#endif
--- 4530,4538 ----
#endif
(void)vim_regsub_multi(&regmatch,
sub_firstlnum - regmatch.startpos[0].lnum,
! sub, new_end, sublen,
! REGSUB_COPY | REGSUB_BACKSLASH
! | (magic_isset() ? REGSUB_MAGIC : 0));
#ifdef FEAT_EVAL
--textlock;
#endif
*** ../vim-8.2.5045/src/version.c 2022-05-30 17:57:47.098595199 +0100
--- src/version.c 2022-05-30 20:58:02.666114736 +0100
***************
*** 736,737 ****
--- 736,739 ----
{ /* Add new patch number below this line */
+ /**/
+ 5046,
/**/

--
We do not stumble over mountains, but over molehills.
Confucius

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
Reply all
Reply to author
Forward
0 new messages