To: vim_dev@googlegroups.com Subject: Patch 9.0.0579 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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\\") ! call TermWait(buf, 100) call term_sendkeys(buf, "\") 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\\") ! call TermWait(buf, 200) call term_sendkeys(buf, "\") 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 -- Bram@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 ///