aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c18
-rw-r--r--src/nvim/eval/funcs.c2
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim12
3 files changed, 31 insertions, 1 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 8bd91ec9a2..0e4dbeaea6 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -65,6 +65,7 @@ static char *e_nowhitespace
= N_("E274: No white space allowed before parenthesis");
static char *e_write2 = N_("E80: Error while writing: %s");
static char *e_string_list_or_blob_required = N_("E1098: String, List or Blob required");
+static char e_expression_too_recursive_str[] = N_("E1169: Expression too recursive: %s");
static char * const namespace_char = "abglstvw";
@@ -2911,6 +2912,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
const char *start_leader, *end_leader;
int ret = OK;
char *alias;
+ static int recurse = 0;
// Initialise variable so that tv_clear() can't mistake this for a
// string and free a string that isn't there.
@@ -2923,6 +2925,20 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
}
end_leader = *arg;
+ // Limit recursion to 1000 levels. At least at 10000 we run out of stack
+ // and crash. With MSVC the stack is smaller.
+ if (recurse ==
+#ifdef _MSC_VER
+ 300
+#else
+ 1000
+#endif
+ ) {
+ semsg(_(e_expression_too_recursive_str), *arg);
+ return FAIL;
+ }
+ recurse++;
+
switch (**arg) {
// Number constant.
case '0':
@@ -3127,6 +3143,8 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
if (ret == OK && evaluate && end_leader > start_leader) {
ret = eval7_leader(rettv, (char *)start_leader, &end_leader);
}
+
+ recurse--;
return ret;
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index f66ff7b5bb..b475ff1096 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -5921,7 +5921,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
for (p = buf, start = buf;
p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
p++) {
- if (*p == '\n' || readlen <= 0) {
+ if (readlen <= 0 || *p == '\n') {
char *s = NULL;
size_t len = (size_t)(p - start);
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index dc110af356..851048ec5b 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -120,6 +120,13 @@ func Test_readfile_binary()
call delete('XReadfile_bin')
endfunc
+func Test_readfile_binary_empty()
+ call writefile([], 'Xempty-file')
+ " This used to compare uninitialized memory in Vim <= 8.2.4065
+ call assert_equal([''], readfile('Xempty-file', 'b'))
+ call delete('Xempty-file')
+endfunc
+
func Test_readfile_bom()
call writefile(["\ufeffFOO", "FOO\ufeffBAR"], 'XReadfile_bom')
call assert_equal(['FOO', 'FOOBAR'], readfile('XReadfile_bom'))
@@ -360,6 +367,11 @@ func Test_curly_assignment()
unlet g:gvar
endfunc
+func Test_deep_recursion()
+ " this was running out of stack
+ call assert_fails("exe 'if ' .. repeat('(', 1002)", 'E1169: Expression too recursive: ((')
+endfunc
+
" K_SPECIAL in the modified character used be escaped, which causes
" double-escaping with feedkeys() or as the return value of an <expr> mapping,
" and doesn't match what getchar() returns,