]> granicus.if.org Git - vim/commitdiff
patch 8.2.0488: Vim9: compiling can break when using a lambda inside :def v8.2.0488
authorBram Moolenaar <Bram@vim.org>
Tue, 31 Mar 2020 21:32:31 +0000 (23:32 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 31 Mar 2020 21:32:31 +0000 (23:32 +0200)
Problem:    Vim9: Compiling can break when using a lambda inside :def.
Solution:   Do not keep a pointer to the dfunc_T for longer time.

src/version.c
src/vim9.h
src/vim9compile.c

index 549bf3bed490b7ba4bfeb10ade76843d893bb8df..58180acc4b35d5fe9dd8c98f21a4844ac98d7202 100644 (file)
@@ -738,6 +738,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    488,
 /**/
     487,
 /**/
index 7b95c377ef1e66d5185da916fc1f61b3e8183a93..a414caa63afbada638dd667661a451bc1f464709 100644 (file)
@@ -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
index c7f50326444c3a4a78ab6294d432812955314448..3c3f5a1635b5b270cf21026ba85bd3edc66a3b91 100644 (file)
@@ -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);