]> granicus.if.org Git - vim/commitdiff
patch 8.1.0439: recursive use of getcmdline() still not protected v8.1.0439
authorBram Moolenaar <Bram@vim.org>
Sun, 30 Sep 2018 15:11:48 +0000 (17:11 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 30 Sep 2018 15:11:48 +0000 (17:11 +0200)
Problem:    Recursive use of getcmdline() still not protected.
Solution:   Instead of saving the command buffer when making a call which may
            cause recursiveness, save the buffer when actually being called
            recursively.

src/ex_getln.c
src/getchar.c
src/main.c
src/proto/ex_getln.pro
src/version.c

index 02c3e3009544d0b6d31ad20bd6dfd658dacf14f7..e1642d1d480a08bc8f5c1e70f0d0df95d06193a0 100644 (file)
@@ -44,13 +44,12 @@ struct cmdline_info
 # endif
 };
 
-/* The current cmdline_info.  It is initialized in getcmdline() and after that
- * used by other functions.  When invoking getcmdline() recursively it needs
- * to be saved with save_cmdline() and restored with restore_cmdline().
- * TODO: make it local to getcmdline() and pass it around. */
+// The current cmdline_info.  It is initialized in getcmdline() and after that
+// used by other functions.  When invoking getcmdline() recursively it needs
+// to be saved with save_cmdline() and restored with restore_cmdline().
 static struct cmdline_info ccline;
 
-static int     cmd_showtail;           /* Only show path tail in lists ? */
+static int     cmd_showtail;   /* Only show path tail in lists ? */
 
 #ifdef FEAT_EVAL
 static int     new_cmdpos;     /* position set by set_cmdline_pos() */
@@ -91,6 +90,7 @@ static int    cmd_hkmap = 0;  /* Hebrew mapping during command line */
 static int     cmd_fkmap = 0;  /* Farsi mapping during command line */
 #endif
 
+static char_u  *getcmdline_int(int firstc, long count, int indent, int init_ccline);
 static int     cmdline_charsize(int idx);
 static void    set_cmdspos(void);
 static void    set_cmdspos_cursor(void);
