]> granicus.if.org Git - vim/commitdiff
patch 8.2.2001: Vim9: :def function does not apply 'maxfuncdepth' v8.2.2001
authorBram Moolenaar <Bram@vim.org>
Tue, 17 Nov 2020 17:23:19 +0000 (18:23 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 17 Nov 2020 17:23:19 +0000 (18:23 +0100)
Problem:    Vim9: :def function does not apply 'maxfuncdepth'.
Solution:   Use 'maxfuncdepth'. (issue #7313)

src/proto/userfunc.pro
src/testdir/test_vim9_func.vim
src/userfunc.c
src/version.c
src/vim9execute.c

index 5bc7a4b90fc065ca56028ff771d1c503fe42c2bc..7ee36dbc1856bb7a9741d10bd74ceebd0691aee6 100644 (file)
@@ -14,6 +14,10 @@ ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx);
 int func_is_global(ufunc_T *ufunc);
 int func_name_refcount(char_u *name);
 void copy_func(char_u *lambda, char_u *global);
+int funcdepth_increment(void);
+void funcdepth_decrement(void);
+int funcdepth_get(void);
+void funcdepth_restore(int depth);
 int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
 void save_funccal(funccal_entry_T *entry);
 void restore_funccal(void);
index a3f21491f2162d1f16d9f88df606e52cff28da61..bbfce23c4ad7419f5af589c472734872b4b809a5 100644 (file)
@@ -49,6 +49,36 @@ def TestCompilingError()
   call delete('XTest_compile_error')
 enddef
 
+def CallRecursive(n: number): number
+  return CallRecursive(n + 1)
+enddef
+
+def CallMapRecursive(l: list<number>): number
+  return map(l, {_, v -> CallMapRecursive([v])})[0]
+enddef
+
+def Test_funcdepth_error()
+  set maxfuncdepth=10
+
+  var caught = false
+  try
+    CallRecursive(1)
+  catch /E132:/
+    caught = true
+  endtry
+  assert_true(caught)
+
+  caught = false
+  try
+    CallMapRecursive([1])
+  catch /E132:/
+    caught = true
+  endtry
+  assert_true(caught)
+
+  set maxfuncdepth&
+enddef
+
 def ReturnString(): string
   return 'string'
 enddef
index 6e780ea0118009a03db2d86e2b22b040b28c042f..7a306b1b7f5a3e766be1c8ab62be337c5f73b9fd 100644 (file)
@@ -1373,6 +1373,50 @@ failed:
     func_clear_free(fp, TRUE);
 }
 
+static int     funcdepth = 0;
+
+/*
+ * Increment the function call depth count.
+ * Return FAIL when going over 'maxfuncdepth'.
+ * Otherwise return OK, must call funcdepth_decrement() later!
+ */
+    int
+funcdepth_increment(void)
+{
+    if (funcdepth >= p_mfd)
+    {
+       emsg(_("E132: Function call depth is higher than 'maxfuncdepth'"));
+       return FAIL;
+    }
+    ++funcdepth;
+    return OK;
+}
+
+    void
+funcdepth_decrement(void)
+{
+    --funcdepth;
+}
+
+/*
+ * Get the current function call depth.
+ */
+    int
+funcdepth_get(void)
+{
+    return funcdepth;
+}
+
+/*
+ * Restore the function call depth.  This is for cases where there is no
+ * garantee funcdepth_decrement() can be called exactly the same number of
+ * times as funcdepth_increment().
+ */
+    void
+funcdepth_restore(int depth)
+{
+    funcdepth = depth;
+}
 
 /*
  * Call a user function.
@@ -1391,7 +1435,6 @@ call_user_func(
     funccall_T *fc;
     int                save_did_emsg;
     int                default_arg_err = FALSE;
-    static int depth = 0;
     dictitem_T *v;
     int                fixvar_idx = 0; // index in fixvar[]
     int                i;
@@ -1406,15 +1449,13 @@ call_user_func(
 #endif
     ESTACK_CHECK_DECLARATION
 
-    // If depth of calling is getting too high, don't execute the function
-    if (depth >= p_mfd)
+    // If depth of calling is getting too high, don't execute the function.
+    if (funcdepth_increment() == FAIL)
     {
-       emsg(_("E132: Function call depth is higher than 'maxfuncdepth'"));
        rettv->v_type = VAR_NUMBER;
        rettv->vval.v_number = -1;
        return;
     }
-    ++depth;
 
     line_breakcheck();         // check for CTRL-C hit
 
@@ -1437,7 +1478,7 @@ call_user_func(
     {
        // Execute the function, possibly compiling it first.
        call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
-       --depth;
+       funcdepth_decrement();
        current_funccal = fc->caller;
        free_funccal(fc);
        return;
@@ -1783,8 +1824,7 @@ call_user_func(
     }
 
     did_emsg |= save_did_emsg;
-    --depth;
-
+    funcdepth_decrement();
     cleanup_function_call(fc);
 }
 
index a988b21dc1fdba60eb294530c29332c12e1467a8..4b91cf1ca1c7e2e70f05396588e6b53aad90822d 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2001,
 /**/
     2000,
 /**/
index d8f9cfe02dfb6eea68326148b56426ee9eca935c..a7d83b47a70c7e9fffa79cc87dc4df5c9ec49f88 100644 (file)
@@ -227,6 +227,10 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx)
                                                                       == FAIL)
        return FAIL;
 
+    // If depth of calling is getting too high, don't execute the function.
+    if (funcdepth_increment() == FAIL)
+       return FAIL;
+
     // Move the vararg-list to below the missing optional arguments.
     if (vararg_count > 0 && arg_to_add > 0)
        *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1);
@@ -503,6 +507,7 @@ func_return(ectx_T *ectx)
     ectx->ec_stack.ga_len = top + 1;
     *STACK_TV_BOT(-1) = *STACK_TV(idx);
 
+    funcdepth_decrement();
     return OK;
 }
 
@@ -835,6 +840,7 @@ call_def_function(
     cmdmod_T   save_cmdmod;
     int                restore_cmdmod = FALSE;
     int                trylevel_at_start = trylevel;
+    int                orig_funcdepth;
 
 // Get pointer to item in the stack.
 #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
@@ -870,11 +876,19 @@ call_def_function(
        }
     }
 
+    // If depth of calling is getting too high, don't execute the function.
+    orig_funcdepth = funcdepth_get();
+    if (funcdepth_increment() == FAIL)
+       return FAIL;
+
     CLEAR_FIELD(ectx);
     ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
     ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
     if (ga_grow(&ectx.ec_stack, 20) == FAIL)
+    {
+       funcdepth_decrement();
        return FAIL;
+    }
     ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
     ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10);
 
@@ -2941,6 +2955,7 @@ failed_early:
     if (ret != OK && did_emsg == did_emsg_before)
        semsg(_(e_unknown_error_while_executing_str),
                                                   printable_func_name(ufunc));
+    funcdepth_restore(orig_funcdepth);
     return ret;
 }