# HG changeset patch # User Bram Moolenaar # Date 1585691104 -7200 # Node ID 8288884fdfe1c07cd905810eaec8678aa5b5cc7a # Parent b6f8f6d22e8e8b0b4f66e1c40c90c4e75386d3c8 patch 8.2.0488: Vim9: compiling can break when using a lambda inside :def Commit: https://github.com/vim/vim/commit/05afceeddc4afbbca60e4e6a729a50d33d4b19f7 Author: Bram Moolenaar Date: Tue Mar 31 23:32:31 2020 +0200 patch 8.2.0488: Vim9: compiling can break when using a lambda inside :def Problem: Vim9: Compiling can break when using a lambda inside :def. Solution: Do not keep a pointer to the dfunc_T for longer time. diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 488, +/**/ 487, /**/ 486, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -257,7 +257,7 @@ struct dfunc_S { // Functions defined with :def are stored in this growarray. // They are never removed, so that they can be found by index. // Deleted functions have the df_deleted flag set. -garray_T def_functions = {0, 0, sizeof(dfunc_T), 200, NULL}; +garray_T def_functions = {0, 0, sizeof(dfunc_T), 50, NULL}; #else extern garray_T def_functions; #endif diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5029,11 +5029,12 @@ compile_execute(char_u *arg, cctx_T *cct * Adds the function to "def_functions". * When "set_return_type" is set then set ufunc->uf_ret_type to the type of the * return statement (used for lambda). + * This can be used recursively through compile_lambda(), which may reallocate + * "def_functions". */ void compile_def_function(ufunc_T *ufunc, int set_return_type) { - dfunc_T *dfunc; char_u *line = NULL; char_u *p; exarg_T ea; @@ -5046,25 +5047,29 @@ compile_def_function(ufunc_T *ufunc, int sctx_T save_current_sctx = current_sctx; int emsg_before = called_emsg; - if (ufunc->uf_dfunc_idx >= 0) { - // Redefining a function that was compiled before. - dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - - // Free old instructions. - delete_def_function_contents(dfunc); - } - else - { - // Add the function to "def_functions". - if (ga_grow(&def_functions, 1) == FAIL) - return; - dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len; - vim_memset(dfunc, 0, sizeof(dfunc_T)); - dfunc->df_idx = def_functions.ga_len; - ufunc->uf_dfunc_idx = dfunc->df_idx; - dfunc->df_ufunc = ufunc; - ++def_functions.ga_len; + dfunc_T *dfunc; // may be invalidated by compile_lambda() + + if (ufunc->uf_dfunc_idx >= 0) + { + // Redefining a function that was compiled before. + dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; + + // Free old instructions. + delete_def_function_contents(dfunc); + } + else + { + // Add the function to "def_functions". + if (ga_grow(&def_functions, 1) == FAIL) + return; + dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len; + vim_memset(dfunc, 0, sizeof(dfunc_T)); + dfunc->df_idx = def_functions.ga_len; + ufunc->uf_dfunc_idx = dfunc->df_idx; + dfunc->df_ufunc = ufunc; + ++def_functions.ga_len; + } } vim_memset(&cctx, 0, sizeof(cctx)); @@ -5414,10 +5419,14 @@ compile_def_function(ufunc_T *ufunc, int generate_instr(&cctx, ISN_RETURN); } - dfunc->df_deleted = FALSE; - dfunc->df_instr = instr->ga_data; - dfunc->df_instr_count = instr->ga_len; - dfunc->df_varcount = cctx.ctx_max_local; + { + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; + dfunc->df_deleted = FALSE; + dfunc->df_instr = instr->ga_data; + dfunc->df_instr_count = instr->ga_len; + dfunc->df_varcount = cctx.ctx_max_local; + } ret = OK; @@ -5425,6 +5434,8 @@ erret: if (ret == FAIL) { int idx; + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; for (idx = 0; idx < instr->ga_len; ++idx) delete_instr(((isn_T *)instr->ga_data) + idx);