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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220530200154.170BD1C1AA3%40moolenaar.net.

Raspunde prin e-mail lui