Patch 9.0.0579
Problem:    Using freed memory when 'tagfunc' wipes out buffer that holds
            'complete'.
Solution:   Make a copy of the option.  Make sure cursor position is valid.
Files:      src/insexpand.c, src/move.c, src/testdir/test_ins_complete.vim


*** ../vim-9.0.0578/src/insexpand.c     2022-09-24 11:17:48.373970710 +0100
--- src/insexpand.c     2022-09-24 19:08:29.753607924 +0100
***************
*** 2490,2496 ****
  
      if (flag == 'w')          // just windows
      {
!       if (buf == curbuf || wp == NULL)  // first call for this flag/expansion
            wp = curwin;
        while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
                && wp->w_buffer->b_scanned)
--- 2490,2497 ----
  
      if (flag == 'w')          // just windows
      {
!       if (buf == curbuf || !win_valid(wp))
!           // first call for this flag/expansion or window was closed
            wp = curwin;
        while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
                && wp->w_buffer->b_scanned)
***************
*** 3188,3196 ****
   */
  typedef struct
  {
!     char_u    *e_cpt;                 // current entry in 'complete'
      buf_T     *ins_buf;               // buffer being scanned
!     pos_T     *cur_match_pos;                 // current match position
      pos_T     prev_match_pos;         // previous match position
      int               set_match_pos;          // save 
first_match_pos/last_match_pos
      pos_T     first_match_pos;        // first match position
--- 3189,3198 ----
   */
  typedef struct
  {
!     char_u    *e_cpt_copy;            // copy of 'complete'
!     char_u    *e_cpt;                 // current entry in "e_cpt_copy"
      buf_T     *ins_buf;               // buffer being scanned
!     pos_T     *cur_match_pos;         // current match position
      pos_T     prev_match_pos;         // previous match position
      int               set_match_pos;          // save 
first_match_pos/last_match_pos
      pos_T     first_match_pos;        // first match position
***************
*** 3257,3263 ****
        st->set_match_pos = TRUE;
      }
      else if (vim_strchr((char_u *)"buwU", *st->e_cpt) != NULL
!           && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != 
curbuf)
      {
        // Scan a buffer, but not the current one.
        if (st->ins_buf->b_ml.ml_mfp != NULL)   // loaded buffer
--- 3259,3266 ----
        st->set_match_pos = TRUE;
      }
      else if (vim_strchr((char_u *)"buwU", *st->e_cpt) != NULL
!           && (st->ins_buf = ins_compl_next_buf(
!                                          st->ins_buf, *st->e_cpt)) != curbuf)
      {
        // Scan a buffer, but not the current one.
        if (st->ins_buf->b_ml.ml_mfp != NULL)   // loaded buffer
***************
*** 3756,3774 ****
      static int
  ins_compl_get_exp(pos_T *ini)
  {
!     static ins_compl_next_state_T st;
      int               i;
      int               found_new_match;
      int               type = ctrl_x_mode;
  
      if (!compl_started)
      {
!       FOR_ALL_BUFFERS(st.ins_buf)
!           st.ins_buf->b_scanned = 0;
        st.found_all = FALSE;
        st.ins_buf = curbuf;
!       st.e_cpt = (compl_cont_status & CONT_LOCAL)
!                                           ? (char_u *)"." : curbuf->b_p_cpt;
        st.last_match_pos = st.first_match_pos = *ini;
      }
      else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf))
--- 3759,3788 ----
      static int
  ins_compl_get_exp(pos_T *ini)
  {
!     static ins_compl_next_state_T   st;
!     static int                            st_cleared = FALSE;
      int               i;
      int               found_new_match;
      int               type = ctrl_x_mode;
  
      if (!compl_started)
      {
!       buf_T *buf;
! 
!       FOR_ALL_BUFFERS(buf)
!           buf->b_scanned = 0;
!       if (!st_cleared)
!       {
!           CLEAR_FIELD(st);
!           st_cleared = TRUE;
!       }
        st.found_all = FALSE;
        st.ins_buf = curbuf;
!       vim_free(st.e_cpt_copy);
!       // Make a copy of 'complete', if case the buffer is wiped out.
!       st.e_cpt_copy = vim_strsave((compl_cont_status & CONT_LOCAL)
!                                           ? (char_u *)"." : curbuf->b_p_cpt);
!       st.e_cpt = st.e_cpt_copy == NULL ? (char_u *)"" : st.e_cpt_copy;
        st.last_match_pos = st.first_match_pos = *ini;
      }
      else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf))
***************
*** 4112,4117 ****
--- 4126,4132 ----
      int           todo = count;
      int           advance;
      int           started = compl_started;
+     buf_T   *orig_curbuf = curbuf;
  
      // When user complete function return -1 for findstart which is next
      // time of 'always', compl_shown_match become NULL.
***************
*** 4144,4149 ****
--- 4159,4171 ----
                                                        &num_matches) == -1)
        return -1;
  
+     if (curbuf != orig_curbuf)
+     {
+       // In case some completion function switched buffer, don't want to
+       // insert the completion elsewhere.
+       return -1;
+     }
+ 
      // Insert the text of the new completion, or the compl_leader.
      if (compl_no_insert && !started)
      {
*** ../vim-9.0.0578/src/move.c  2022-09-19 16:45:26.202239861 +0100
--- src/move.c  2022-09-24 19:14:30.234942928 +0100
***************
*** 683,688 ****
--- 683,689 ----
      void
  validate_cursor(void)
  {
+     check_cursor();
      check_cursor_moved(curwin);
      if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != 
(VALID_WCOL|VALID_WROW))
        curs_columns(TRUE);
*** ../vim-9.0.0578/src/testdir/test_ins_complete.vim   2022-09-24 
14:08:19.896461420 +0100
--- src/testdir/test_ins_complete.vim   2022-09-24 19:18:21.255489759 +0100
***************
*** 547,555 ****
  
    call writefile(lines, 'Xpreviewscript')
    let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12})
-   call TermWait(buf, 50)
    call term_sendkeys(buf, "Gi\<C-X>\<C-O>")
!   call TermWait(buf, 100)
    call term_sendkeys(buf, "\<C-N>")
    call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {})
  
--- 547,554 ----
  
    call writefile(lines, 'Xpreviewscript')
    let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12})
    call term_sendkeys(buf, "Gi\<C-X>\<C-O>")
!   call TermWait(buf, 200)
    call term_sendkeys(buf, "\<C-N>")
    call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {})
  
***************
*** 2172,2175 ****
--- 2171,2191 ----
    bwipe!
  endfunc
  
+ func s:Tagfunc(t,f,o)
+   bwipe!
+   return []
+ endfunc
+ 
+ " This was using freed memory, since 'complete' was in a wiped out buffer.
+ " Also using a window that was closed.
+ func Test_tagfunc_wipes_out_buffer()
+   new
+   set complete=.,t,w,b,u,i
+   se tagfunc=s:Tagfunc
+   sil norm i 
+ 
+   bwipe!
+ endfunc
+ 
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-9.0.0578/src/version.c       2022-09-24 17:44:18.966404466 +0100
--- src/version.c       2022-09-24 19:19:42.059601525 +0100
***************
*** 701,702 ****
--- 701,704 ----
  {   /* Add new patch number below this line */
+ /**/
+     579,
  /**/

-- 
"Hit any key to continue" is very confusing when you have two keyboards.

 /// 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/20220924182155.8E2E91C0757%40moolenaar.net.

Raspunde prin e-mail lui