Skip to content

Commit 438d176

Browse files
committed
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.
1 parent b434ae2 commit 438d176

5 files changed

Lines changed: 63 additions & 97 deletions

File tree

src/ex_getln.c

Lines changed: 59 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,12 @@ struct cmdline_info
4444
# endif
4545
};
4646

47-
/* The current cmdline_info. It is initialized in getcmdline() and after that
48-
* used by other functions. When invoking getcmdline() recursively it needs
49-
* to be saved with save_cmdline() and restored with restore_cmdline().
50-
* TODO: make it local to getcmdline() and pass it around. */
47+
// The current cmdline_info. It is initialized in getcmdline() and after that
48+
// used by other functions. When invoking getcmdline() recursively it needs
49+
// to be saved with save_cmdline() and restored with restore_cmdline().
5150
static struct cmdline_info ccline;
5251

53-
static int cmd_showtail; /* Only show path tail in lists ? */
52+
static int cmd_showtail; /* Only show path tail in lists ? */
5453

5554
#ifdef FEAT_EVAL
5655
static int new_cmdpos; /* position set by set_cmdline_pos() */
@@ -91,6 +90,7 @@ static int cmd_hkmap = 0; /* Hebrew mapping during command line */
9190
static int cmd_fkmap = 0; /* Farsi mapping during command line */
9291
#endif
9392

