Compare commits

...

8 Commits

Author SHA1 Message Date
Bram Moolenaar
fabaf753e2 patch 8.0.1423: error in return not caught by try/catch
Problem:    Error in return not caught by try/catch.
Solution:   Call update_force_abort(). (Yasuhiro Matsomoto, closes #2483)
2017-12-23 17:26:11 +01:00
Bram Moolenaar
45a0000d5c patch 8.0.1422: no fallback to underline when undercurl is not set
Problem:    No fallback to underline when undercurl is not set. (Ben Jackson)
Solution:   Check for the value to be empty instead of NULL. (closes #2424)
2017-12-22 21:12:34 +01:00
Bram Moolenaar
e6640ad44e patch 8.0.1421: accessing invalid memory with overlong byte sequence
Problem:    Accessing invalid memory with overlong byte sequence.
Solution:   Check for NUL character. (test by Dominique Pelle, closes #2485)
2017-12-22 21:06:56 +01:00
Bram Moolenaar
3c09722600 patch 8.0.1420: accessing freed memory in vimgrep
Problem:    Accessing freed memory in vimgrep.
Solution:   Check that the quickfix list is still valid. (Yegappan Lakshmanan,
            closes #2474)
2017-12-21 20:54:49 +01:00
Bram Moolenaar
b73fa629d6 patch 8.0.1419: cursor column is not updated after ]s
Problem:    Cursor column is not updated after ]s. (Gary Johnson)
Solution:   Set the curswant flag.
2017-12-21 20:27:47 +01:00
Bram Moolenaar
ae6f865125 patch 8.0.1418: no test for expanding backticks
Problem:    No test for expanding backticks.
Solution:   Add a test. (Dominique Pelle, closes #2479)
2017-12-20 22:32:20 +01:00
Bram Moolenaar
1bd999f982 patch 8.0.1417: test doesn't search for a sentence
Problem:    Test doesn't search for a sentence. Still fails when searching for
            start of sentence. (Dominique Pelle)
Solution:   Add paren. Check for MAXCOL in dec().
2017-12-19 22:25:40 +01:00
Bram Moolenaar
8ada6aa929 patch 8.0.1416: crash when searching for a sentence
Problem:    Crash when searching for a sentence.
Solution:   Return NUL when getting character at MAXCOL. (closes #2468)
2017-12-19 21:23:21 +01:00
19 changed files with 309 additions and 62 deletions

View File

@@ -2147,6 +2147,7 @@ test_arglist \
test_edit \ test_edit \
test_erasebackword \ test_erasebackword \
test_escaped_glob \ test_escaped_glob \
test_eval_stuff \
test_ex_undo \ test_ex_undo \
test_ex_z \ test_ex_z \
test_exec_while_if \ test_exec_while_if \

View File

@@ -11173,7 +11173,10 @@ f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
/* Find the start and length of the badly spelled word. */ /* Find the start and length of the badly spelled word. */
len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr); len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
if (len != 0) if (len != 0)
{
word = ml_get_cursor(); word = ml_get_cursor();
curwin->w_set_curswant = TRUE;
}
} }
else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL) else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
{ {

View File

@@ -4521,13 +4521,14 @@ get_address(
if (lnum != MAXLNUM) if (lnum != MAXLNUM)
curwin->w_cursor.lnum = lnum; curwin->w_cursor.lnum = lnum;
/* /*
* Start a forward search at the end of the line. * Start a forward search at the end of the line (unless
* before the first line).
* Start a backward search at the start of the line. * Start a backward search at the start of the line.
* This makes sure we never match in the current * This makes sure we never match in the current
* line, and can match anywhere in the * line, and can match anywhere in the
* next/previous line. * next/previous line.
*/ */
if (c == '/') if (c == '/' && curwin->w_cursor.lnum > 0)
curwin->w_cursor.col = MAXCOL; curwin->w_cursor.col = MAXCOL;
else else
curwin->w_cursor.col = 0; curwin->w_cursor.col = 0;

View File

@@ -2650,8 +2650,12 @@ del_lines(
int int
gchar_pos(pos_T *pos) gchar_pos(pos_T *pos)
{ {
char_u *ptr = ml_get_pos(pos); char_u *ptr;
/* When searching columns is sometimes put at the end of a line. */
if (pos->col == MAXCOL)
return NUL;
ptr = ml_get_pos(pos);
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
if (has_mbyte) if (has_mbyte)
return (*mb_ptr2char)(ptr); return (*mb_ptr2char)(ptr);

View File

@@ -348,24 +348,29 @@ inc_cursor(void)
int int
inc(pos_T *lp) inc(pos_T *lp)
{ {
char_u *p = ml_get_pos(lp); char_u *p;
if (*p != NUL) /* still within line, move to next char (may be NUL) */ /* when searching position may be set to end of a line */
if (lp->col != MAXCOL)
{ {
#ifdef FEAT_MBYTE p = ml_get_pos(lp);
if (has_mbyte) if (*p != NUL) /* still within line, move to next char (may be NUL) */
{ {
int l = (*mb_ptr2len)(p); #ifdef FEAT_MBYTE
if (has_mbyte)
{
int l = (*mb_ptr2len)(p);
lp->col += l; lp->col += l;
return ((p[l] != NUL) ? 0 : 2); return ((p[l] != NUL) ? 0 : 2);
} }
#endif #endif
lp->col++; lp->col++;
#ifdef FEAT_VIRTUALEDIT #ifdef FEAT_VIRTUALEDIT
lp->coladd = 0; lp->coladd = 0;
#endif #endif
return ((p[1] != NUL) ? 0 : 2); return ((p[1] != NUL) ? 0 : 2);
}
} }
if (lp->lnum != curbuf->b_ml.ml_line_count) /* there is a next line */ if (lp->lnum != curbuf->b_ml.ml_line_count) /* there is a next line */
{ {
@@ -412,8 +417,21 @@ dec(pos_T *lp)
#ifdef FEAT_VIRTUALEDIT #ifdef FEAT_VIRTUALEDIT
lp->coladd = 0; lp->coladd = 0;
#endif #endif
if (lp->col > 0) /* still within line */ if (lp->col == MAXCOL)
{ {
/* past end of line */
p = ml_get(lp->lnum);
lp->col = (colnr_T)STRLEN(p);
#ifdef FEAT_MBYTE
if (has_mbyte)
lp->col -= (*mb_head_off)(p, p + lp->col);
#endif
return 0;
}
if (lp->col > 0)
{
/* still within line */
lp->col--; lp->col--;
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
if (has_mbyte) if (has_mbyte)
@@ -424,8 +442,10 @@ dec(pos_T *lp)
#endif #endif
return 0; return 0;
} }
if (lp->lnum > 1) /* there is a prior line */
if (lp->lnum > 1)
{ {
/* there is a prior line */
lp->lnum--; lp->lnum--;
p = ml_get(lp->lnum); p = ml_get(lp->lnum);
lp->col = (colnr_T)STRLEN(p); lp->col = (colnr_T)STRLEN(p);
@@ -435,7 +455,9 @@ dec(pos_T *lp)
#endif #endif
return 1; return 1;
} }
return -1; /* at start of file */
/* at start of file */
return -1;
} }
/* /*
@@ -1600,11 +1622,17 @@ strup_save(char_u *orig)
char_u *s; char_u *s;
c = utf_ptr2char(p); c = utf_ptr2char(p);
l = utf_ptr2len(p);
if (c == 0)
{
/* overlong sequence, use only the first byte */
c = *p;
l = 1;
}
uc = utf_toupper(c); uc = utf_toupper(c);
/* Reallocate string when byte count changes. This is rare, /* Reallocate string when byte count changes. This is rare,
* thus it's OK to do another malloc()/free(). */ * thus it's OK to do another malloc()/free(). */
l = utf_ptr2len(p);
newl = utf_char2len(uc); newl = utf_char2len(uc);
if (newl != l) if (newl != l)
{ {
@@ -1663,11 +1691,17 @@ strlow_save(char_u *orig)
char_u *s; char_u *s;
c = utf_ptr2char(p); c = utf_ptr2char(p);
l = utf_ptr2len(p);
if (c == 0)
{
/* overlong sequence, use only the first byte */
c = *p;
l = 1;
}
lc = utf_tolower(c); lc = utf_tolower(c);
/* Reallocate string when byte count changes. This is rare, /* Reallocate string when byte count changes. This is rare,
* thus it's OK to do another malloc()/free(). */ * thus it's OK to do another malloc()/free(). */
l = utf_ptr2len(p);
newl = utf_char2len(lc); newl = utf_char2len(lc);
if (newl != l) if (newl != l)
{ {

View File

@@ -6814,6 +6814,8 @@ nv_brackets(cmdarg_T *cap)
clearopbeep(cap->oap); clearopbeep(cap->oap);
break; break;
} }
else
curwin->w_set_curswant = TRUE;
# ifdef FEAT_FOLDING # ifdef FEAT_FOLDING
if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
foldOpenCursor(); foldOpenCursor();

View File

@@ -144,6 +144,7 @@ static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *);
static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack); static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack);
static char_u *qf_pop_dir(struct dir_stack_T **); static char_u *qf_pop_dir(struct dir_stack_T **);
static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *); static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *);
static int qflist_valid(win_T *wp, int_u qf_id);
static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); static void qf_fmt_text(char_u *text, char_u *buf, int bufsize);
static void qf_clean_dir_stack(struct dir_stack_T **); static void qf_clean_dir_stack(struct dir_stack_T **);
static int qf_win_pos_update(qf_info_T *qi, int old_qf_index); static int qf_win_pos_update(qf_info_T *qi, int old_qf_index);
@@ -177,6 +178,9 @@ static qf_info_T *ll_get_or_alloc_list(win_T *);
static char_u *qf_last_bufname = NULL; static char_u *qf_last_bufname = NULL;
static bufref_T qf_last_bufref = {NULL, 0, 0}; static bufref_T qf_last_bufref = {NULL, 0, 0};
static char *e_loc_list_changed =
N_("E926: Current location list was changed");
/* /*
* Read the errorfile "efile" into memory, line by line, building the error * Read the errorfile "efile" into memory, line by line, building the error
* list. Set the error list's title to qf_title. * list. Set the error list's title to qf_title.
@@ -1927,6 +1931,29 @@ qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *filename)
return ds_ptr==NULL? NULL: ds_ptr->dirname; return ds_ptr==NULL? NULL: ds_ptr->dirname;
} }
/*
* Returns TRUE if a quickfix/location list with the given identifier exists.
*/
static int
qflist_valid (win_T *wp, int_u qf_id)
{
qf_info_T *qi = &ql_info;
int i;
if (wp != NULL)
{
qi = GET_LOC_LIST(wp); /* Location list */
if (qi == NULL)
return FALSE;
}
for (i = 0; i < qi->qf_listcount; ++i)
if (qi->qf_lists[i].qf_id == qf_id)
return TRUE;
return FALSE;
}
/* /*
* When loading a file from the quickfix, the auto commands may modify it. * When loading a file from the quickfix, the auto commands may modify it.
* This may invalidate the current quickfix entry. This function checks * This may invalidate the current quickfix entry. This function checks
@@ -2343,14 +2370,28 @@ qf_jump_edit_buffer(
else else
{ {
int old_qf_curlist = qi->qf_curlist; int old_qf_curlist = qi->qf_curlist;
int save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
retval = buflist_getfile(qf_ptr->qf_fnum, retval = buflist_getfile(qf_ptr->qf_fnum,
(linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
if (qi != &ql_info && !win_valid_any_tab(oldwin))
if (qi != &ql_info)
{ {
EMSG(_("E924: Current window was closed")); /*
*abort = TRUE; * Location list. Check whether the associated window is still
*opened_window = FALSE; * present and the list is still valid.
*/
if (!win_valid_any_tab(oldwin))
{
EMSG(_("E924: Current window was closed"));
*abort = TRUE;
*opened_window = FALSE;
}
else if (!qflist_valid(oldwin, save_qfid))
{
EMSG(_(e_loc_list_changed));
*abort = TRUE;
}
} }
else if (old_qf_curlist != qi->qf_curlist else if (old_qf_curlist != qi->qf_curlist
|| !is_qf_entry_present(qi, qf_ptr)) || !is_qf_entry_present(qi, qf_ptr))
@@ -2358,7 +2399,7 @@ qf_jump_edit_buffer(
if (qi == &ql_info) if (qi == &ql_info)
EMSG(_("E925: Current quickfix was changed")); EMSG(_("E925: Current quickfix was changed"));
else else
EMSG(_("E926: Current location list was changed")); EMSG(_(e_loc_list_changed));
*abort = TRUE; *abort = TRUE;
} }
@@ -4065,6 +4106,7 @@ ex_cfile(exarg_T *eap)
qf_info_T *qi = &ql_info; qf_info_T *qi = &ql_info;
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
char_u *au_name = NULL; char_u *au_name = NULL;
int save_qfid;
#endif #endif
int res; int res;
@@ -4122,8 +4164,15 @@ ex_cfile(exarg_T *eap)
if (res >= 0 && qi != NULL) if (res >= 0 && qi != NULL)
qf_list_changed(qi, qi->qf_curlist); qf_list_changed(qi, qi->qf_curlist);
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
if (au_name != NULL) if (au_name != NULL)
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf); apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf);
/*
* Autocmd might have freed the quickfix/location list. Check whether it is
* still valid
*/
if (!qflist_valid(wp, save_qfid))
return;
#endif #endif
if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile)) if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile))
{ {
@@ -4149,8 +4198,11 @@ ex_vimgrep(exarg_T *eap)
char_u *p; char_u *p;
int fi; int fi;
qf_info_T *qi = &ql_info; qf_info_T *qi = &ql_info;
int loclist_cmd = FALSE;
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
int_u save_qfid;
qfline_T *cur_qf_start; qfline_T *cur_qf_start;
win_T *wp;
#endif #endif
long lnum; long lnum;
buf_T *buf; buf_T *buf;
@@ -4204,6 +4256,7 @@ ex_vimgrep(exarg_T *eap)
qi = ll_get_or_alloc_list(curwin); qi = ll_get_or_alloc_list(curwin);
if (qi == NULL) if (qi == NULL)
return; return;
loclist_cmd = TRUE;
} }
if (eap->addr_count > 0) if (eap->addr_count > 0)
@@ -4274,8 +4327,9 @@ ex_vimgrep(exarg_T *eap)
mch_dirname(dirname_start, MAXPATHL); mch_dirname(dirname_start, MAXPATHL);
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
/* Remember the value of qf_start, so that we can check for autocommands /* Remember the current values of the quickfix list and qf_start, so that
* changing the current quickfix list. */ * we can check for autocommands changing the current quickfix list. */
save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start; cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start;
#endif #endif
@@ -4335,6 +4389,18 @@ ex_vimgrep(exarg_T *eap)
using_dummy = FALSE; using_dummy = FALSE;
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
if (loclist_cmd)
{
/*
* Verify that the location list is still valid. An autocmd might
* have freed the location list.
*/
if (!qflist_valid(curwin, save_qfid))
{
EMSG(_(e_loc_list_changed));
goto theend;
}
}
if (cur_qf_start != qi->qf_lists[qi->qf_curlist].qf_start) if (cur_qf_start != qi->qf_lists[qi->qf_curlist].qf_start)
{ {
int idx; int idx;
@@ -4491,6 +4557,13 @@ ex_vimgrep(exarg_T *eap)
if (au_name != NULL) if (au_name != NULL)
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
curbuf->b_fname, TRUE, curbuf); curbuf->b_fname, TRUE, curbuf);
/*
* The QuickFixCmdPost autocmd may free the quickfix list. Check the list
* is still valid.
*/
wp = loclist_cmd ? curwin : NULL;
if (!qflist_valid(wp, save_qfid))
goto theend;
#endif #endif
/* Jump to first match. */ /* Jump to first match. */
@@ -5543,7 +5616,8 @@ ex_cbuffer(exarg_T *eap)
#endif #endif
/* Must come after autocommands. */ /* Must come after autocommands. */
if (eap->cmdidx == CMD_lbuffer || eap->cmdidx == CMD_lgetbuffer if (eap->cmdidx == CMD_lbuffer
|| eap->cmdidx == CMD_lgetbuffer
|| eap->cmdidx == CMD_laddbuffer) || eap->cmdidx == CMD_laddbuffer)
{ {
qi = ll_get_or_alloc_list(curwin); qi = ll_get_or_alloc_list(curwin);
@@ -5614,14 +5688,6 @@ ex_cexpr(exarg_T *eap)
#endif #endif
int res; int res;
if (eap->cmdidx == CMD_lexpr || eap->cmdidx == CMD_lgetexpr
|| eap->cmdidx == CMD_laddexpr)
{
qi = ll_get_or_alloc_list(curwin);
if (qi == NULL)
return;
}
#ifdef FEAT_AUTOCMD #ifdef FEAT_AUTOCMD
switch (eap->cmdidx) switch (eap->cmdidx)
{ {
@@ -5643,6 +5709,15 @@ ex_cexpr(exarg_T *eap)
} }
#endif #endif
if (eap->cmdidx == CMD_lexpr
|| eap->cmdidx == CMD_lgetexpr
|| eap->cmdidx == CMD_laddexpr)
{
qi = ll_get_or_alloc_list(curwin);
if (qi == NULL)
return;
}
/* Evaluate the expression. When the result is a string or a list we can /* Evaluate the expression. When the result is a string or a list we can
* use it to fill the errorlist. */ * use it to fill the errorlist. */
tv = eval_expr(eap->arg, NULL); tv = eval_expr(eap->arg, NULL);

View File

@@ -8041,7 +8041,7 @@ screen_start_highlight(int attr)
else else
attr = aep->ae_attr; attr = aep->ae_attr;
} }
if ((attr & HL_BOLD) && T_MD != NULL) /* bold */ if ((attr & HL_BOLD) && *T_MD != NUL) /* bold */
out_str(T_MD); out_str(T_MD);
else if (aep != NULL && cterm_normal_fg_bold && else if (aep != NULL && cterm_normal_fg_bold &&
#ifdef FEAT_TERMGUICOLORS #ifdef FEAT_TERMGUICOLORS
@@ -8056,19 +8056,19 @@ screen_start_highlight(int attr)
/* If the Normal FG color has BOLD attribute and the new HL /* If the Normal FG color has BOLD attribute and the new HL
* has a FG color defined, clear BOLD. */ * has a FG color defined, clear BOLD. */
out_str(T_ME); out_str(T_ME);
if ((attr & HL_STANDOUT) && T_SO != NULL) /* standout */ if ((attr & HL_STANDOUT) && *T_SO != NUL) /* standout */
out_str(T_SO); out_str(T_SO);
if ((attr & HL_UNDERCURL) && T_UCS != NULL) /* undercurl */ if ((attr & HL_UNDERCURL) && *T_UCS != NUL) /* undercurl */
out_str(T_UCS); out_str(T_UCS);
if (((attr & HL_UNDERLINE) /* underline or undercurl */ if (((attr & HL_UNDERLINE) /* underline or undercurl */
|| ((attr & HL_UNDERCURL) && T_UCS == NULL)) || ((attr & HL_UNDERCURL) && *T_UCS == NUL))
&& T_US != NULL) && *T_US != NUL)
out_str(T_US); out_str(T_US);
if ((attr & HL_ITALIC) && T_CZH != NULL) /* italic */ if ((attr & HL_ITALIC) && *T_CZH != NUL) /* italic */
out_str(T_CZH); out_str(T_CZH);
if ((attr & HL_INVERSE) && T_MR != NULL) /* inverse (reverse) */ if ((attr & HL_INVERSE) && *T_MR != NUL) /* inverse (reverse) */
out_str(T_MR); out_str(T_MR);
if ((attr & HL_STRIKETHROUGH) && T_STS != NULL) /* strike */ if ((attr & HL_STRIKETHROUGH) && *T_STS != NUL) /* strike */
out_str(T_STS); out_str(T_STS);
/* /*
@@ -8180,7 +8180,7 @@ screen_stop_highlight(void)
else else
out_str(T_SE); out_str(T_SE);
} }
if ((screen_attr & HL_UNDERCURL) && T_UCE != NULL) if ((screen_attr & HL_UNDERCURL) && *T_UCE != NUL)
{ {
if (STRCMP(T_UCE, T_ME) == 0) if (STRCMP(T_UCE, T_ME) == 0)
do_ME = TRUE; do_ME = TRUE;
@@ -8188,7 +8188,7 @@ screen_stop_highlight(void)
out_str(T_UCE); out_str(T_UCE);
} }
if ((screen_attr & HL_UNDERLINE) if ((screen_attr & HL_UNDERLINE)
|| ((screen_attr & HL_UNDERCURL) && T_UCE == NULL)) || ((screen_attr & HL_UNDERCURL) && *T_UCE == NUL))
{ {
if (STRCMP(T_UE, T_ME) == 0) if (STRCMP(T_UE, T_ME) == 0)
do_ME = TRUE; do_ME = TRUE;

View File

@@ -94,6 +94,7 @@ NEW_TESTS = test_arabic.res \
test_edit.res \ test_edit.res \
test_erasebackword.res \ test_erasebackword.res \
test_escaped_glob.res \ test_escaped_glob.res \
test_eval_stuff.res \
test_exec_while_if.res \ test_exec_while_if.res \
test_exists.res \ test_exists.res \
test_exists_autocmd.res \ test_exists_autocmd.res \

View File

@@ -1178,10 +1178,3 @@ func Test_nocatch_wipe_dummy_buffer()
call assert_fails('lv½ /x', 'E480') call assert_fails('lv½ /x', 'E480')
au! au!
endfunc endfunc
func Test_wipe_cbuffer()
sv x
au * * bw
lb
au!
endfunc

View File

@@ -1,5 +1,7 @@
Test for various eval features. vim: set ft=vim : Test for various eval features. vim: set ft=vim :
NOTE: Do not add more here, use new style test test_eval_stuff.vim
Note: system clipboard is saved, changed and restored. Note: system clipboard is saved, changed and restored.
clipboard contents clipboard contents
@@ -134,10 +136,10 @@ if has('clipboard')
let _clipreg = ['*', getreg('*'), getregtype('*')] let _clipreg = ['*', getreg('*'), getregtype('*')]
let _clipopt = &cb let _clipopt = &cb
let &cb='unnamed' let &cb='unnamed'
5y 7y
AR * AR *
tabdo :windo :echo "hi" tabdo :windo :echo "hi"
6y 8y
AR * AR *
let &cb=_clipopt let &cb=_clipopt
call call('setreg', _clipreg) call call('setreg', _clipreg)

View File

@@ -0,0 +1,13 @@
" Tests for various eval things.
function s:foo() abort
try
return [] == 0
catch
return 1
endtry
endfunction
func Test_catch_return_with_error()
call assert_equal(1, s:foo())
endfunc

View File

@@ -268,6 +268,11 @@ func Test_tolower()
" Ⱥ (U+023A) and Ⱦ (U+023E) are the *only* code points to increase " Ⱥ (U+023A) and Ⱦ (U+023E) are the *only* code points to increase
" in length (2 to 3 bytes) when lowercased. So let's test them. " in length (2 to 3 bytes) when lowercased. So let's test them.
call assert_equal("ⱥ ⱦ", tolower("Ⱥ Ⱦ")) call assert_equal("ⱥ ⱦ", tolower("Ⱥ Ⱦ"))
" This call to tolower with invalid utf8 sequence used to cause access to
" invalid memory.
call tolower("\xC0\x80\xC0")
call tolower("123\xC0\x80\xC0")
endfunc endfunc
func Test_toupper() func Test_toupper()
@@ -338,6 +343,11 @@ func Test_toupper()
call assert_equal("ZŹŻŽƵẐẔ", toupper("ZŹŻŽƵẐẔ")) call assert_equal("ZŹŻŽƵẐẔ", toupper("ZŹŻŽƵẐẔ"))
call assert_equal("Ⱥ Ⱦ", toupper("ⱥ ⱦ")) call assert_equal("Ⱥ Ⱦ", toupper("ⱥ ⱦ"))
" This call to toupper with invalid utf8 sequence used to cause access to
" invalid memory.
call toupper("\xC0\x80\xC0")
call toupper("123\xC0\x80\xC0")
endfunc endfunc
" Tests for the mode() function " Tests for the mode() function

View File

@@ -404,6 +404,15 @@ func! Test_normal10_expand()
call assert_equal(expected[i], expand('<cexpr>'), 'i == ' . i) call assert_equal(expected[i], expand('<cexpr>'), 'i == ' . i)
endfor endfor
if executable('echo')
" Test expand(`...`) i.e. backticks command expansion.
" MS-Windows has a trailing space.
call assert_match('^abcde *$', expand('`echo abcde`'))
endif
" Test expand(`=...`) i.e. backticks expression expansion
call assert_equal('5', expand('`=2+3`'))
" clean up " clean up
bw! bw!
endfunc endfunc
@@ -1537,12 +1546,12 @@ fun! Test_normal29_brace()
\ 'the ''{'' flag is in ''cpoptions'' then ''{'' in the first column is used as a', \ 'the ''{'' flag is in ''cpoptions'' then ''{'' in the first column is used as a',
\ 'paragraph boundary |posix|.', \ 'paragraph boundary |posix|.',
\ '{', \ '{',
\ 'This is no paragaraph', \ 'This is no paragraph',
\ 'unless the ''{'' is set', \ 'unless the ''{'' is set',
\ 'in ''cpoptions''', \ 'in ''cpoptions''',
\ '}', \ '}',
\ '.IP', \ '.IP',
\ 'The nroff macros IP seperates a paragraph', \ 'The nroff macros IP separates a paragraph',
\ 'That means, it must be a ''.''', \ 'That means, it must be a ''.''',
\ 'followed by IP', \ 'followed by IP',
\ '.LPIt does not matter, if afterwards some', \ '.LPIt does not matter, if afterwards some',
@@ -1557,7 +1566,7 @@ fun! Test_normal29_brace()
1 1
norm! 0d2} norm! 0d2}
call assert_equal(['.IP', call assert_equal(['.IP',
\ 'The nroff macros IP seperates a paragraph', 'That means, it must be a ''.''', 'followed by IP', \ 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''', 'followed by IP',
\ '.LPIt does not matter, if afterwards some', 'more characters follow.', '.SHAlso section boundaries from the nroff', \ '.LPIt does not matter, if afterwards some', 'more characters follow.', '.SHAlso section boundaries from the nroff',
\ 'macros terminate a paragraph. That means', 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$')) \ 'macros terminate a paragraph. That means', 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
norm! 0d} norm! 0d}
@@ -1576,21 +1585,21 @@ fun! Test_normal29_brace()
set cpo+={ set cpo+={
1 1
norm! 0d2} norm! 0d2}
call assert_equal(['{', 'This is no paragaraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}',
\ '.IP', 'The nroff macros IP seperates a paragraph', 'That means, it must be a ''.''', \ '.IP', 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''',
\ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.', \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.',
\ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means', \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
\ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$')) \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
$ $
norm! d} norm! d}
call assert_equal(['{', 'This is no paragaraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}',
\ '.IP', 'The nroff macros IP seperates a paragraph', 'That means, it must be a ''.''', \ '.IP', 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''',
\ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.', \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.',
\ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means', \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
\ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$')) \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
norm! gg} norm! gg}
norm! d5} norm! d5}
call assert_equal(['{', 'This is no paragaraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', ''], getline(1,'$')) call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', ''], getline(1,'$'))
" clean up " clean up
set cpo-={ set cpo-={

View File

@@ -3038,3 +3038,43 @@ func Test_lfile_crash()
call assert_fails('lfile', 'E40') call assert_fails('lfile', 'E40')
au! QuickFixCmdPre au! QuickFixCmdPre
endfunc endfunc
" The following test used to crash vim
func Test_lbuffer_crash()
sv Xtest
augroup QF_Test
au!
au * * bw
augroup END
lbuffer
augroup QF_Test
au!
augroup END
endfunc
" The following test used to crash vim
func Test_lexpr_crash()
augroup QF_Test
au!
au * * call setloclist(0, [], 'f')
augroup END
lexpr ""
augroup QF_Test
au!
augroup END
enew | only
endfunc
" The following test used to crash Vim
func Test_lvimgrep_crash()
sv Xtest
augroup QF_Test
au!
au * * call setloclist(0, [], 'f')
augroup END
lvimgrep quickfix test_quickfix.vim
augroup QF_Test
au!
augroup END
enew | only
endfunc

View File

@@ -729,3 +729,12 @@ func Test_look_behind()
call search(getline(".")) call search(getline("."))
bwipe! bwipe!
endfunc endfunc
func Test_search_sentence()
new
" this used to cause a crash
call assert_fails("/\\%')", 'E486')
call assert_fails("/", 'E486')
/\%'(
/
endfunc

View File

@@ -28,6 +28,37 @@ func Test_wrap_search()
set nospell set nospell
endfunc endfunc
func Test_curswant()
new
call setline(1, ['Another plong line', 'abcdefghijklmnopq'])
set spell wrapscan
normal 0]s
call assert_equal('plong', expand('<cword>'))
normal j
call assert_equal(9, getcurpos()[2])
normal 0[s
call assert_equal('plong', expand('<cword>'))
normal j
call assert_equal(9, getcurpos()[2])
normal 0]S
call assert_equal('plong', expand('<cword>'))
normal j
call assert_equal(9, getcurpos()[2])
normal 0[S
call assert_equal('plong', expand('<cword>'))
normal j
call assert_equal(9, getcurpos()[2])
normal 1G0
call assert_equal('plong', spellbadword()[0])
normal j
call assert_equal(9, getcurpos()[2])
bwipe!
set nospell
endfunc
func Test_z_equal_on_invalid_utf8_word() func Test_z_equal_on_invalid_utf8_word()
split split
set spell set spell

View File

@@ -2972,6 +2972,9 @@ ex_return(exarg_T *eap)
/* It's safer to return also on error. */ /* It's safer to return also on error. */
else if (!eap->skip) else if (!eap->skip)
{ {
/* In return statement, cause_abort should be force_abort. */
update_force_abort();
/* /*
* Return unless the expression evaluation has been cancelled due to an * Return unless the expression evaluation has been cancelled due to an
* aborting error, an interrupt, or an exception. * aborting error, an interrupt, or an exception.

View File

@@ -771,6 +771,22 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1423,
/**/
1422,
/**/
1421,
/**/
1420,
/**/
1419,
/**/
1418,
/**/
1417,
/**/
1416,
/**/ /**/
1415, 1415,
/**/ /**/