From bc54f3f3fed4dc3556df8c46cee6739d211b0eb2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 14:34:28 +0200 Subject: [PATCH 1/9] patch 7.4.2322 Problem: Access memory beyond the end of the line. (Dominique Pelle) Solution: Adjust the cursor column. --- src/move.c | 1 + src/testdir/test_normal.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/move.c b/src/move.c index 6322acf989..a4d5f82997 100644 --- a/src/move.c +++ b/src/move.c @@ -2479,6 +2479,7 @@ onepage(int dir, long count) foldAdjustCursor(); #endif cursor_correct(); + check_cursor_col(); if (retval == OK) beginline(BL_SOL | BL_FIX); curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL); diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index ff6710218d..98cb7754bb 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -398,6 +398,15 @@ func! Test_normal14_page() bw! endfu +func! Test_normal14_page_eol() + 10new + norm oxxxxxxx + exe "norm 2\" + " check with valgrind that cursor is put back in column 1 + exe "norm 2\" + bw! +endfunc + func! Test_normal15_z_scroll_vert() " basic test for z commands that scroll the window call Setup_NewWindow() diff --git a/src/version.c b/src/version.c index 5628a9dce3..155d9dda20 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2322, /**/ 2321, /**/ From d77f9d595eb5f301b39b4373f2900a13c0ca30e2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 15:13:39 +0200 Subject: [PATCH 2/9] patch 7.4.2323 Problem: Using freed memory when using 'formatexpr'. (Dominique Pelle) Solution: Make a copy of 'formatexpr' before evaluating it. --- src/ops.c | 9 ++++++++- src/testdir/test_normal.vim | 24 ++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/ops.c b/src/ops.c index c03c7be2e7..4bef6c5a21 100644 --- a/src/ops.c +++ b/src/ops.c @@ -4741,6 +4741,7 @@ fex_format( int use_sandbox = was_set_insecurely((char_u *)"formatexpr", OPT_LOCAL); int r; + char_u *fex; /* * Set v:lnum to the first line number and v:count to the number of lines. @@ -4750,16 +4751,22 @@ fex_format( set_vim_var_nr(VV_COUNT, count); set_vim_var_char(c); + /* Make a copy, the option could be changed while calling it. */ + fex = vim_strsave(curbuf->b_p_fex); + if (fex == NULL) + return 0; + /* * Evaluate the function. */ if (use_sandbox) ++sandbox; - r = (int)eval_to_number(curbuf->b_p_fex); + r = (int)eval_to_number(fex); if (use_sandbox) --sandbox; set_vim_var_string(VV_CHAR, NULL, -1); + vim_free(fex); return r; } diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 98cb7754bb..34561ffbab 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -192,6 +192,30 @@ func! Test_normal05_formatexpr() bw! endfu +func Test_normal05_formatexpr_newbuf() + " Edit another buffer in the 'formatexpr' function + new + func! Format() + edit another + endfunc + set formatexpr=Format() + norm gqG + bw! + set formatexpr= +endfunc + +func Test_normal05_formatexpr_setopt() + " Change the 'formatexpr' value in the function + new + func! Format() + set formatexpr= + endfunc + set formatexpr=Format() + norm gqG + bw! + set formatexpr= +endfunc + func! Test_normal06_formatprg() " basic test for formatprg " only test on non windows platform diff --git a/src/version.c b/src/version.c index 155d9dda20..85121d6e32 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2323, /**/ 2322, /**/ From e0ab94e7123ca7855f45919114d948ef2bc1e8c3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 19:50:54 +0200 Subject: [PATCH 3/9] patch 7.4.2324 Problem: Crash when editing a new buffer and BufUnload autocommand wipes out the new buffer. (Norio Takagi) Solution: Don't allow wiping out this buffer. (partly by Hirohito Higashi) Move old style test13 into test_autocmd. Avoid ml_get error when editing a file. --- src/Makefile | 2 +- src/buffer.c | 24 ++++++--- src/ex_cmds.c | 13 ++--- src/ex_docmd.c | 6 +-- src/structs.h | 4 +- src/testdir/Make_all.mak | 1 - src/testdir/test13.in | 64 ----------------------- src/testdir/test13.ok | 31 ------------ src/testdir/test_autocmd.vim | 98 ++++++++++++++++++++++++++++++++++++ src/version.c | 2 + src/window.c | 10 ++-- 11 files changed, 133 insertions(+), 122 deletions(-) delete mode 100644 src/testdir/test13.in delete mode 100644 src/testdir/test13.ok diff --git a/src/Makefile b/src/Makefile index b201ed494c..a56aa04e6c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2042,7 +2042,7 @@ test1 \ test_utf8 \ test_wordcount \ test2 test3 test4 test5 test6 test7 test8 test9 \ - test11 test12 test13 test14 test15 test17 test18 test19 \ + test11 test12 test14 test15 test17 test18 test19 \ test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \ test30 test31 test32 test33 test34 test36 test37 test38 test39 \ test40 test41 test42 test43 test44 test45 test48 test49 \ diff --git a/src/buffer.c b/src/buffer.c index 9270c39fc9..f375c1f649 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -476,6 +476,14 @@ close_buffer( unload_buf = TRUE; #endif + /* Disallow deleting the buffer when it is locked (already being closed or + * halfway a command that relies on it). Unloading is allowed. */ + if (buf->b_locked > 0 && (del_buf || wipe_buf)) + { + EMSG(_("E937: Attempt to delete a buffer that is in use")); + return; + } + if (win != NULL #ifdef FEAT_WINDOWS && win_valid_any_tab(win) /* in case autocommands closed the window */ @@ -499,7 +507,7 @@ close_buffer( /* When the buffer is no longer in a window, trigger BufWinLeave */ if (buf->b_nwindows == 1) { - buf->b_closing = TRUE; + ++buf->b_locked; if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, FALSE, buf) && !bufref_valid(&bufref)) @@ -509,7 +517,7 @@ aucmd_abort: EMSG(_(e_auabort)); return; } - buf->b_closing = FALSE; + --buf->b_locked; if (abort_if_last && one_window()) /* Autocommands made this the only window. */ goto aucmd_abort; @@ -518,13 +526,13 @@ aucmd_abort: * BufHidden */ if (!unload_buf) { - buf->b_closing = TRUE; + ++buf->b_locked; if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname, FALSE, buf) && !bufref_valid(&bufref)) /* Autocommands deleted the buffer. */ goto aucmd_abort; - buf->b_closing = FALSE; + --buf->b_locked; if (abort_if_last && one_window()) /* Autocommands made this the only window. */ goto aucmd_abort; @@ -685,7 +693,7 @@ buf_freeall(buf_T *buf, int flags) # endif /* Make sure the buffer isn't closed by autocommands. */ - buf->b_closing = TRUE; + ++buf->b_locked; set_bufref(&bufref, buf); if (buf->b_ml.ml_mfp != NULL) { @@ -711,7 +719,7 @@ buf_freeall(buf_T *buf, int flags) /* autocommands deleted the buffer */ return; } - buf->b_closing = FALSE; + --buf->b_locked; # ifdef FEAT_WINDOWS /* If the buffer was in curwin and the window has changed, go back to that @@ -1369,7 +1377,7 @@ do_buffer( */ while (buf == curbuf # ifdef FEAT_AUTOCMD - && !(curwin->w_closing || curwin->w_buffer->b_closing) + && !(curwin->w_closing || curwin->w_buffer->b_locked > 0) # endif && (firstwin != lastwin || first_tabpage->tp_next != NULL)) { @@ -5100,7 +5108,7 @@ ex_buffer_all(exarg_T *eap) #endif ) && firstwin != lastwin #ifdef FEAT_AUTOCMD - && !(wp->w_closing || wp->w_buffer->b_closing) + && !(wp->w_closing || wp->w_buffer->b_locked > 0) #endif ) { diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 61ab2ab125..daae0dd6fd 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3872,8 +3872,8 @@ do_ecmd( oldbuf = TRUE; set_bufref(&bufref, buf); (void)buf_check_timestamp(buf, FALSE); - /* Check if autocommands made buffer invalid or changed the current - * buffer. */ + /* Check if autocommands made the buffer invalid or changed the + * current buffer. */ if (!bufref_valid(&bufref) #ifdef FEAT_AUTOCMD || curbuf != old_curbuf.br_buf @@ -3938,8 +3938,9 @@ do_ecmd( win_T *the_curwin = curwin; /* Set the w_closing flag to avoid that autocommands close the - * window. */ + * window. And set b_locked for the same reason. */ the_curwin->w_closing = TRUE; + ++buf->b_locked; if (curbuf == old_curbuf.br_buf) #endif @@ -3953,6 +3954,7 @@ do_ecmd( #ifdef FEAT_AUTOCMD the_curwin->w_closing = FALSE; + --buf->b_locked; # ifdef FEAT_EVAL /* autocmds may abort script processing */ @@ -4139,11 +4141,6 @@ do_ecmd( /* Assume success now */ retval = OK; - /* - * Reset cursor position, could be used by autocommands. - */ - check_cursor(); - /* * Check if we are editing the w_arg_idx file in the argument list. */ diff --git a/src/ex_docmd.c b/src/ex_docmd.c index b568e46c3b..dc0a71e682 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7201,7 +7201,7 @@ ex_quit(exarg_T *eap) /* Refuse to quit when locked or when the buffer in the last window is * being closed (can only happen in autocommands). */ if (curbuf_locked() || (wp->w_buffer->b_nwindows == 1 - && wp->w_buffer->b_closing)) + && wp->w_buffer->b_locked > 0)) return; #endif @@ -7283,7 +7283,7 @@ ex_quit_all(exarg_T *eap) apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); /* Refuse to quit when locked or when the buffer in the last window is * being closed (can only happen in autocommands). */ - if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) + if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) return; #endif @@ -7665,7 +7665,7 @@ ex_exit(exarg_T *eap) apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); /* Refuse to quit when locked or when the buffer in the last window is * being closed (can only happen in autocommands). */ - if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) + if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0)) return; #endif diff --git a/src/structs.h b/src/structs.h index ebeefd091f..a44bcec4cb 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1845,8 +1845,8 @@ struct file_buffer int b_flags; /* various BF_ flags */ #ifdef FEAT_AUTOCMD - int b_closing; /* buffer is being closed, don't let - autocommands close it too. */ + int b_locked; /* Buffer is being closed or referenced, don't + let autocommands wipe it out. */ #endif /* diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index b038605fbc..5a7099337d 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -111,7 +111,6 @@ SCRIPTS_MORE1 = \ SCRIPTS_MORE2 = \ test2.out \ test12.out \ - test13.out \ test25.out \ test49.out \ test97.out \ diff --git a/src/testdir/test13.in b/src/testdir/test13.in deleted file mode 100644 index cbf78c7367..0000000000 --- a/src/testdir/test13.in +++ /dev/null @@ -1,64 +0,0 @@ -Tests for autocommands on :close command - -Write three files and open them, each in a window. -Then go to next window, with autocommand that deletes the previous one. -Do this twice, writing the file. - -Also test deleting the buffer on a Unload event. If this goes wrong there -will be the ATTENTION prompt. - -Also test changing buffers in a BufDel autocommand. If this goes wrong there -are ml_line errors and/or a Crash. - -STARTTEST -:so small.vim -:/^start of testfile/,/^end of testfile/w! Xtestje1 -:/^start of testfile/,/^end of testfile/w! Xtestje2 -:/^start of testfile/,/^end of testfile/w! Xtestje3 -:e Xtestje1 -otestje1 -:w -:sp Xtestje2 -otestje2 -:w -:sp Xtestje3 -otestje3 -:w - -:au WinLeave Xtestje2 bwipe - -:w! test.out -:au WinLeave Xtestje1 bwipe Xtestje3 -:close -:w >>test.out -:e Xtestje1 -:bwipe Xtestje2 Xtestje3 test.out -:au! -:au! BufUnload Xtestje1 bwipe -:e Xtestje3 -:w >>test.out -:e Xtestje2 -:sp Xtestje1 -:e -:w >>test.out -:au! -:only -:e Xtestje1 -:bwipe Xtestje2 Xtestje3 test.out test13.in -:au BufWipeout Xtestje1 buf Xtestje1 -:bwipe -:w >>test.out -:only -:help -:wincmd w -:1quit -:$put ='Final line' -:$w >>test.out -:qa! -ENDTEST - -start of testfile - contents - contents - contents -end of testfile diff --git a/src/testdir/test13.ok b/src/testdir/test13.ok deleted file mode 100644 index 66ebce63f7..0000000000 --- a/src/testdir/test13.ok +++ /dev/null @@ -1,31 +0,0 @@ -start of testfile -testje1 - contents - contents - contents -end of testfile -start of testfile -testje1 - contents - contents - contents -end of testfile -start of testfile -testje3 - contents - contents - contents -end of testfile -start of testfile -testje2 - contents - contents - contents -end of testfile -start of testfile -testje1 - contents - contents - contents -end of testfile -Final line diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index f05a55f1aa..43aa8d48dd 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -77,11 +77,49 @@ function Test_autocmd_bufunload_with_tabnext() quit call assert_equal(2, tabpagenr('$')) + autocmd! test_autocmd_bufunload_with_tabnext_group augroup! test_autocmd_bufunload_with_tabnext_group tablast quit endfunc +" SEGV occurs in older versions. (At least 7.4.2321 or older) +function Test_autocmd_bufunload_avoiding_SEGV_01() + split aa.txt + let lastbuf = bufnr('$') + + augroup test_autocmd_bufunload + autocmd! + exe 'autocmd BufUnload ' . (lastbuf + 1) . 'bwipeout!' + augroup END + + call assert_fails('edit bb.txt', 'E937:') + + autocmd! test_autocmd_bufunload + augroup! test_autocmd_bufunload + bwipe! aa.txt + bwipe! bb.txt +endfunc + +" SEGV occurs in older versions. (At least 7.4.2321 or older) +function Test_autocmd_bufunload_avoiding_SEGV_02() + setlocal buftype=nowrite + let lastbuf = bufnr('$') + + augroup test_autocmd_bufunload + autocmd! + exe 'autocmd BufUnload ' . (lastbuf + 1) . 'bwipeout!' + augroup END + + normal! i1 + call assert_fails('edit a.txt', 'E517:') + call feedkeys("\") + + autocmd! test_autocmd_bufunload + augroup! test_autocmd_bufunload + bwipe! a.txt +endfunc + func Test_win_tab_autocmd() let g:record = [] @@ -196,3 +234,63 @@ func Test_augroup_deleted() au! VimEnter endfunc +" Tests for autocommands on :close command. +" This used to be in test13. +func Test_three_windows() + " Write three files and open them, each in a window. + " Then go to next window, with autocommand that deletes the previous one. + " Do this twice, writing the file. + e! Xtestje1 + call setline(1, 'testje1') + w + sp Xtestje2 + call setline(1, 'testje2') + w + sp Xtestje3 + call setline(1, 'testje3') + w + wincmd w + au WinLeave Xtestje2 bwipe + wincmd w + call assert_equal('Xtestje1', expand('%')) + + au WinLeave Xtestje1 bwipe Xtestje3 + close + call assert_equal('Xtestje1', expand('%')) + + " Test deleting the buffer on a Unload event. If this goes wrong there + " will be the ATTENTION prompt. + e Xtestje1 + au! + au! BufUnload Xtestje1 bwipe + call assert_fails('e Xtestje3', 'E937:') + call assert_equal('Xtestje3', expand('%')) + + e Xtestje2 + sp Xtestje1 + call assert_fails('e', 'E937:') + call assert_equal('Xtestje2', expand('%')) + + " Test changing buffers in a BufWipeout autocommand. If this goes wrong + " there are ml_line errors and/or a Crash. + au! + only + e Xanother + e Xtestje1 + bwipe Xtestje2 + bwipe Xtestje3 + au BufWipeout Xtestje1 buf Xtestje1 + bwipe + call assert_equal('Xanother', expand('%')) + + only + help + wincmd w + 1quit + call assert_equal('Xanother', expand('%')) + + au! + call delete('Xtestje1') + call delete('Xtestje2') + call delete('Xtestje3') +endfunc diff --git a/src/version.c b/src/version.c index 85121d6e32..f5843dd502 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2324, /**/ 2323, /**/ diff --git a/src/window.c b/src/window.c index 4f992711fe..f61a83bb25 100644 --- a/src/window.c +++ b/src/window.c @@ -2127,7 +2127,7 @@ close_windows( { if (wp->w_buffer == buf && (!keep_curwin || wp != curwin) #ifdef FEAT_AUTOCMD - && !(wp->w_closing || wp->w_buffer->b_closing) + && !(wp->w_closing || wp->w_buffer->b_locked > 0) #endif ) { @@ -2148,7 +2148,7 @@ close_windows( for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next) if (wp->w_buffer == buf #ifdef FEAT_AUTOCMD - && !(wp->w_closing || wp->w_buffer->b_closing) + && !(wp->w_closing || wp->w_buffer->b_locked > 0) #endif ) { @@ -2287,7 +2287,8 @@ win_close(win_T *win, int free_buf) } #ifdef FEAT_AUTOCMD - if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing)) + if (win->w_closing || (win->w_buffer != NULL + && win->w_buffer->b_locked > 0)) return FAIL; /* window is already being closed */ if (win == aucmd_win) { @@ -2503,7 +2504,8 @@ win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) #ifdef FEAT_AUTOCMD /* Get here with win->w_buffer == NULL when win_close() detects the tab * page changed. */ - if (win->w_closing || (win->w_buffer != NULL && win->w_buffer->b_closing)) + if (win->w_closing || (win->w_buffer != NULL + && win->w_buffer->b_locked > 0)) return; /* window is already being closed */ #endif From 30180b8dad5c1478e7920e56a71352cb318fadb0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 19:57:56 +0200 Subject: [PATCH 4/9] patch 7.4.2325 Problem: Tiny build fails. Solution: Add #ifdef. --- src/buffer.c | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index f375c1f649..6489168214 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -476,6 +476,7 @@ close_buffer( unload_buf = TRUE; #endif +#ifdef FEAT_AUTOCMD /* Disallow deleting the buffer when it is locked (already being closed or * halfway a command that relies on it). Unloading is allowed. */ if (buf->b_locked > 0 && (del_buf || wipe_buf)) @@ -483,6 +484,7 @@ close_buffer( EMSG(_("E937: Attempt to delete a buffer that is in use")); return; } +#endif if (win != NULL #ifdef FEAT_WINDOWS diff --git a/src/version.c b/src/version.c index f5843dd502..95777312dc 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2325, /**/ 2324, /**/ From d5824ce1b5491df7d2eb0b66189d366fa67b4585 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 20:35:01 +0200 Subject: [PATCH 5/9] patch 7.4.2326 Problem: Illegal memory access when Visual selection starts in invalid position. (Dominique Pelle) Solution: Correct position when needed. --- src/misc2.c | 22 ++++++++++++++++++++++ src/normal.c | 3 +++ src/proto/misc2.pro | 1 + src/version.c | 2 ++ 4 files changed, 28 insertions(+) diff --git a/src/misc2.c b/src/misc2.c index 7c639d6bbf..4d914d233e 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -504,6 +504,28 @@ get_cursor_rel_lnum( return retval; } +/* + * Make sure "pos.lnum" and "pos.col" are valid in "buf". + * This allows for the col to be on the NUL byte. + */ + void +check_pos(buf_T *buf, pos_T *pos) +{ + char_u *line; + colnr_T len; + + if (pos->lnum > buf->b_ml.ml_line_count) + pos->lnum = buf->b_ml.ml_line_count; + + if (pos->col > 0) + { + line = ml_get_buf(buf, pos->lnum, FALSE); + len = (colnr_T)STRLEN(line); + if (pos->col > len) + pos->col = len; + } +} + /* * Make sure curwin->w_cursor.lnum is valid. */ diff --git a/src/normal.c b/src/normal.c index 0f9b23051d..edaa740e4c 100644 --- a/src/normal.c +++ b/src/normal.c @@ -9451,7 +9451,10 @@ get_op_vcol( #ifdef FEAT_MBYTE /* prevent from moving onto a trail byte */ if (has_mbyte) + { + check_pos(curwin->w_buffer, &oap->end); mb_adjustpos(curwin->w_buffer, &oap->end); + } #endif getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol); diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro index 70c7dae5b6..d18ae20330 100644 --- a/src/proto/misc2.pro +++ b/src/proto/misc2.pro @@ -12,6 +12,7 @@ int dec_cursor(void); int dec(pos_T *lp); int decl(pos_T *lp); linenr_T get_cursor_rel_lnum(win_T *wp, linenr_T lnum); +void check_pos(buf_T *buf, pos_T *pos); void check_cursor_lnum(void); void check_cursor_col(void); void check_cursor_col_win(win_T *win); diff --git a/src/version.c b/src/version.c index 95777312dc..06fb3ef552 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2326, /**/ 2325, /**/ From c8fe338d64cc6183c03d4c12b1e036a7745e2932 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 20:44:42 +0200 Subject: [PATCH 6/9] patch 7.4.2327 Problem: Freeing a variable that is on the stack. Solution: Don't free res_tv or err_tv. (Ozaki Kiichi) --- src/channel.c | 10 +++------- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/channel.c b/src/channel.c index bbe98be1b2..10ed42e6b7 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2142,7 +2142,7 @@ channel_exe_cmd(channel_T *channel, int part, typval_T *argv) } else { - typval_T *tv; + typval_T *tv = NULL; typval_T res_tv; typval_T err_tv; char_u *json = NULL; @@ -2159,8 +2159,6 @@ channel_exe_cmd(channel_T *channel, int part, typval_T *argv) ch_logs(channel, "Calling '%s'", (char *)arg); if (func_call(arg, &argv[2], NULL, NULL, &res_tv) == OK) tv = &res_tv; - else - tv = NULL; } if (argv[id_idx].v_type == VAR_NUMBER) @@ -2174,11 +2172,9 @@ channel_exe_cmd(channel_T *channel, int part, typval_T *argv) /* If evaluation failed or the result can't be encoded * then return the string "ERROR". */ vim_free(json); - free_tv(tv); err_tv.v_type = VAR_STRING; err_tv.vval.v_string = (char_u *)"ERROR"; - tv = &err_tv; - json = json_encode_nr_expr(id, tv, options | JSON_NL); + json = json_encode_nr_expr(id, &err_tv, options | JSON_NL); } if (json != NULL) { @@ -2191,7 +2187,7 @@ channel_exe_cmd(channel_T *channel, int part, typval_T *argv) --emsg_skip; if (tv == &res_tv) clear_tv(tv); - else if (tv != &err_tv) + else free_tv(tv); } } diff --git a/src/version.c b/src/version.c index 06fb3ef552..4ab697b9ba 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2327, /**/ 2326, /**/ From f9e687e0681a250e1549ab27b6c7ef2c500395e3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 21:33:09 +0200 Subject: [PATCH 7/9] patch 7.4.2328 Problem: Crash when BufWinLeave autocmd goes to another tab page. (Hirohito Higashi) Solution: Make close_buffer() go back to the right window. --- src/buffer.c | 18 ++++++++++++++++++ src/testdir/test_autocmd.vim | 10 ++++++++++ src/version.c | 2 ++ 3 files changed, 30 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index 6489168214..ac37685aa6 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -450,6 +450,11 @@ close_buffer( int is_curbuf; int nwindows; bufref_T bufref; +# ifdef FEAT_WINDOWS + int is_curwin = (curwin!= NULL && curwin->w_buffer == buf); + win_T *the_curwin = curwin; + tabpage_T *the_curtab = curtab; +# endif #endif int unload_buf = (action != 0); int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); @@ -544,6 +549,19 @@ aucmd_abort: return; # endif } + +# ifdef FEAT_WINDOWS + /* If the buffer was in curwin and the window has changed, go back to that + * window, if it still exists. This avoids that ":edit x" triggering a + * "tabnext" BufUnload autocmd leaves a window behind without a buffer. */ + if (is_curwin && curwin != the_curwin && win_valid_any_tab(the_curwin)) + { + block_autocmds(); + goto_tabpage_win(the_curtab, the_curwin); + unblock_autocmds(); + } +# endif + nwindows = buf->b_nwindows; #endif diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 43aa8d48dd..c029ca1bd6 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -83,6 +83,16 @@ function Test_autocmd_bufunload_with_tabnext() quit endfunc +function Test_autocmd_bufwinleave_with_tabfirst() + tabedit + augroup sample + autocmd! + autocmd BufWinLeave tabfirst + augroup END + call setline(1, ['a', 'b', 'c']) + edit! a.txt +endfunc + " SEGV occurs in older versions. (At least 7.4.2321 or older) function Test_autocmd_bufunload_avoiding_SEGV_01() split aa.txt diff --git a/src/version.c b/src/version.c index 4ab697b9ba..89e5f9509c 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2328, /**/ 2327, /**/ From 26b84339fd8766898bcf6a259cbc2e0c38689726 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 21:42:36 +0200 Subject: [PATCH 8/9] patch 7.4.2329 Problem: Error for min() and max() contains %s. (Nikolay Pavlov) Solution: Pass the function name. (closes #1040) --- src/evalfunc.c | 2 +- src/testdir/test_expr.vim | 7 +++++++ src/version.c | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 9d94694d82..1c1dcf7120 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -7629,7 +7629,7 @@ max_min(typval_T *argvars, typval_T *rettv, int domax) } } else - EMSG(_(e_listdictarg)); + EMSG2(_(e_listdictarg), domax ? "max()" : "min()"); rettv->vval.v_number = error ? 0 : n; } diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index 3097daf443..108ee508ea 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -335,6 +335,13 @@ function Test_printf_errors() call assert_fails('echo printf("%d", 1.2)', 'E805:') endfunc +function Test_max_min_errors() + call assert_fails('call max(v:true)', 'E712:') + call assert_fails('call max(v:true)', 'max()') + call assert_fails('call min(v:true)', 'E712:') + call assert_fails('call min(v:true)', 'min()') +endfunc + function Test_printf_64bit() if has('num64') call assert_equal("123456789012345", printf('%d', 123456789012345)) diff --git a/src/version.c b/src/version.c index 89e5f9509c..42eeaa84e5 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2329, /**/ 2328, /**/ From 030cddc7ec0c3d2fe3969140cd1b92b2f18633c0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 4 Sep 2016 23:41:42 +0200 Subject: [PATCH 9/9] patch 7.4.2330 Problem: Coverity complains about not checking curwin to be NULL. Solution: Use firstwin to avoid the warning. --- src/buffer.c | 6 +++--- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index ac37685aa6..398fee7b6f 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -707,7 +707,7 @@ buf_freeall(buf_T *buf, int flags) int is_curbuf = (buf == curbuf); bufref_T bufref; # ifdef FEAT_WINDOWS - int is_curwin = (curwin!= NULL && curwin->w_buffer == buf); + int is_curwin = (curwin != NULL && curwin->w_buffer == buf); win_T *the_curwin = curwin; tabpage_T *the_curtab = curtab; # endif @@ -772,7 +772,7 @@ buf_freeall(buf_T *buf, int flags) #endif #ifdef FEAT_SYN_HL /* Remove any ownsyntax, unless exiting. */ - if (firstwin != NULL && curwin->w_buffer == buf) + if (curwin != NULL && curwin->w_buffer == buf) reset_synblock(curwin); #endif @@ -788,7 +788,7 @@ buf_freeall(buf_T *buf, int flags) clearFolding(win); } # else - if (curwin->w_buffer == buf) + if (curwin != NULL && curwin->w_buffer == buf) clearFolding(curwin); # endif #endif diff --git a/src/version.c b/src/version.c index 42eeaa84e5..31324c49fe 100644 --- a/src/version.c +++ b/src/version.c @@ -763,6 +763,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2330, /**/ 2329, /**/