93+
static char_u *getcmdline_int(int firstc, long count, int indent, int init_ccline);
9494
static int cmdline_charsize(int idx);
9595
static void set_cmdspos(void);
9696
static void set_cmdspos_cursor(void);
@@ -463,7 +463,6 @@ may_do_incsearch_highlighting(
463463
int skiplen, patlen;
464464
int found; // do_search() result
465465
pos_T end_pos;
466-
struct cmdline_info save_ccline;
467466
#ifdef FEAT_RELTIME
468467
proftime_T tm;
469468
#endif
@@ -601,9 +600,7 @@ may_do_incsearch_highlighting(
601600
if (p_ru && curwin->w_status_height > 0)
602601
curwin->w_redr_status = TRUE;
603602

604-
save_cmdline(&save_ccline);
605603
update_screen(SOME_VALID);
606-
restore_cmdline(&save_ccline);
607604
restore_last_search_pattern();
608605

609606
// 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)
800797
char_u *
801798
getcmdline(
802799
int firstc,
803-
long count UNUSED, /* only used for incremental search */
804-
int indent) /* indent for inside conditionals */
800+
long count, // only used for incremental search
801+
int indent) // indent for inside conditionals
802+
{
803+
return getcmdline_int(firstc, count, indent, TRUE);
804+
}
805+
806+
static char_u *
807+
getcmdline_int(
808+
int firstc,
809+
long count UNUSED, // only used for incremental search
810+
int indent, // indent for inside conditionals
811+
int init_ccline) // clear ccline first
805812
{
806813
int c;
807814
int i;
@@ -832,14 +839,20 @@ getcmdline(
832839
#endif
833840
expand_T xpc;
834841
long *b_im_ptr = NULL;
835-
#if defined(FEAT_WILDMENU) || defined(FEAT_EVAL)
836-
/* Everything that may work recursively should save and restore the
837-
* current command line in save_ccline. That includes update_screen(), a
838-
* custom status line may invoke ":normal". */
839842
struct cmdline_info save_ccline;
840-
#endif
843+
int did_save_ccline = FALSE;
841844
int cmdline_type;
842845

846+
if (ccline.cmdbuff != NULL)
847+
{
848+
// Being called recursively. Since ccline is global, we need to save
849+
// the current buffer and restore it when returning.
850+
save_cmdline(&save_ccline);
851+
did_save_ccline = TRUE;
852+
}
853+
if (init_ccline)
854+
vim_memset(&ccline, 0, sizeof(struct cmdline_info));
855+
843856
#ifdef FEAT_EVAL
844857
if (firstc == -1)
845858
{
@@ -868,7 +881,7 @@ getcmdline(
868881
/* alloc initial ccline.cmdbuff */
869882
alloc_cmdbuff(exmode_active ? 250 : indent + 1);
870883
if (ccline.cmdbuff == NULL)
871-
return NULL; /* out of memory */
884+
goto theend; // out of memory
872885
ccline.cmdlen = ccline.cmdpos = 0;
873886
ccline.cmdbuff[0] = NUL;
874887
sb_text_start_cmdline();
@@ -1125,9 +1138,7 @@ getcmdline(
11251138
p_ls = save_p_ls;
11261139
p_wmh = save_p_wmh;
11271140
last_status(FALSE);
1128-
save_cmdline(&save_ccline);
11291141
update_screen(VALID); /* redraw the screen NOW */
1130-
restore_cmdline(&save_ccline);
11311142
redrawcmd();
11321143
save_p_ls = -1;
11331144
}
@@ -1333,19 +1344,15 @@ getcmdline(
13331344
else
13341345
new_cmdpos = ccline.cmdpos;
13351346

1336-
save_cmdline(&save_ccline);
13371347
c = get_expr_register();
1338-
restore_cmdline(&save_ccline);
13391348
if (c == '=')
13401349
{
13411350
/* Need to save and restore ccline. And set "textlock"
13421351
* to avoid nasty things like going to another buffer when
13431352
* evaluating an expression. */
1344-
save_cmdline(&save_ccline);
13451353
++textlock;
13461354
p = get_expr_line();
13471355
--textlock;
1348-
restore_cmdline(&save_ccline);
13491356

13501357
if (p != NULL)
13511358
{
@@ -1812,11 +1819,7 @@ getcmdline(
18121819
c = ESC;
18131820
}
18141821
else
1815-
{
1816-
save_cmdline(&save_ccline);
18171822
c = get_expr_register();
1818-
restore_cmdline(&save_ccline);
1819-
}
18201823
}
18211824
#endif
18221825
if (c != ESC) /* use ESC to cancel inserting register */
@@ -2187,7 +2190,7 @@ getcmdline(
21872190
int len;
21882191
int old_firstc;
21892192

2190-
vim_free(ccline.cmdbuff);
2193+
VIM_CLEAR(ccline.cmdbuff);
21912194
xpc.xp_context = EXPAND_NOTHING;
21922195
if (hiscnt == hislen)
21932196
p = lookfor; /* back to the old one */
@@ -2486,11 +2489,14 @@ getcmdline(
24862489
#endif
24872490
sb_text_end_cmdline();
24882491

2492+
theend:
24892493
{
24902494
char_u *p = ccline.cmdbuff;
24912495

2492-
/* Make ccline empty, getcmdline() may try to use it. */
2493-
ccline.cmdbuff = NULL;
2496+
if (did_save_ccline)
2497+
restore_cmdline(&save_ccline);
2498+
else
2499+
ccline.cmdbuff = NULL;
24942500
return p;
24952501
}
24962502
}
@@ -2512,10 +2518,18 @@ getcmdline_prompt(
25122518
{
25132519
char_u *s;
25142520
struct cmdline_info save_ccline;
2521+
int did_save_ccline = FALSE;
25152522
int msg_col_save = msg_col;
25162523
int msg_silent_save = msg_silent;
25172524

2518-
save_cmdline(&save_ccline);
2525+
if (ccline.cmdbuff != NULL)
2526+
{
2527+
// Save the values of the current cmdline and restore them below.
2528+
save_cmdline(&save_ccline);
2529+
did_save_ccline = TRUE;
2530+
}
2531+
2532+
vim_memset(&ccline, 0, sizeof(struct cmdline_info));
25192533
ccline.cmdprompt = prompt;
25202534
ccline.cmdattr = attr;
25212535
# ifdef FEAT_EVAL
@@ -2524,8 +2538,11 @@ getcmdline_prompt(
25242538
ccline.input_fn = (firstc == '@');
25252539
# endif
25262540
msg_silent = 0;
2527-
s = getcmdline(firstc, 1L, 0);
2528-
restore_cmdline(&save_ccline);
2541+
s = getcmdline_int(firstc, 1L, 0, FALSE);
2542+
2543+
if (did_save_ccline)
2544+
restore_cmdline(&save_ccline);
2545+
25292546
msg_silent = msg_silent_save;
25302547
/* Restore msg_col, the prompt from input() may have changed it.
25312548
* But only if called recursively and the commandline is therefore being
@@ -3121,7 +3138,6 @@ redrawcmd_preedit(void)
31213138
/*
31223139
* Allocate a new command line buffer.
31233140
* Assigns the new buffer to ccline.cmdbuff and ccline.cmdbufflen.
3124-
* Returns the new value of ccline.cmdbuff and ccline.cmdbufflen.
31253141
*/
31263142
static void
31273143
alloc_cmdbuff(int len)
@@ -3542,9 +3558,7 @@ save_cmdline(struct cmdline_info *ccp)
35423558
}
35433559
*ccp = prev_ccline;
35443560
prev_ccline = ccline;
3545-
ccline.cmdbuff = NULL;
3546-
ccline.cmdprompt = NULL;
3547-
ccline.xpc = NULL;
3561+
ccline.cmdbuff = NULL; // signal that ccline is not in use
35483562
}
35493563

35503564
/*
@@ -3557,37 +3571,6 @@ restore_cmdline(struct cmdline_info *ccp)
35573571
prev_ccline = *ccp;
35583572
}
35593573

3560-
#if defined(FEAT_EVAL) || defined(PROTO)
3561-
/*
3562-
* Save the command line into allocated memory. Returns a pointer to be
3563-
* passed to restore_cmdline_alloc() later.
3564-
* Returns NULL when failed.
3565-
*/
3566-
char_u *
3567-
save_cmdline_alloc(void)
3568-
{
3569-
struct cmdline_info *p;
3570-
3571-
p = (struct cmdline_info *)alloc((unsigned)sizeof(struct cmdline_info));
3572-
if (p != NULL)
3573-
save_cmdline(p);
3574-
return (char_u *)p;
3575-
}
3576-
3577-
/*
3578-
* Restore the command line from the return value of save_cmdline_alloc().
3579-
*/
3580-
void
3581-
restore_cmdline_alloc(char_u *p)
3582-
{
3583-
if (p != NULL)
3584-
{
3585-
restore_cmdline((struct cmdline_info *)p);
3586-
vim_free(p);
3587-
}
3588-
}
3589-
#endif
3590-
35913574
/*
35923575
* Paste a yank register into the command line.
35933576
* Used by CTRL-R command in command-line mode.
@@ -3606,7 +3589,6 @@ cmdline_paste(
36063589
char_u *arg;
36073590
char_u *p;
36083591
int allocated;
3609-
struct cmdline_info save_ccline;
36103592

36113593
/* check for valid regname; also accept special characters for CTRL-R in
36123594
* the command line */
@@ -3625,13 +3607,11 @@ cmdline_paste(
36253607
regname = may_get_selection(regname);
36263608
#endif
36273609

3628-
/* Need to save and restore ccline. And set "textlock" to avoid nasty
3629-
* things like going to another buffer when evaluating an expression. */
3630-
save_cmdline(&save_ccline);
3610+
// Need to set "textlock" to avoid nasty things like going to another
3611+
// buffer when evaluating an expression.
36313612
++textlock;
36323613
i = get_spec_reg(regname, &arg, &allocated, TRUE);
36333614
--textlock;
3634-
restore_cmdline(&save_ccline);
36353615

36363616
if (i)
36373617
{
@@ -5601,7 +5581,6 @@ call_user_expand_func(
56015581
sctx_T save_current_sctx = current_sctx;
56025582
char_u *pat = NULL;
56035583
void *ret;
5604-
struct cmdline_info save_ccline;
56055584

56065585
if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
56075586
return NULL;
@@ -5624,15 +5603,10 @@ call_user_expand_func(
56245603
args[2].vval.v_number = xp->xp_col;
56255604
args[3].v_type = VAR_UNKNOWN;
56265605

5627-
/* Save the cmdline, we don't know what the function may do. */
5628-
save_ccline = ccline;
5629-
ccline.cmdbuff = NULL;
5630-
ccline.cmdprompt = NULL;
56315606
current_sctx = xp->xp_script_ctx;
56325607

56335608
ret = user_expand_func(xp->xp_arg, 3, args);
56345609

5635-
ccline = save_ccline;
56365610
current_sctx = save_current_sctx;
56375611
if (ccline.cmdbuff != NULL)
56385612
ccline.cmdbuff[ccline.cmdlen] = keep;
@@ -6481,7 +6455,7 @@ remove_key_from_history(void)
64816455

64826456
#if defined(FEAT_EVAL) || defined(FEAT_CMDWIN) || defined(PROTO)
64836457
/*
6484-
* Get pointer to the command line info to use. cmdline_paste() may clear
6458+
* Get pointer to the command line info to use. save_ccline() may clear
64856459
* ccline and put the previous value in prev_ccline.
64866460
*/
64876461
static struct cmdline_info *
@@ -7072,6 +7046,12 @@ finish_viminfo_history(vir_T *virp)
70727046
}
70737047
}
70747048

7049+
void
7050+
cmdline_init(void)
7051+
{
7052+
vim_memset(&ccline, 0, sizeof(struct cmdline_info));
7053+
}
7054+
70757055
/*
70767056
* Write history to viminfo file in "fp".
70777057
* When "merge" is TRUE merge history lines with a previously read viminfo
@@ -7238,7 +7218,6 @@ cmd_gchar(int offset)
72387218
static int
72397219
open_cmdwin(void)
72407220
{
7241-
struct cmdline_info save_ccline;
72427221
bufref_T old_curbuf;
72437222
win_T *old_curwin = curwin;
72447223
bufref_T bufref;
@@ -7355,9 +7334,6 @@ open_cmdwin(void)
73557334
invalidate_botline();
73567335
redraw_later(SOME_VALID);
73577336

7358-
/* Save the command line info, can be used recursively. */
7359-
save_cmdline(&save_ccline);
7360-
73617337
/* No Ex mode here! */
73627338
exmode_active = 0;
73637339

@@ -7394,10 +7370,7 @@ open_cmdwin(void)
73947370
KeyTyped = save_KeyTyped;
73957371
# endif
73967372

7397-
/* Restore the command line info. */
7398-
restore_cmdline(&save_ccline);
73997373
cmdwin_type = 0;
7400-
74017374
exmode_active = save_exmode;
74027375

74037376
/* Safety check: The old window or buffer was deleted: It's a bug when

src/getchar.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4666,7 +4666,6 @@ eval_map_expr(
46664666
char_u *res;
46674667
char_u *p;
46684668
char_u *expr;
4669-
char_u *save_cmd;
46704669
pos_T save_cursor;
46714670
int save_msg_col;
46724671
int save_msg_row;
@@ -4678,13 +4677,6 @@ eval_map_expr(
46784677
return NULL;
46794678
vim_unescape_csi(expr);
46804679

4681-
save_cmd = save_cmdline_alloc();
4682-
if (save_cmd == NULL)
4683-
{
4684-
vim_free(expr);
4685-
return NULL;
4686-
}
4687-
46884680
/* Forbid changing text or using ":normal" to avoid most of the bad side
46894681
* effects. Also restore the cursor position. */
46904682
++textlock;
@@ -4700,7 +4692,6 @@ eval_map_expr(
47004692
msg_col = save_msg_col;
47014693
msg_row = save_msg_row;
47024694

4703-
restore_cmdline_alloc(save_cmd);
47044695
vim_free(expr);
47054696

47064697
if (p == NULL)

src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,7 @@ vim_main2(void)
929929
void
930930
common_init(mparm_T *paramp)
931931
{
932+
cmdline_init();
932933

933934
#ifdef FEAT_MBYTE
934935
(void)mb_init(); /* init mb_bytelen_tab[] to ones */

0 commit comments

Comments
 (0)