]> granicus.if.org Git - vim/commitdiff
patch 8.1.0475: memory not freed on exit when quit in autocmd v8.1.0475
authorBram Moolenaar <Bram@vim.org>
Sun, 14 Oct 2018 19:41:01 +0000 (21:41 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 14 Oct 2018 19:41:01 +0000 (21:41 +0200)
Problem:    Memory not freed on exit when quit in autocmd.
Solution:   Remember funccal stack when executing autocmd.

src/eval.c
src/ex_cmds2.c
src/fileio.c
src/main.c
src/proto/userfunc.pro
src/structs.h
src/userfunc.c
src/version.c

index 8746d5556340aa627cc6d9c4ddf4be83457540f8..7c462fb6a27cd0205c7574ec5d5b6ee65a2d7431 100644 (file)
@@ -859,9 +859,9 @@ eval_to_string_safe(
     int                use_sandbox)
 {
     char_u     *retval;
-    void       *save_funccalp;
+    funccal_entry_T funccal_entry;
 
-    save_funccalp = save_funccal();
+    save_funccal(&funccal_entry);
     if (use_sandbox)
        ++sandbox;
     ++textlock;
@@ -869,7 +869,7 @@ eval_to_string_safe(
     if (use_sandbox)
        --sandbox;
     --textlock;
-    restore_funccal(save_funccalp);
+    restore_funccal();
     return retval;
 }
 
@@ -8532,7 +8532,7 @@ read_viminfo_varlist(vir_T *virp, int writing)
     char_u     *tab;
     int                type = VAR_NUMBER;
     typval_T   tv;
-    void       *save_funccal;
+    funccal_entry_T funccal_entry;
 
     if (!writing && (find_viminfo_parameter('!') != NULL))
     {
@@ -8581,9 +8581,9 @@ read_viminfo_varlist(vir_T *virp, int writing)
                }
 
                /* when in a function use global variables */
-               save_funccal = clear_current_funccal();
+               save_funccal(&funccal_entry);
                set_var(virp->vir_line + 1, &tv, FALSE);
-               restore_current_funccal(save_funccal);
+               restore_funccal();
 
                if (tv.v_type == VAR_STRING)
                    vim_free(tv.vval.v_string);
index 032ebe93b9c1666a1dc8da4414b94c8fb56d2e6c..9a23f82055b703643bfe3bb5c72edd1723a1dd15 100644 (file)
@@ -4344,7 +4344,7 @@ do_source(
 #ifdef FEAT_EVAL
     sctx_T                 save_current_sctx;
     static scid_T          last_current_SID = 0;
-    void                   *save_funccalp;
+    funccal_entry_T        funccalp_entry;
     int                            save_debug_break_level = debug_break_level;
     scriptitem_T           *si = NULL;
 # ifdef UNIX
@@ -4506,7 +4506,7 @@ do_source(
 
     /* Don't use local function variables, if called from a function.
      * Also starts profiling timer for nested script. */
-    save_funccalp = save_funccal();
+    save_funccal(&funccalp_entry);
 
     /*
      * Check if this script was sourced before to finds its SID.
@@ -4665,7 +4665,7 @@ do_source(
 #ifdef FEAT_EVAL
 almosttheend:
     current_sctx = save_current_sctx;
-    restore_funccal(save_funccalp);
+    restore_funccal();
 # ifdef FEAT_PROFILE
     if (do_profiling == PROF_YES)
        prof_child_exit(&wait_start);           /* leaving a child now */
index 4380067fd525e1862d00f79ef3c16e9b67025bc0..afc5157d9d1ede6ffbcc44062cc77ae1c902cc93 100644 (file)
@@ -9400,7 +9400,7 @@ apply_autocmds_group(
     AutoPat    *ap;
 #ifdef FEAT_EVAL
     sctx_T     save_current_sctx;
-    void       *save_funccalp;
+    funccal_entry_T funccal_entry;
     char_u     *save_cmdarg;
     long       save_cmdbang;
 #endif
@@ -9615,8 +9615,8 @@ apply_autocmds_group(
        prof_child_enter(&wait_time); /* doesn't count for the caller itself */
 # endif
 
-    /* Don't use local function variables, if called from a function */
-    save_funccalp = save_funccal();
+    // Don't use local function variables, if called from a function.
+    save_funccal(&funccal_entry);
 #endif
 
     /*
@@ -9713,7 +9713,7 @@ apply_autocmds_group(
     autocmd_match = save_autocmd_match;
 #ifdef FEAT_EVAL
     current_sctx = save_current_sctx;
-    restore_funccal(save_funccalp);
+    restore_funccal();
 # ifdef FEAT_PROFILE
     if (do_profiling == PROF_YES)
        prof_child_exit(&wait_time);
index 5cfec349982a88e603cf46e081ef105264482b53..d4ff370550f0629ebb078d981054669ed126b6d2 100644 (file)
@@ -1717,7 +1717,7 @@ get_number_arg(
 }
 
 /*
- * Check for: [r][e][g][vi|vim|view][diff][ex[im]]
+ * Check for: [r][e][g][vi|vim|view][diff][ex[im]]  (sort of)
  * If the executable name starts with "r" we disable shell commands.
  * If the next character is "e" we run in Easy mode.
  * If the next character is "g" we run the GUI version.
@@ -1788,7 +1788,7 @@ parse_command_name(mparm_T *parmp)
     else if (STRNICMP(initstr, "vim", 3) == 0)
        initstr += 3;
 
-    /* Catch "[r][g]vimdiff" and "[r][g]viewdiff". */
+    // Catch "[r][g]vimdiff" and "[r][g]viewdiff".
     if (STRICMP(initstr, "diff") == 0)
     {
 #ifdef FEAT_DIFF
@@ -1800,13 +1800,15 @@ parse_command_name(mparm_T *parmp)
 #endif
     }
 
+    // Checking for "ex" here may catch some weir names, such as "vimex" or
+    // "viewex", we assume the user knows that.
     if (STRNICMP(initstr, "ex", 2) == 0)
     {
        if (STRNICMP(initstr + 2, "im", 2) == 0)
            exmode_active = EXMODE_VIM;
        else
            exmode_active = EXMODE_NORMAL;
-       change_compatible(TRUE);        /* set 'compatible' */
+       change_compatible(TRUE);        // set 'compatible'
     }
 }
 
@@ -4188,12 +4190,16 @@ eval_client_expr_to_string(char_u *expr)
     char_u     *res;
     int                save_dbl = debug_break_level;
     int                save_ro = redir_off;
-    void       *fc = NULL;
+    funccal_entry_T funccal_entry;
+    int                did_save_funccal = FALSE;
 
     /* Evaluate the expression at the toplevel, don't use variables local to
      * the calling function. Except when in debug mode. */
     if (!debug_mode)
-       fc = clear_current_funccal();
+    {
+       save_funccal(&funccal_entry);
+       did_save_funccal = TRUE;
+    }
 
      /* Disable debugging, otherwise Vim hangs, waiting for "cont" to be
       * typed. */
@@ -4210,8 +4216,8 @@ eval_client_expr_to_string(char_u *expr)
     --emsg_silent;
     if (emsg_silent < 0)
        emsg_silent = 0;
-    if (fc != NULL)
-       restore_current_funccal(fc);
+    if (did_save_funccal)
+       restore_funccal();
 
     /* A client can tell us to redraw, but not to display the cursor, so do
      * that here. */
index 3149ec50a23ea8ec58fbfcacc61383690fe4a07f..ac9bdc00662b5db12bb1449f1defc4119794c9d0 100644 (file)
@@ -39,15 +39,13 @@ linenr_T *func_breakpoint(void *cookie);
 int *func_dbg_tick(void *cookie);
 int func_level(void *cookie);
 int current_func_returned(void);
-void *save_funccal(void);
-void restore_funccal(void *vfc);
+void save_funccal(funccal_entry_T *entry);
+void restore_funccal(void);
 int free_unref_funccal(int copyID, int testing);
 hashtab_T *get_funccal_local_ht(void);
 dictitem_T *get_funccal_local_var(void);
 hashtab_T *get_funccal_args_ht(void);
 dictitem_T *get_funccal_args_var(void);
-void *clear_current_funccal(void);
-void restore_current_funccal(void *f);
 void list_func_vars(int *first);
 dict_T *get_current_funccal_dict(hashtab_T *ht);
 hashitem_T *find_hi_in_scoped_ht(char_u *name, hashtab_T **pht);
index ad03cd4776ebfc46baca20ea420076b0bfa2ba8b..ebd94c36191887ecc11f11df8926161284faad0c 100644 (file)
@@ -1354,7 +1354,7 @@ typedef struct
     int                uf_cleared;     /* func_clear() was already called */
     garray_T   uf_args;        /* arguments */
     garray_T   uf_lines;       /* function lines */
-#ifdef FEAT_PROFILE
+# ifdef FEAT_PROFILE
     int                uf_profiling;   /* TRUE when func is being profiled */
     int                uf_prof_initialized;
     /* profiling the function as a whole */
@@ -1371,7 +1371,7 @@ typedef struct
     proftime_T uf_tml_wait;    /* start wait time for current line */
     int                uf_tml_idx;     /* index of line being timed; -1 if none */
     int                uf_tml_execed;  /* line being timed was executed */
-#endif
+# endif
     sctx_T     uf_script_ctx;  /* SCTX where function was defined,
                                   used for s: variables */
     int                uf_refcount;    /* reference count, see func_name_refcount() */
@@ -1429,6 +1429,12 @@ typedef struct
     dictitem_T *fd_di;         /* Dictionary item used */
 } funcdict_T;
 
+typedef struct funccal_entry funccal_entry_T;
+struct funccal_entry {
+    void           *top_funccal;
+    funccal_entry_T *next;
+};
+
 #else
 /* dummy typedefs for function prototypes */
 typedef struct
index f6e16fefd43b1ce4723483dfbd63ebccc5b3d7bf..ec239c7710d756b79b75587952ab8f65845da8cc 100644 (file)
@@ -1175,6 +1175,33 @@ func_name_refcount(char_u *name)
     return isdigit(*name) || *name == '<';
 }
 
+static funccal_entry_T *funccal_stack = NULL;
+
+/*
+ * Save the current function call pointer, and set it to NULL.
+ * Used when executing autocommands and for ":source".
+ */
+    void
+save_funccal(funccal_entry_T *entry)
+{
+    entry->top_funccal = current_funccal;
+    entry->next = funccal_stack;
+    funccal_stack = entry;
+    current_funccal = NULL;
+}
+
+    void
+restore_funccal(void)
+{
+    if (funccal_stack == NULL)
+       IEMSG("INTERNAL: restore_funccal()");
+    else
+    {
+       current_funccal = funccal_stack->top_funccal;
+       funccal_stack = funccal_stack->next;
+    }
+}
+
 #if defined(EXITFREE) || defined(PROTO)
     void
 free_all_functions(void)
@@ -1185,11 +1212,13 @@ free_all_functions(void)
     long_u     todo = 1;
     long_u     used;
 
-    /* Clean up the call stack. */
+    /* Clean up the current_funccal chain and the funccal stack. */
     while (current_funccal != NULL)
     {
        clear_tv(current_funccal->rettv);
        cleanup_function_call(current_funccal);
+       if (current_funccal == NULL && funccal_stack != NULL)
+           restore_funccal();
     }
 
     /* First clear what the functions contain.  Since this may lower the
@@ -3578,27 +3607,6 @@ current_func_returned(void)
     return current_funccal->returned;
 }
 
-/*
- * Save the current function call pointer, and set it to NULL.
- * Used when executing autocommands and for ":source".
- */
-    void *
-save_funccal(void)
-{
-    funccall_T *fc = current_funccal;
-
-    current_funccal = NULL;
-    return (void *)fc;
-}
-
-    void
-restore_funccal(void *vfc)
-{
-    funccall_T *fc = (funccall_T *)vfc;
-
-    current_funccal = fc;
-}
-
     int
 free_unref_funccal(int copyID, int testing)
 {
@@ -3701,25 +3709,6 @@ get_funccal_args_var()
     return &get_funccal()->l_avars_var;
 }
 
-/*
- * Clear the current_funccal and return the old value.
- * Caller is expected to invoke restore_current_funccal().
- */
-    void *
-clear_current_funccal()
-{
-    funccall_T *f = current_funccal;
-
-    current_funccal = NULL;
-    return f;
-}
-
-    void
-restore_current_funccal(void *f)
-{
-    current_funccal = f;
-}
-
 /*
  * List function variables, if there is a function.
  */
index 519003036f985c5d1918bcad71d328ee2f53c5eb..4523c71f79fe84cb67de9c9e9a43b44e9650a3f5 100644 (file)
@@ -792,6 +792,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    475,
 /**/
     474,
 /**/