Patch 8.2.4474
Problem:    Memory allocation failures not tested in quickfix code.
Solution:   Add alloc IDs and tests. (Yegappan Lakshmanan, closes #9848)
Files:      src/alloc.h, src/quickfix.c, src/vim.h,
            src/testdir/test_quickfix.vim


*** ../vim-8.2.4473/src/alloc.h 2018-12-21 13:36:57.000000000 +0000
--- src/alloc.h 2022-02-26 10:26:38.851839325 +0000
***************
*** 8,33 ****
  
  /*
   * alloc.h: enumeration of alloc IDs.
   * Each entry must be on exactly one line, GetAllocId() depends on that.
   */
  typedef enum {
!       aid_none = 0,
!       aid_qf_dirname_start,
!       aid_qf_dirname_now,
!       aid_qf_namebuf,
!       aid_qf_module,
!       aid_qf_errmsg,
!       aid_qf_pattern,
!       aid_tagstack_items,
!       aid_tagstack_from,
!       aid_tagstack_details,
!       aid_sign_getdefined,
!       aid_sign_getplaced,
!       aid_sign_define_by_name,
!       aid_sign_getlist,
!       aid_sign_getplaced_dict,
!       aid_sign_getplaced_list,
!       aid_insert_sign,
!       aid_sign_getinfo,
!       aid_last
  } alloc_id_T;
--- 8,44 ----
  
  /*
   * alloc.h: enumeration of alloc IDs.
+  * Used by test_alloc_fail() to test memory allocation failures.
   * Each entry must be on exactly one line, GetAllocId() depends on that.
   */
  typedef enum {
!     aid_none = 0,
!     aid_qf_dirname_start,
!     aid_qf_dirname_now,
!     aid_qf_namebuf,
!     aid_qf_module,
!     aid_qf_errmsg,
!     aid_qf_pattern,
!     aid_qf_efm_fmtstr,
!     aid_qf_efm_fmtpart,
!     aid_qf_title,
!     aid_qf_mef_name,
!     aid_qf_qfline,
!     aid_qf_qfinfo,
!     aid_qf_dirstack,
!     aid_qf_multiline_pfx,
!     aid_qf_makecmd,
!     aid_qf_linebuf,
!     aid_tagstack_items,
!     aid_tagstack_from,
!     aid_tagstack_details,
!     aid_sign_getdefined,
!     aid_sign_getplaced,
!     aid_sign_define_by_name,
!     aid_sign_getlist,
!     aid_sign_getplaced_dict,
!     aid_sign_getplaced_list,
!     aid_insert_sign,
!     aid_sign_getinfo,
!     aid_last
  } alloc_id_T;
*** ../vim-8.2.4473/src/quickfix.c      2022-02-24 12:33:13.151233722 +0000
--- src/quickfix.c      2022-02-26 10:26:38.851839325 +0000
***************
*** 547,559 ****
  
      // Get some space to modify the format string into.
      sz = efm_regpat_bufsz(efm);
!     if ((fmtstr = alloc(sz)) == NULL)
        goto parse_efm_error;
  
      while (efm[0] != NUL)
      {
        // Allocate a new eformat structure and put it at the end of the list
!       fmt_ptr = ALLOC_CLEAR_ONE(efm_T);
        if (fmt_ptr == NULL)
            goto parse_efm_error;
        if (fmt_first == NULL)      // first one
--- 547,559 ----
  
      // Get some space to modify the format string into.
      sz = efm_regpat_bufsz(efm);
!     if ((fmtstr = alloc_id(sz, aid_qf_efm_fmtstr)) == NULL)
        goto parse_efm_error;
  
      while (efm[0] != NUL)
      {
        // Allocate a new eformat structure and put it at the end of the list
!       fmt_ptr = ALLOC_CLEAR_ONE_ID(efm_T, aid_qf_efm_fmtpart);
        if (fmt_ptr == NULL)
            goto parse_efm_error;
        if (fmt_first == NULL)      // first one
***************
*** 628,634 ****
      state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
      if (state->growbuf == NULL)
      {
!       state->growbuf = alloc(state->linelen + 1);
        if (state->growbuf == NULL)
            return NULL;
        state->growbufsiz = state->linelen;
--- 628,634 ----
      state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
      if (state->growbuf == NULL)
      {
!       state->growbuf = alloc_id(state->linelen + 1, aid_qf_linebuf);
        if (state->growbuf == NULL)
            return NULL;
        state->growbufsiz = state->linelen;
***************
*** 685,691 ****
  }
  
  /*
!  * Get the next string from state->p_Li.
   */
      static int
  qf_get_next_list_line(qfstate_T *state)
--- 685,691 ----
  }
  
  /*
!  * Get the next string from the List item state->p_li.
   */
      static int
  qf_get_next_list_line(qfstate_T *state)
***************
*** 777,783 ****
        if (state->growbuf == NULL)
        {
            state->growbufsiz = 2 * (IOSIZE - 1);
!           state->growbuf = alloc(state->growbufsiz);
            if (state->growbuf == NULL)
                return QF_NOMEM;
        }
--- 777,783 ----
        if (state->growbuf == NULL)
        {
            state->growbufsiz = 2 * (IOSIZE - 1);
!           state->growbuf = alloc_id(state->growbufsiz, aid_qf_linebuf);
            if (state->growbuf == NULL)
                return QF_NOMEM;
        }
***************
*** 1382,1389 ****
        if (*fields->errmsg && !qfl->qf_multiignore)
        {
            len = (int)STRLEN(qfprev->qf_text);
!           if ((ptr = alloc(len + STRLEN(fields->errmsg) + 2))
!                   == NULL)
                return QF_FAIL;
            STRCPY(ptr, qfprev->qf_text);
            vim_free(qfprev->qf_text);
--- 1382,1390 ----
        if (*fields->errmsg && !qfl->qf_multiignore)
        {
            len = (int)STRLEN(qfprev->qf_text);
!           ptr = alloc_id(len + STRLEN(fields->errmsg) + 2,
!                                               aid_qf_multiline_pfx);
!           if (ptr == NULL)
                return QF_FAIL;
            STRCPY(ptr, qfprev->qf_text);
            vim_free(qfprev->qf_text);
***************
*** 1859,1865 ****
  
      if (title != NULL)
      {
!       char_u *p = alloc(STRLEN(title) + 2);
  
        qfl->qf_title = p;
        if (p != NULL)
--- 1860,1866 ----
  
      if (title != NULL)
      {
!       char_u *p = alloc_id(STRLEN(title) + 2, aid_qf_title);
  
        qfl->qf_title = p;
        if (p != NULL)
***************
*** 2109,2115 ****
      qfline_T  *qfp;
      qfline_T  **lastp;        // pointer to qf_last or NULL
  
!     if ((qfp = ALLOC_ONE(qfline_T)) == NULL)
        return QF_FAIL;
      if (bufnum != 0)
      {
--- 2110,2116 ----
      qfline_T  *qfp;
      qfline_T  **lastp;        // pointer to qf_last or NULL
  
!     if ((qfp = ALLOC_ONE_ID(qfline_T, aid_qf_qfline)) == NULL)
        return QF_FAIL;
      if (bufnum != 0)
      {
***************
*** 2189,2195 ****
  {
      qf_info_T *qi;
  
!     qi = ALLOC_CLEAR_ONE(qf_info_T);
      if (qi != NULL)
      {
        qi->qf_refcount++;
--- 2190,2196 ----
  {
      qf_info_T *qi;
  
!     qi = ALLOC_CLEAR_ONE_ID(qf_info_T, aid_qf_qfinfo);
      if (qi != NULL)
      {
        qi->qf_refcount++;
***************
*** 2483,2489 ****
      struct dir_stack_T  *ds_ptr;
  
      // allocate new stack element and hook it in
!     ds_new = ALLOC_ONE(struct dir_stack_T);
      if (ds_new == NULL)
        return NULL;
  
--- 2484,2490 ----
      struct dir_stack_T  *ds_ptr;
  
      // allocate new stack element and hook it in
!     ds_new = ALLOC_ONE_ID(struct dir_stack_T, aid_qf_dirstack);
      if (ds_new == NULL)
        return NULL;
  
***************
*** 4945,4951 ****
        else
            off += 19;
  
!       name = alloc(STRLEN(p_mef) + 30);
        if (name == NULL)
            break;
        STRCPY(name, p_mef);
--- 4946,4952 ----
        else
            off += 19;
  
!       name = alloc_id(STRLEN(p_mef) + 30, aid_qf_mef_name);
        if (name == NULL)
            break;
        STRCPY(name, p_mef);
***************
*** 4976,4982 ****
      len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1;
      if (*p_sp != NUL)
        len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
!     cmd = alloc(len);
      if (cmd == NULL)
        return NULL;
      sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd,
--- 4977,4983 ----
      len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1;
      if (*p_sp != NUL)
        len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
!     cmd = alloc_id(len, aid_qf_makecmd);
      if (cmd == NULL)
        return NULL;
      sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd,
***************
*** 5042,5048 ****
--- 5043,5052 ----
  
      cmd = make_get_fullcmd(eap->arg, fname);
      if (cmd == NULL)
+     {
+       vim_free(fname);
        return;
+     }
  
      // let the shell know if we are redirecting output or not
      do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0);
*** ../vim-8.2.4473/src/vim.h   2022-02-12 21:08:55.577918000 +0000
--- src/vim.h   2022-02-26 10:26:38.851839325 +0000
***************
*** 1608,1615 ****
--- 1608,1617 ----
  // Allocate memory for one type and cast the returned pointer to have the
  // compiler check the types.
  #define ALLOC_ONE(type)  (type *)alloc(sizeof(type))
+ #define ALLOC_ONE_ID(type, id)  (type *)alloc_id(sizeof(type), id)
  #define ALLOC_MULT(type, count)  (type *)alloc(sizeof(type) * (count))
  #define ALLOC_CLEAR_ONE(type)  (type *)alloc_clear(sizeof(type))
+ #define ALLOC_CLEAR_ONE_ID(type, id)  (type *)alloc_clear_id(sizeof(type), id)
  #define ALLOC_CLEAR_MULT(type, count)  (type *)alloc_clear(sizeof(type) * 
(count))
  #define LALLOC_CLEAR_ONE(type)  (type *)lalloc_clear(sizeof(type), FALSE)
  #define LALLOC_CLEAR_MULT(type, count)  (type *)lalloc_clear(sizeof(type) * 
(count), FALSE)
*** ../vim-8.2.4473/src/testdir/test_quickfix.vim       2022-02-24 
12:33:13.151233722 +0000
--- src/testdir/test_quickfix.vim       2022-02-26 10:26:38.851839325 +0000
***************
*** 621,642 ****
    call Xtest_browse('l')
  endfunc
  
! func Test_nomem()
    call test_alloc_fail(GetAllocId('qf_dirname_start'), 0, 0)
!   call assert_fails('vimgrep vim runtest.vim', 'E342:')
  
!   call GetAllocId('qf_dirname_now')->test_alloc_fail(0, 0)
!   call assert_fails('vimgrep vim runtest.vim', 'E342:')
  
    call test_alloc_fail(GetAllocId('qf_namebuf'), 0, 0)
!   call assert_fails('cfile runtest.vim', 'E342:')
  
    call test_alloc_fail(GetAllocId('qf_errmsg'), 0, 0)
!   call assert_fails('cfile runtest.vim', 'E342:')
  
    call test_alloc_fail(GetAllocId('qf_pattern'), 0, 0)
!   call assert_fails('cfile runtest.vim', 'E342:')
  
  endfunc
  
  func s:test_xhelpgrep(cchar)
--- 621,767 ----
    call Xtest_browse('l')
  endfunc
  
! " Test for memory allocation failures
! func Xnomem_tests(cchar)
!   call s:setup_commands(a:cchar)
! 
    call test_alloc_fail(GetAllocId('qf_dirname_start'), 0, 0)
!   call assert_fails('Xvimgrep vim runtest.vim', 'E342:')
  
!   call test_alloc_fail(GetAllocId('qf_dirname_now'), 0, 0)
!   call assert_fails('Xvimgrep vim runtest.vim', 'E342:')
  
    call test_alloc_fail(GetAllocId('qf_namebuf'), 0, 0)
!   call assert_fails('Xfile runtest.vim', 'E342:')
  
    call test_alloc_fail(GetAllocId('qf_errmsg'), 0, 0)
!   call assert_fails('Xfile runtest.vim', 'E342:')
  
    call test_alloc_fail(GetAllocId('qf_pattern'), 0, 0)
!   call assert_fails('Xfile runtest.vim', 'E342:')
  
+   call test_alloc_fail(GetAllocId('qf_efm_fmtstr'), 0, 0)
+   set efm=%f
+   call assert_fails('Xexpr ["Xfile1"]', 'E342:')
+   set efm&
+ 
+   call test_alloc_fail(GetAllocId('qf_efm_fmtpart'), 0, 0)
+   set efm=%f:%l:%m,%f-%l-%m
+   call assert_fails('Xaddexpr ["Xfile2", "Xfile3"]', 'E342:')
+   set efm&
+ 
+   call test_alloc_fail(GetAllocId('qf_title'), 0, 0)
+   call assert_fails('Xexpr ""', 'E342:')
+   call assert_equal('', g:Xgetlist({'all': 1}).title)
+ 
+   call test_alloc_fail(GetAllocId('qf_mef_name'), 0, 0)
+   set makeef=Xtmp##.err
+   call assert_fails('Xgrep needle haystack', 'E342:')
+   set makeef&
+ 
+   call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
+   call assert_fails('Xexpr "Xfile1:10:Line10"', 'E342:')
+ 
+   if a:cchar == 'l'
+     for id in ['qf_qfline', 'qf_qfinfo']
+       lgetexpr ["Xfile1:10:L10", "Xfile2:20:L20"]
+       call test_alloc_fail(GetAllocId(id), 0, 0)
+       call assert_fails('new', 'E342:')
+       call assert_equal(2, winnr('$'))
+       call assert_equal([], getloclist(0))
+       %bw!
+     endfor
+   endif
+ 
+   call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
+   try
+     call assert_fails('Xvimgrep vim runtest.vim', 'E342:')
+   catch /^Vim:Interrupt$/
+   endtry
+ 
+   call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
+   try
+     call assert_fails('Xvimgrep /vim/f runtest.vim', 'E342:')
+   catch /^Vim:Interrupt$/
+   endtry
+ 
+   let l = getqflist({"lines": ["Xfile1:10:L10"]})
+   call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
+   call assert_fails('call g:Xsetlist(l.items)', 'E342:')
+ 
+   call test_alloc_fail(GetAllocId('qf_qfline'), 0, 0)
+   try
+     call assert_fails('Xhelpgrep quickfix', 'E342:')
+   catch /^Vim:Interrupt$/
+   endtry
+ 
+   call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+   call assert_fails('let l = g:Xgetlist({"lines": ["Xfile1:10:L10"]})', 
'E342:')
+   call assert_equal(#{items: []}, l)
+ 
+   if a:cchar == 'l'
+     call setqflist([], 'f')
+     call setloclist(0, [], 'f')
+     call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+     call assert_fails('lhelpgrep quickfix', 'E342:')
+     call assert_equal([], getloclist(0))
+ 
+     call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+     call assert_fails('lvimgrep vim runtest.vim', 'E342:')
+ 
+     let l = getqflist({"lines": ["Xfile1:10:L10"]})
+     call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+     call assert_fails('call setloclist(0, l.items)', 'E342:')
+ 
+     call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+     call assert_fails('lbuffer', 'E342:')
+ 
+     call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+     call assert_fails('lexpr ["Xfile1:10:L10", "Xfile2:20:L20"]', 'E342:')
+ 
+     call test_alloc_fail(GetAllocId('qf_qfinfo'), 0, 0)
+     call assert_fails('lfile runtest.vim', 'E342:')
+   endif
+ 
+   call test_alloc_fail(GetAllocId('qf_dirstack'), 0, 0)
+   set efm=%DEntering\ dir\ %f,%f:%l:%m
+   call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 
'E342:')
+   set efm&
+ 
+   call test_alloc_fail(GetAllocId('qf_dirstack'), 0, 0)
+   set efm=%+P[%f],(%l)%m
+   call assert_fails('Xexpr ["[runtest.vim]", "(1)Hello"]', 'E342:')
+   set efm&
+ 
+   call test_alloc_fail(GetAllocId('qf_multiline_pfx'), 0, 0)
+   set efm=%EError,%Cline\ %l,%Z%m
+   call assert_fails('Xexpr ["Error", "line 1", "msg"]', 'E342:')
+   set efm&
+ 
+   call test_alloc_fail(GetAllocId('qf_makecmd'), 0, 0)
+   call assert_fails('Xgrep vim runtest.vim', 'E342:')
+ 
+   call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
+   call assert_fails('Xexpr repeat("a", 8192)', 'E342:')
+ 
+   call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
+   call assert_fails('Xexpr [repeat("a", 8192)]', 'E342:')
+ 
+   new
+   call setline(1, repeat('a', 8192))
+   call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
+   call assert_fails('Xbuffer', 'E342:')
+   %bw!
+ 
+   call writefile([repeat('a', 8192)], 'Xtest')
+   call test_alloc_fail(GetAllocId('qf_linebuf'), 0, 0)
+   call assert_fails('Xfile Xtest', 'E342:')
+   call delete('Xtest')
+ endfunc
+ 
+ func Test_nomem()
+   call Xnomem_tests('c')
+   call Xnomem_tests('l')
  endfunc
  
  func s:test_xhelpgrep(cchar)
*** ../vim-8.2.4473/src/version.c       2022-02-25 21:47:44.905532201 +0000
--- src/version.c       2022-02-26 10:28:37.815899194 +0000
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     4474,
  /**/

-- 
Laughing helps. It's like jogging on the inside.

 /// 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/20220226103504.6185D1C1149%40moolenaar.net.

Raspunde prin e-mail lui