summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-03-31 23:32:31 +0200
committerBram Moolenaar <Bram@vim.org>2020-03-31 23:32:31 +0200
commit05afceeddc4afbbca60e4e6a729a50d33d4b19f7 (patch)
tree6a9153d6198fde25a73ba3cd1c7a7be60e7d94aa
parentbd5da371aafe5a2207065643502f4d1ff6b286c7 (diff)
patch 8.2.0488: Vim9: compiling can break when using a lambda inside :defv8.2.0488
Problem: Vim9: Compiling can break when using a lambda inside :def. Solution: Do not keep a pointer to the dfunc_T for longer time.
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h2
-rw-r--r--src/vim9compile.c55
3 files changed, 36 insertions, 23 deletions
diff --git a/src/version.c b/src/version.c
index 549bf3bed4..58180acc4b 100644
--- 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
index 7b95c377ef..a414caa63a 100644
--- 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
index c7f5032644..3c3f5a1635 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -5029,11 +5029,12 @@ compile_execute(char_u *arg, cctx_T *cctx)
* 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 set_return_type)
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;
+ dfunc_T *dfunc; // may be invalidated by compile_lambda()
- // 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;
+ 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 set_return_type)
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);