# HG changeset patch # User Christian Brabandt # Date 1538320508 -7200 # Node ID 3b72808fbb0d701245f7f273325feed8d4c75eb5 # Parent 5889d7548ac604ce1f3c869c09e9e176c2340c92 patch 8.1.0439: recursive use of getcmdline() still not protected commit https://github.com/vim/vim/commit/438d176e35c16d56ff3bb7a80300197ce5a30c4f Author: Bram Moolenaar Date: Sun Sep 30 17:11:48 2018 +0200 patch 8.1.0439: recursive use of getcmdline() still not protected 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. diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -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 mapp 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 * 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 diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -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) diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -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 */ diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro --- a/src/proto/ex_getln.pro +++ b/src/proto/ex_getln.pro @@ -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 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); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -795,6 +795,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 439, +/**/ 438, /**/ 437,