aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval/userfunc.c7
-rw-r--r--src/nvim/ex_eval.c17
-rw-r--r--src/nvim/ex_eval.h7
-rw-r--r--src/nvim/screen.c10
-rw-r--r--src/nvim/testdir/test_statusline.vim12
-rw-r--r--src/nvim/testdir/test_trycatch.vim92
6 files changed, 129 insertions, 16 deletions
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index eb5c6e503a..0fadc0d220 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -3017,11 +3017,12 @@ void ex_call(exarg_T *eap)
}
}
- // When inside :try we need to check for following "| catch".
- if (!failed || eap->cstack->cs_trylevel > 0) {
+ // When inside :try we need to check for following "| catch" or "| endtry".
+ // Not when there was an error, but do check if an exception was thrown.
+ if ((!aborting() || current_exception != NULL) && (!failed || eap->cstack->cs_trylevel > 0)) {
// Check for trailing illegal characters and a following command.
if (!ends_excmd(*arg)) {
- if (!failed) {
+ if (!failed && !aborting()) {
emsg_severe = true;
emsg(_(e_trailing));
}
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 3c7c635d98..f4aaab5c43 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -1083,7 +1083,7 @@ void ex_endwhile(exarg_T *eap)
if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = err;
} else {
- fl = cstack->cs_flags[cstack->cs_idx];
+ fl = cstack->cs_flags[cstack->cs_idx];
if (!(fl & csf)) {
// If we are in a ":while" or ":for" but used the wrong endloop
// command, do not rewind to the next enclosing ":for"/":while".
@@ -1575,6 +1575,7 @@ void ex_endtry(exarg_T *eap)
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
eap->errmsg = get_end_emsg(cstack);
+
// Find the matching ":try" and report what's missing.
idx = cstack->cs_idx;
do {
@@ -1594,6 +1595,9 @@ void ex_endtry(exarg_T *eap)
if (current_exception) {
discard_current_exception();
}
+
+ // report eap->errmsg, also when there already was an error
+ did_emsg = false;
} else {
idx = cstack->cs_idx;
@@ -1664,8 +1668,10 @@ void ex_endtry(exarg_T *eap)
*/
(void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE);
- --cstack->cs_idx;
- --cstack->cs_trylevel;
+ if (cstack->cs_idx >= 0 && (cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
+ cstack->cs_idx--;
+ }
+ cstack->cs_trylevel--;
if (!skip) {
report_resume_pending(pending,
@@ -1913,7 +1919,7 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
default:
if (cstack->cs_flags[idx] & CSF_FINALLY) {
- if (cstack->cs_pending[idx] & CSTP_THROW) {
+ if ((cstack->cs_pending[idx] & CSTP_THROW) && cstack->cs_exception[idx] != NULL) {
// Cancel the pending exception. This is in the
// finally clause, so that the stack of the
// caught exceptions is not involved.
@@ -1934,8 +1940,9 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
*/
if (!(cstack->cs_flags[idx] & CSF_FINALLY)) {
if ((cstack->cs_flags[idx] & CSF_ACTIVE)
- && (cstack->cs_flags[idx] & CSF_CAUGHT)) {
+ && (cstack->cs_flags[idx] & CSF_CAUGHT) && !(cstack->cs_flags[idx] & CSF_FINISHED)) {
finish_exception((except_T *)cstack->cs_exception[idx]);
+ cstack->cs_flags[idx] |= CSF_FINISHED;
}
// Stop at this try conditional - except the try block never
// got active (because of an inactive surrounding conditional
diff --git a/src/nvim/ex_eval.h b/src/nvim/ex_eval.h
index 15da4b2d60..1cd0a47d7a 100644
--- a/src/nvim/ex_eval.h
+++ b/src/nvim/ex_eval.h
@@ -14,9 +14,10 @@
#define CSF_TRY 0x0100 // is a ":try"
#define CSF_FINALLY 0x0200 // ":finally" has been passed
-#define CSF_THROWN 0x0400 // exception thrown to this try conditional
-#define CSF_CAUGHT 0x0800 // exception caught by this try conditional
-#define CSF_SILENT 0x1000 // "emsg_silent" reset by ":try"
+#define CSF_THROWN 0x0800 // exception thrown to this try conditional
+#define CSF_CAUGHT 0x1000 // exception caught by this try conditional
+#define CSF_FINISHED 0x2000 // CSF_CAUGHT was handled by finish_exception()
+#define CSF_SILENT 0x4000 // "emsg_silent" reset by ":try"
// Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
// (an ":if"), and CSF_SILENT is only used when CSF_TRY is set.
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 296255ed8c..5a33ebfb37 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -5173,19 +5173,19 @@ static void win_redr_status(win_T *wp)
*(p + len++) = ' ';
}
if (bt_help(wp->w_buffer)) {
- STRCPY(p + len, _("[Help]"));
+ snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Help]"));
len += (int)STRLEN(p + len);
}
if (wp->w_p_pvw) {
- STRCPY(p + len, _("[Preview]"));
+ snprintf((char *)p + len, MAXPATHL - len, "%s", _("[Preview]"));
len += (int)STRLEN(p + len);
}
if (bufIsChanged(wp->w_buffer)) {
- STRCPY(p + len, "[+]");
- len += 3;
+ snprintf((char *)p + len, MAXPATHL - len, "%s", "[+]");
+ len += (int)STRLEN(p + len);
}
if (wp->w_buffer->b_p_ro) {
- STRCPY(p + len, _("[RO]"));
+ snprintf((char *)p + len, MAXPATHL - len, "%s", _("[RO]"));
// len += (int)STRLEN(p + len); // dead assignment
}
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index fad13e3340..492d09c645 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -523,4 +523,16 @@ func Test_statusline_mbyte_fillchar()
%bw!
endfunc
+" Used to write beyond allocated memory. This assumes MAXPATHL is 4096 bytes.
+func Test_statusline_verylong_filename()
+ let fname = repeat('x', 4090)
+ " Nvim's swap file creation fails on Windows (E303) due to fname's length
+ " exe "new " .. fname
+ exe "noswapfile new " .. fname
+ set buftype=help
+ set previewwindow
+ redraw
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim
index adc1745b39..205ed095ea 100644
--- a/src/nvim/testdir/test_trycatch.vim
+++ b/src/nvim/testdir/test_trycatch.vim
@@ -1996,5 +1996,97 @@ func Test_reload_in_try_catch()
call delete('Xreload')
endfunc
+" Test for using throw in a called function with following error {{{1
+func Test_user_command_throw_in_function_call()
+ let lines =<< trim END
+ function s:get_dict() abort
+ throw 'my_error'
+ endfunction
+
+ try
+ call s:get_dict().foo()
+ catch /my_error/
+ let caught = 'yes'
+ catch
+ let caught = v:exception
+ endtry
+ call assert_equal('yes', caught)
+ END
+ call writefile(lines, 'XtestThrow')
+ source XtestThrow
+
+ call delete('XtestThrow')
+ unlet g:caught
+endfunc
+
+" Test for using throw in a called function with following endtry {{{1
+func Test_user_command_function_call_with_endtry()
+ let lines =<< trim END
+ funct s:throw(msg) abort
+ throw a:msg
+ endfunc
+ func s:main() abort
+ try
+ try
+ throw 'err1'
+ catch
+ call s:throw('err2') | endtry
+ catch
+ let s:caught = 'yes'
+ endtry
+ endfunc
+
+ call s:main()
+ call assert_equal('yes', s:caught)
+ END
+ call writefile(lines, 'XtestThrow')
+ source XtestThrow
+
+ call delete('XtestThrow')
+endfunc
+
+func ThisWillFail()
+
+endfunc
+
+" This was crashing prior to the fix in 8.2.3478.
+func Test_error_in_catch_and_finally()
+ let lines =<< trim END
+ try
+ echo x
+ catch
+ for l in []
+ finally
+ END
+ call writefile(lines, 'XtestCatchAndFinally')
+ try
+ source XtestCatchAndFinally
+ catch /E600:/
+ endtry
+
+ call delete('XtestCatchAndFinally')
+endfunc
+
+" This was causing an illegal memory access
+func Test_leave_block_in_endtry_not_called()
+ let lines =<< trim END
+ " vim9script
+ " try #
+ try "
+ for x in []
+ if
+ endwhile
+ if
+ endtry
+ END
+ call writefile(lines, 'XtestEndtry')
+ try
+ source XtestEndtry
+ catch /E171:/
+ endtry
+
+ call delete('XtestEndtry')
+endfunc
+
" Modeline {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker