patch 8.2.2001: Vim9: :def function does not apply 'maxfuncdepth'
Problem: Vim9: :def function does not apply 'maxfuncdepth'. Solution: Use 'maxfuncdepth'. (issue #7313)
This commit is contained in:
		| @ -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); | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -750,6 +750,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     2001, | ||||
| /**/ | ||||
|     2000, | ||||
| /**/ | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user