0
0
mirror of https://github.com/vim/vim.git synced 2025-07-25 10:54:51 -04:00

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.
This commit is contained in:
Bram Moolenaar 2018-09-30 17:11:48 +02:00
parent b434ae2a1f
commit 438d176e35
5 changed files with 63 additions and 97 deletions

View File

@ -44,13 +44,12 @@ struct cmdline_info
# endif # endif
}; };
/* The current cmdline_info. It is initialized in getcmdline() and after that // The current cmdline_info. It is initialized in getcmdline() and after that
* used by other functions. When invoking getcmdline() recursively it needs // used by other functions. When invoking getcmdline() recursively it needs
* to be saved with save_cmdline() and restored with restore_cmdline(). // to be saved with save_cmdline() and restored with restore_cmdline().
* TODO: make it local to getcmdline() and pass it around. */
static struct cmdline_info ccline; 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 #ifdef FEAT_EVAL
static int new_cmdpos; /* position set by set_cmdline_pos() */ 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 */ static int cmd_fkmap = 0; /* Farsi mapping during command line */
#endif #endif
static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline);
static int cmdline_charsize(int idx); static int cmdline_charsize(int idx);
static void set_cmdspos(void); static void set_cmdspos(void);
static void set_cmdspos_cursor(void); static void set_cmdspos_cursor(void);
@ -463,7 +463,6 @@ may_do_incsearch_highlighting(
int skiplen, patlen; int skiplen, patlen;
int found; // do_search() result int found; // do_search() result
pos_T end_pos; pos_T end_pos;
struct cmdline_info save_ccline;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
proftime_T tm; proftime_T tm;
#endif #endif
@ -601,9 +600,7 @@ may_do_incsearch_highlighting(
if (p_ru && curwin->w_status_height > 0) if (p_ru && curwin->w_status_height > 0)
curwin->w_redr_status = TRUE; curwin->w_redr_status = TRUE;
save_cmdline(&save_ccline);
update_screen(SOME_VALID); update_screen(SOME_VALID);
restore_cmdline(&save_ccline);
restore_last_search_pattern(); restore_last_search_pattern();
// Leave it at the end to make CTRL-R CTRL-W work. But not when beyond the // 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 * char_u *
getcmdline( getcmdline(
int firstc, int firstc,
long count UNUSED, /* only used for incremental search */ long count, // only used for incremental search
int indent) /* indent for inside conditionals */ 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 c;
int i; int i;
@ -832,14 +839,20 @@ getcmdline(
#endif #endif
expand_T xpc; expand_T xpc;
long *b_im_ptr = NULL; 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; struct cmdline_info save_ccline;
#endif int did_save_ccline = FALSE;
int cmdline_type; 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 #ifdef FEAT_EVAL
if (firstc == -1) if (firstc == -1)
{ {
@ -868,7 +881,7 @@ getcmdline(
/* alloc initial ccline.cmdbuff */ /* alloc initial ccline.cmdbuff */
alloc_cmdbuff(exmode_active ? 250 : indent + 1); alloc_cmdbuff(exmode_active ? 250 : indent + 1);
if (ccline.cmdbuff == NULL) if (ccline.cmdbuff == NULL)
return NULL; /* out of memory */ goto theend; // out of memory
ccline.cmdlen = ccline.cmdpos = 0; ccline.cmdlen = ccline.cmdpos = 0;
ccline.cmdbuff[0] = NUL; ccline.cmdbuff[0] = NUL;
sb_text_start_cmdline(); sb_text_start_cmdline();
@ -1125,9 +1138,7 @@ getcmdline(
p_ls = save_p_ls; p_ls = save_p_ls;
p_wmh = save_p_wmh; p_wmh = save_p_wmh;
last_status(FALSE); last_status(FALSE);
save_cmdline(&save_ccline);
update_screen(VALID); /* redraw the screen NOW */ update_screen(VALID); /* redraw the screen NOW */
restore_cmdline(&save_ccline);
redrawcmd(); redrawcmd();
save_p_ls = -1; save_p_ls = -1;
} }
@ -1333,19 +1344,15 @@ getcmdline(
else else
new_cmdpos = ccline.cmdpos; new_cmdpos = ccline.cmdpos;
save_cmdline(&save_ccline);
c = get_expr_register(); c = get_expr_register();
restore_cmdline(&save_ccline);
if (c == '=') if (c == '=')
{ {
/* Need to save and restore ccline. And set "textlock" /* Need to save and restore ccline. And set "textlock"
* to avoid nasty things like going to another buffer when * to avoid nasty things like going to another buffer when
* evaluating an expression. */ * evaluating an expression. */
save_cmdline(&save_ccline);
++textlock; ++textlock;
p = get_expr_line(); p = get_expr_line();
--textlock; --textlock;
restore_cmdline(&save_ccline);
if (p != NULL) if (p != NULL)
{ {
@ -1812,11 +1819,7 @@ getcmdline(
c = ESC; c = ESC;
} }
else else
{
save_cmdline(&save_ccline);
c = get_expr_register(); c = get_expr_register();
restore_cmdline(&save_ccline);
}
} }
#endif #endif
if (c != ESC) /* use ESC to cancel inserting register */ if (c != ESC) /* use ESC to cancel inserting register */
@ -2187,7 +2190,7 @@ getcmdline(
int len; int len;
int old_firstc; int old_firstc;
vim_free(ccline.cmdbuff); VIM_CLEAR(ccline.cmdbuff);
xpc.xp_context = EXPAND_NOTHING; xpc.xp_context = EXPAND_NOTHING;
if (hiscnt == hislen) if (hiscnt == hislen)
p = lookfor; /* back to the old one */ p = lookfor; /* back to the old one */
@ -2486,11 +2489,14 @@ returncmd:
#endif #endif
sb_text_end_cmdline(); sb_text_end_cmdline();
theend:
{ {
char_u *p = ccline.cmdbuff; char_u *p = ccline.cmdbuff;
/* Make ccline empty, getcmdline() may try to use it. */ if (did_save_ccline)
ccline.cmdbuff = NULL; restore_cmdline(&save_ccline);
else
ccline.cmdbuff = NULL;
return p; return p;
} }
} }
@ -2512,10 +2518,18 @@ getcmdline_prompt(
{ {
char_u *s; char_u *s;
struct cmdline_info save_ccline; struct cmdline_info save_ccline;
int did_save_ccline = FALSE;
int msg_col_save = msg_col; int msg_col_save = msg_col;
int msg_silent_save = msg_silent; 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.cmdprompt = prompt;
ccline.cmdattr = attr; ccline.cmdattr = attr;
# ifdef FEAT_EVAL # ifdef FEAT_EVAL
@ -2524,8 +2538,11 @@ getcmdline_prompt(
ccline.input_fn = (firstc == '@'); ccline.input_fn = (firstc == '@');
# endif # endif
msg_silent = 0; msg_silent = 0;
s = getcmdline(firstc, 1L, 0); s = getcmdline_int(firstc, 1L, 0, FALSE);
restore_cmdline(&save_ccline);
if (did_save_ccline)
restore_cmdline(&save_ccline);
msg_silent = msg_silent_save; msg_silent = msg_silent_save;
/* Restore msg_col, the prompt from input() may have changed it. /* Restore msg_col, the prompt from input() may have changed it.
* But only if called recursively and the commandline is therefore being * But only if called recursively and the commandline is therefore being
@ -3121,7 +3138,6 @@ redrawcmd_preedit(void)
/* /*
* Allocate a new command line buffer. * Allocate a new command line buffer.
* Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen. * Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
* Returns the new value of ccline.cmdbuff and ccline.cmdbufflen.
*/ */
static void static void
alloc_cmdbuff(int len) alloc_cmdbuff(int len)
@ -3542,9 +3558,7 @@ save_cmdline(struct cmdline_info *ccp)
} }
*ccp = prev_ccline; *ccp = prev_ccline;
prev_ccline = ccline; prev_ccline = ccline;
ccline.cmdbuff = NULL; ccline.cmdbuff = NULL; // signal that ccline is not in use
ccline.cmdprompt = NULL;
ccline.xpc = NULL;
} }
/* /*
@ -3557,37 +3571,6 @@ restore_cmdline(struct cmdline_info *ccp)
prev_ccline = *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. * Paste a yank register into the command line.
* Used by CTRL-R command in command-line mode. * Used by CTRL-R command in command-line mode.
@ -3606,7 +3589,6 @@ cmdline_paste(
char_u *arg; char_u *arg;
char_u *p; char_u *p;
int allocated; int allocated;
struct cmdline_info save_ccline;
/* check for valid regname; also accept special characters for CTRL-R in /* check for valid regname; also accept special characters for CTRL-R in
* the command line */ * the command line */
@ -3625,13 +3607,11 @@ cmdline_paste(
regname = may_get_selection(regname); regname = may_get_selection(regname);
#endif #endif
/* Need to save and restore ccline. And set "textlock" to avoid nasty // Need to set "textlock" to avoid nasty things like going to another
* things like going to another buffer when evaluating an expression. */ // buffer when evaluating an expression.
save_cmdline(&save_ccline);
++textlock; ++textlock;
i = get_spec_reg(regname, &arg, &allocated, TRUE); i = get_spec_reg(regname, &arg, &allocated, TRUE);
--textlock; --textlock;
restore_cmdline(&save_ccline);
if (i) if (i)
{ {
@ -5601,7 +5581,6 @@ call_user_expand_func(
sctx_T save_current_sctx = current_sctx; sctx_T save_current_sctx = current_sctx;
char_u *pat = NULL; char_u *pat = NULL;
void *ret; void *ret;
struct cmdline_info save_ccline;
if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
return NULL; return NULL;
@ -5624,15 +5603,10 @@ call_user_expand_func(
args[2].vval.v_number = xp->xp_col; args[2].vval.v_number = xp->xp_col;
args[3].v_type = VAR_UNKNOWN; 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; current_sctx = xp->xp_script_ctx;
ret = user_expand_func(xp->xp_arg, 3, args); ret = user_expand_func(xp->xp_arg, 3, args);
ccline = save_ccline;
current_sctx = save_current_sctx; current_sctx = save_current_sctx;
if (ccline.cmdbuff != NULL) if (ccline.cmdbuff != NULL)
ccline.cmdbuff[ccline.cmdlen] = keep; ccline.cmdbuff[ccline.cmdlen] = keep;
@ -6481,7 +6455,7 @@ remove_key_from_history(void)
#if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO) #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. * ccline and put the previous value in prev_ccline.
*/ */
static struct cmdline_info * 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". * Write history to viminfo file in "fp".
* When "merge" is TRUE merge history lines with a previously read viminfo * When "merge" is TRUE merge history lines with a previously read viminfo
@ -7238,7 +7218,6 @@ cmd_gchar(int offset)
static int static int
open_cmdwin(void) open_cmdwin(void)
{ {
struct cmdline_info save_ccline;
bufref_T old_curbuf; bufref_T old_curbuf;
win_T *old_curwin = curwin; win_T *old_curwin = curwin;
bufref_T bufref; bufref_T bufref;
@ -7355,9 +7334,6 @@ open_cmdwin(void)
invalidate_botline(); invalidate_botline();
redraw_later(SOME_VALID); redraw_later(SOME_VALID);
/* Save the command line info, can be used recursively. */
save_cmdline(&save_ccline);
/* No Ex mode here! */ /* No Ex mode here! */
exmode_active = 0; exmode_active = 0;
@ -7394,10 +7370,7 @@ open_cmdwin(void)
KeyTyped = save_KeyTyped; KeyTyped = save_KeyTyped;
# endif # endif
/* Restore the command line info. */
restore_cmdline(&save_ccline);
cmdwin_type = 0; cmdwin_type = 0;
exmode_active = save_exmode; exmode_active = save_exmode;
/* Safety check: The old window or buffer was deleted: It's a bug when /* Safety check: The old window or buffer was deleted: It's a bug when

View File

@ -4666,7 +4666,6 @@ eval_map_expr(
char_u *res; char_u *res;
char_u *p; char_u *p;
char_u *expr; char_u *expr;
char_u *save_cmd;
pos_T save_cursor; pos_T save_cursor;
int save_msg_col; int save_msg_col;
int save_msg_row; int save_msg_row;
@ -4678,13 +4677,6 @@ eval_map_expr(
return NULL; return NULL;
vim_unescape_csi(expr); 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 /* Forbid changing text or using ":normal" to avoid most of the bad side
* effects. Also restore the cursor position. */ * effects. Also restore the cursor position. */
++textlock; ++textlock;
@ -4700,7 +4692,6 @@ eval_map_expr(
msg_col = save_msg_col; msg_col = save_msg_col;
msg_row = save_msg_row; msg_row = save_msg_row;
restore_cmdline_alloc(save_cmd);
vim_free(expr); vim_free(expr);
if (p == NULL) if (p == NULL)

View File

@ -929,6 +929,7 @@ vim_main2(void)
void void
common_init(mparm_T *paramp) common_init(mparm_T *paramp)
{ {
cmdline_init();
#ifdef FEAT_MBYTE #ifdef FEAT_MBYTE
(void)mb_init(); /* init mb_bytelen_tab[] to ones */ (void)mb_init(); /* init mb_bytelen_tab[] to ones */

View File

@ -15,8 +15,6 @@ void free_cmdline_buf(void);
void putcmdline(int c, int shift); void putcmdline(int c, int shift);
void unputcmdline(void); void unputcmdline(void);
int put_on_cmdline(char_u *str, int len, int redraw); 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 cmdline_paste_str(char_u *s, int literally);
void redrawcmdline(void); void redrawcmdline(void);
void redrawcmdline_ex(int do_compute_cmdrow); 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); int read_viminfo_history(vir_T *virp, int writing);
void handle_viminfo_history(garray_T *values, int writing); void handle_viminfo_history(garray_T *values, int writing);
void finish_viminfo_history(vir_T *virp); void finish_viminfo_history(vir_T *virp);
void cmdline_init(void);
void write_viminfo_history(FILE *fp, int merge); void write_viminfo_history(FILE *fp, int merge);
void cmd_pchar(int c, int offset); void cmd_pchar(int c, int offset);
int cmd_gchar(int offset); int cmd_gchar(int offset);

View File

@ -794,6 +794,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
439,
/**/ /**/
438, 438,
/**/ /**/