@@ -463,7 +463,6 @@ may_do_incsearch_highlighting(
     int                skiplen, patlen;
     int                found;  // do_search() result
     pos_T      end_pos;
-    struct cmdline_info        save_ccline;
 #ifdef FEAT_RELTIME
     proftime_T tm;
 #endif
@@ -601,9 +600,7 @@ may_do_incsearch_highlighting(
     if (p_ru && curwin->w_status_height > 0)
        curwin->w_redr_status = TRUE;
 
-    save_cmdline(&save_ccline);
     update_screen(SOME_VALID);
-    restore_cmdline(&save_ccline);
     restore_last_search_pattern();
 
     // Leave it at the end to make CTRL-R CTRL-W work.  But not when beyond the
@@ -800,8 +797,18 @@ may_add_char_to_search(int firstc, int *c, incsearch_state_T *is_state)
     char_u *
 getcmdline(
     int                firstc,
-    long       count UNUSED,   /* only used for incremental search */
-    int                indent)         /* indent for inside conditionals */
+    long       count,          // only used for incremental search
+    int                indent)         // indent for inside conditionals
+{
+    return getcmdline_int(firstc, count, indent, TRUE);
+}
+
+    static char_u *
+getcmdline_int(
+    int                firstc,
+    long       count UNUSED,   // only used for incremental search
+    int                indent,         // indent for inside conditionals
+    int                init_ccline)    // clear ccline first
 {
     int                c;
     int                i;
@@ -832,14 +839,20 @@ getcmdline(
 #endif
     expand_T   xpc;
     long       *b_im_ptr = NULL;
-#if defined(FEAT_WILDMENU) || defined(FEAT_EVAL)
-    /* Everything that may work recursively should save and restore the
-     * current command line in save_ccline.  That includes update_screen(), a
-     * custom status line may invoke ":normal". */
     struct cmdline_info save_ccline;
-#endif
+    int                did_save_ccline = FALSE;
     int                cmdline_type;
 
+    if (ccline.cmdbuff != NULL)
+    {
+       // Being called recursively.  Since ccline is global, we need to save
+       // the current buffer and restore it when returning.
+       save_cmdline(&save_ccline);
+       did_save_ccline = TRUE;
+    }
+    if (init_ccline)
+       vim_memset(&ccline, 0, sizeof(struct cmdline_info));
+
 #ifdef FEAT_EVAL
     if (firstc == -1)
     {
@@ -868,7 +881,7 @@ getcmdline(
     /* alloc initial ccline.cmdbuff */
     alloc_cmdbuff(exmode_active ? 250 : indent + 1);
     if (ccline.cmdbuff == NULL)
-       return NULL;                        /* out of memory */
+       goto theend;    // out of memory
     ccline.cmdlen = ccline.cmdpos = 0;
     ccline.cmdbuff[0] = NUL;
     sb_text_start_cmdline();
@@ -1125,9 +1138,7 @@ getcmdline(
                    p_ls = save_p_ls;
                    p_wmh = save_p_wmh;
                    last_status(FALSE);
-                   save_cmdline(&save_ccline);
                    update_screen(VALID);       /* redraw the screen NOW */
-                   restore_cmdline(&save_ccline);
                    redrawcmd();
                    save_p_ls = -1;
                }
@@ -1333,19 +1344,15 @@ getcmdline(
                else
                    new_cmdpos = ccline.cmdpos;
 
-               save_cmdline(&save_ccline);
                c = get_expr_register();
-               restore_cmdline(&save_ccline);
                if (c == '=')
                {
                    /* Need to save and restore ccline.  And set "textlock"
                     * to avoid nasty things like going to another buffer when
                     * evaluating an expression. */
-                   save_cmdline(&save_ccline);
                    ++textlock;
                    p = get_expr_line();
                    --textlock;
-                   restore_cmdline(&save_ccline);
 
                    if (p != NULL)
                    {
@@ -1812,11 +1819,7 @@ getcmdline(
                        c = ESC;
                    }
                    else
-                   {
-                       save_cmdline(&save_ccline);
                        c = get_expr_register();
-                       restore_cmdline(&save_ccline);
-                   }
                }
 #endif
                if (c != ESC)       /* use ESC to cancel inserting register */
@@ -2187,7 +2190,7 @@ getcmdline(
                    int         len;
                    int         old_firstc;
 
-                   vim_free(ccline.cmdbuff);
+                   VIM_CLEAR(ccline.cmdbuff);
                    xpc.xp_context = EXPAND_NOTHING;
                    if (hiscnt == hislen)
                        p = lookfor;    /* back to the old one */
@@ -2486,11 +2489,14 @@ returncmd:
 #endif
     sb_text_end_cmdline();
 
+theend:
     {
        char_u *p = ccline.cmdbuff;
 
-       /* Make ccline empty, getcmdline() may try to use it. */
-       ccline.cmdbuff = NULL;
+       if (did_save_ccline)
+           restore_cmdline(&save_ccline);
+       else
+           ccline.cmdbuff = NULL;
        return p;
     }
 }
@@ -2512,10 +2518,18 @@ getcmdline_prompt(
 {
     char_u             *s;
     struct cmdline_info        save_ccline;
+    int                        did_save_ccline = FALSE;
     int                        msg_col_save = msg_col;
     int                        msg_silent_save = msg_silent;
 
-    save_cmdline(&save_ccline);
+    if (ccline.cmdbuff != NULL)
+    {
+       // Save the values of the current cmdline and restore them below.
+       save_cmdline(&save_ccline);
+       did_save_ccline = TRUE;
+    }
+
+    vim_memset(&ccline, 0, sizeof(struct cmdline_info));
     ccline.cmdprompt = prompt;
     ccline.cmdattr = attr;
 # ifdef FEAT_EVAL
@@ -2524,8 +2538,11 @@ getcmdline_prompt(
     ccline.input_fn = (firstc == '@');
 # endif
     msg_silent = 0;
-    s = getcmdline(firstc, 1L, 0);
-    restore_cmdline(&save_ccline);
+    s = getcmdline_int(firstc, 1L, 0, FALSE);
+
+    if (did_save_ccline)
+       restore_cmdline(&save_ccline);
+
     msg_silent = msg_silent_save;
     /* Restore msg_col, the prompt from input() may have changed it.
      * But only if called recursively and the commandline is therefore being
@@ -3121,7 +3138,6 @@ redrawcmd_preedit(void)
 /*
  * Allocate a new command line buffer.
  * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
- * Returns the new value of ccline.cmdbuff and ccline.cmdbufflen.
  */
     static void
 alloc_cmdbuff(int len)
@@ -3542,9 +3558,7 @@ save_cmdline(struct cmdline_info *ccp)
     }
     *ccp = prev_ccline;
     prev_ccline = ccline;
-    ccline.cmdbuff = NULL;
-    ccline.cmdprompt = NULL;
-    ccline.xpc = NULL;
+    ccline.cmdbuff = NULL;  // signal that ccline is not in use
 }
 
 /*
@@ -3557,37 +3571,6 @@ restore_cmdline(struct cmdline_info *ccp)
     prev_ccline = *ccp;
 }
 
-#if defined(FEAT_EVAL) || defined(PROTO)
-/*
- * Save the command line into allocated memory.  Returns a pointer to be
- * passed to restore_cmdline_alloc() later.
- * Returns NULL when failed.
- */
-    char_u *
-save_cmdline_alloc(void)
-{
-    struct cmdline_info *p;
-
-    p = (struct cmdline_info *)alloc((unsigned)sizeof(struct cmdline_info));
-    if (p != NULL)
-       save_cmdline(p);
-    return (char_u *)p;
-}
-
-/*
- * Restore the command line from the return value of save_cmdline_alloc().
- */
-    void
-restore_cmdline_alloc(char_u *p)
-{
-    if (p != NULL)
-    {
-       restore_cmdline((struct cmdline_info *)p);
-       vim_free(p);
-    }
-}
-#endif
-
 /*
  * Paste a yank register into the command line.
  * Used by CTRL-R command in command-line mode.
@@ -3606,7 +3589,6 @@ cmdline_paste(
     char_u             *arg;
     char_u             *p;
     int                        allocated;
-    struct cmdline_info        save_ccline;
 
     /* check for valid regname; also accept special characters for CTRL-R in
      * the command line */
@@ -3625,13 +3607,11 @@ cmdline_paste(
     regname = may_get_selection(regname);
 #endif
 
-    /* Need to save and restore ccline.  And set "textlock" to avoid nasty
-     * things like going to another buffer when evaluating an expression. */
-    save_cmdline(&save_ccline);
+    // Need to  set "textlock" to avoid nasty things like going to another
+    // buffer when evaluating an expression.
     ++textlock;
     i = get_spec_reg(regname, &arg, &allocated, TRUE);
     --textlock;
-    restore_cmdline(&save_ccline);
 
     if (i)
     {
@@ -5601,7 +5581,6 @@ call_user_expand_func(
     sctx_T     save_current_sctx = current_sctx;
     char_u     *pat = NULL;
     void       *ret;
-    struct cmdline_info            save_ccline;
 
     if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
        return NULL;
@@ -5624,15 +5603,10 @@ call_user_expand_func(
     args[2].vval.v_number = xp->xp_col;
     args[3].v_type = VAR_UNKNOWN;
 
-    /* Save the cmdline, we don't know what the function may do. */
-    save_ccline = ccline;
-    ccline.cmdbuff = NULL;
-    ccline.cmdprompt = NULL;
     current_sctx = xp->xp_script_ctx;
 
     ret = user_expand_func(xp->xp_arg, 3, args);
 
-    ccline = save_ccline;
     current_sctx = save_current_sctx;
     if (ccline.cmdbuff != NULL)
        ccline.cmdbuff[ccline.cmdlen] = keep;
@@ -6481,7 +6455,7 @@ remove_key_from_history(void)
 
 #if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
 /*
- * Get pointer to the command line info to use. cmdline_paste() may clear
+ * Get pointer to the command line info to use. save_ccline() may clear
  * ccline and put the previous value in prev_ccline.
  */
     static struct cmdline_info *
@@ -7072,6 +7046,12 @@ finish_viminfo_history(vir_T *virp)
     }
 }
 
+    void
+cmdline_init(void)
+{
+    vim_memset(&ccline, 0, sizeof(struct cmdline_info));
+}
+
 /*
  * Write history to viminfo file in "fp".
  * When "merge" is TRUE merge history lines with a previously read viminfo
@@ -7238,7 +7218,6 @@ cmd_gchar(int offset)
     static int
 open_cmdwin(void)
 {
-    struct cmdline_info        save_ccline;
     bufref_T           old_curbuf;
     win_T              *old_curwin = curwin;
     bufref_T           bufref;
@@ -7355,9 +7334,6 @@ open_cmdwin(void)
     invalidate_botline();
     redraw_later(SOME_VALID);
 
-    /* Save the command line info, can be used recursively. */
-    save_cmdline(&save_ccline);
-
     /* No Ex mode here! */
     exmode_active = 0;
 
@@ -7394,10 +7370,7 @@ open_cmdwin(void)
     KeyTyped = save_KeyTyped;
 # endif
 
-    /* Restore the command line info. */
-    restore_cmdline(&save_ccline);
     cmdwin_type = 0;
-
     exmode_active = save_exmode;
 
     /* Safety check: The old window or buffer was deleted: It's a bug when
index cc8b344e11ad8aadc9003411b986e5dfeee7e0ce..6331cd76e332d9715aa7d4686ebc59b18fcafb5b 100644 (file)
@@ -4666,7 +4666,6 @@ eval_map_expr(
     char_u     *res;
     char_u     *p;
     char_u     *expr;
-    char_u     *save_cmd;
     pos_T      save_cursor;
     int                save_msg_col;
     int                save_msg_row;
@@ -4678,13 +4677,6 @@ eval_map_expr(
        return NULL;
     vim_unescape_csi(expr);
 
-    save_cmd = save_cmdline_alloc();
-    if (save_cmd == NULL)
-    {
-       vim_free(expr);
-       return NULL;
-    }
-
     /* Forbid changing text or using ":normal" to avoid most of the bad side
      * effects.  Also restore the cursor position. */
     ++textlock;
@@ -4700,7 +4692,6 @@ eval_map_expr(
     msg_col = save_msg_col;
     msg_row = save_msg_row;
 
-    restore_cmdline_alloc(save_cmd);
     vim_free(expr);
 
     if (p == NULL)
index 8ee165003da499b34f0a1a1b781597265e03faec..d9cd6f9d0647f3fd2e0195817651c08e0ea327b0 100644 (file)
@@ -929,6 +929,7 @@ vim_main2(void)
     void
 common_init(mparm_T *paramp)
 {
+    cmdline_init();
 
 #ifdef FEAT_MBYTE
     (void)mb_init();   /* init mb_bytelen_tab[] to ones */
index 6f8290423517fbfb96fcbbdf3686f268142fd92e..c7386a4184545c7ae87b37fe024ea46a3c551af5 100644 (file)
@@ -15,8 +15,6 @@ void free_cmdline_buf(void);
 void putcmdline(int c, int shift);
 void unputcmdline(void);
 int put_on_cmdline(char_u *str, int len, int redraw);
-char_u *save_cmdline_alloc(void);
-void restore_cmdline_alloc(char_u *p);
 void cmdline_paste_str(char_u *s, int literally);
 void redrawcmdline(void);
 void redrawcmdline_ex(int do_compute_cmdrow);
@@ -54,6 +52,7 @@ void prepare_viminfo_history(int asklen, int writing);
 int read_viminfo_history(vir_T *virp, int writing);
 void handle_viminfo_history(garray_T *values, int writing);
 void finish_viminfo_history(vir_T *virp);
+void cmdline_init(void);
 void write_viminfo_history(FILE *fp, int merge);
 void cmd_pchar(int c, int offset);
 int cmd_gchar(int offset);
index f4e0508d65ce3250995e614d75d70245636dd0f3..1f14030030ce7877ba8346b273ac08f6fc08e0d8 100644 (file)
@@ -794,6 +794,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    439,
 /**/
     438,
 /**/