Skip to content

Commit ffa9684

Browse files
committed
patch 8.1.0053: first argument of 'completefunc' has inconsistent type
Problem: The first argument given to 'completefunc' can be Number or String, depending on the value. Solution: Avoid guessing the type of an argument, use typval_T in the callers of call_vim_function(). (Ozaki Kiichi, closes #2993)
1 parent 83f4cbd commit ffa9684

File tree

8 files changed

+86
-89
lines changed

8 files changed

+86
-89
lines changed

src/edit.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4201,7 +4201,7 @@ expand_by_function(
42014201
{
42024202
list_T *matchlist = NULL;
42034203
dict_T *matchdict = NULL;
4204-
char_u *args[2];
4204+
typval_T args[3];
42054205
char_u *funcname;
42064206
pos_T pos;
42074207
win_T *curwin_save;
@@ -4213,15 +4213,18 @@ expand_by_function(
42134213
return;
42144214

42154215
/* Call 'completefunc' to obtain the list of matches. */
4216-
args[0] = (char_u *)"0";
4217-
args[1] = base;
4216+
args[0].v_type = VAR_NUMBER;
4217+
args[0].vval.v_number = 0;
4218+
args[1].v_type = VAR_STRING;
4219+
args[1].vval.v_string = base != NULL ? base : (char_u *)"";
4220+
args[2].v_type = VAR_UNKNOWN;
42184221

42194222
pos = curwin->w_cursor;
42204223
curwin_save = curwin;
42214224
curbuf_save = curbuf;
42224225

42234226
/* Call a function, which returns a list or dict. */
4224-
if (call_vim_function(funcname, 2, args, FALSE, FALSE, &rettv) == OK)
4227+
if (call_vim_function(funcname, 2, args, &rettv, FALSE) == OK)
42254228
{
42264229
switch (rettv.v_type)
42274230
{
@@ -5528,7 +5531,7 @@ ins_complete(int c, int enable_pum)
55285531
* Call user defined function 'completefunc' with "a:findstart"
55295532
* set to 1 to obtain the length of text to use for completion.
55305533
*/
5531-
char_u *args[2];
5534+
typval_T args[3];
55325535
int col;
55335536
char_u *funcname;
55345537
pos_T pos;
@@ -5548,8 +5551,11 @@ ins_complete(int c, int enable_pum)
55485551
return FAIL;
55495552
}
55505553

5551-
args[0] = (char_u *)"1";
5552-
args[1] = NULL;
5554+
args[0].v_type = VAR_NUMBER;
5555+
args[0].vval.v_number = 1;
5556+
args[1].v_type = VAR_STRING;
5557+
args[1].vval.v_string = (char_u *)"";
5558+
args[2].v_type = VAR_UNKNOWN;
55535559
pos = curwin->w_cursor;
55545560
curwin_save = curwin;
55555561
curbuf_save = curbuf;

src/eval.c

Lines changed: 18 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,79 +1011,37 @@ eval_expr(char_u *arg, char_u **nextcmd)
10111011

10121012
/*
10131013
* Call some Vim script function and return the result in "*rettv".
1014-
* Uses argv[argc] for the function arguments. Only Number and String
1015-
* arguments are currently supported.
1014+
* Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc]
1015+
* should have type VAR_UNKNOWN.
10161016
* Returns OK or FAIL.
10171017
*/
10181018
int
10191019
call_vim_function(
10201020
char_u *func,
10211021
int argc,
1022-
char_u **argv,
1023-
int safe, /* use the sandbox */
1024-
int str_arg_only, /* all arguments are strings */
1025-
typval_T *rettv)
1022+
typval_T *argv,
1023+
typval_T *rettv,
1024+
int safe) /* use the sandbox */
10261025
{
1027-
typval_T *argvars;
1028-
varnumber_T n;
1029-
int len;
1030-
int i;
10311026
int doesrange;
10321027
void *save_funccalp = NULL;
10331028
int ret;
10341029

1035-
argvars = (typval_T *)alloc((unsigned)((argc + 1) * sizeof(typval_T)));
1036-
if (argvars == NULL)
1037-
return FAIL;
1038-
1039-
for (i = 0; i < argc; i++)
1040-
{
1041-
/* Pass a NULL or empty argument as an empty string */
1042-
if (argv[i] == NULL || *argv[i] == NUL)
1043-
{
1044-
argvars[i].v_type = VAR_STRING;
1045-
argvars[i].vval.v_string = (char_u *)"";
1046-
continue;
1047-
}
1048-
1049-
if (str_arg_only)
1050-
len = 0;
1051-
else
1052-
{
1053-
/* Recognize a number argument, the others must be strings. A dash
1054-
* is a string too. */
1055-
vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0);
1056-
if (len == 1 && *argv[i] == '-')
1057-
len = 0;
1058-
}
1059-
if (len != 0 && len == (int)STRLEN(argv[i]))
1060-
{
1061-
argvars[i].v_type = VAR_NUMBER;
1062-
argvars[i].vval.v_number = n;
1063-
}
1064-
else
1065-
{
1066-
argvars[i].v_type = VAR_STRING;
1067-
argvars[i].vval.v_string = argv[i];
1068-
}
1069-
}
1070-
10711030
if (safe)
10721031
{
10731032
save_funccalp = save_funccal();
10741033
++sandbox;
10751034
}
10761035

10771036
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
1078-
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, NULL,
1037+
ret = call_func(func, (int)STRLEN(func), rettv, argc, argv, NULL,
10791038
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
10801039
&doesrange, TRUE, NULL, NULL);
10811040
if (safe)
10821041
{
10831042
--sandbox;
10841043
restore_funccal(save_funccalp);
10851044
}
1086-
vim_free(argvars);
10871045

10881046
if (ret == FAIL)
10891047
clear_tv(rettv);
@@ -1094,20 +1052,20 @@ call_vim_function(
10941052
/*
10951053
* Call Vim script function "func" and return the result as a number.
10961054
* Returns -1 when calling the function fails.
1097-
* Uses argv[argc] for the function arguments.
1055+
* Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
1056+
* have type VAR_UNKNOWN.
10981057
*/
10991058
varnumber_T
11001059
call_func_retnr(
11011060
char_u *func,
11021061
int argc,
1103-
char_u **argv,
1062+
typval_T *argv,
11041063
int safe) /* use the sandbox */
11051064
{
11061065
typval_T rettv;
11071066
varnumber_T retval;
11081067

1109-
/* All arguments are passed as strings, no conversion to number. */
1110-
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
1068+
if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL)
11111069
return -1;
11121070

11131071
retval = get_tv_number_chk(&rettv, NULL);
@@ -1122,20 +1080,20 @@ call_func_retnr(
11221080
/*
11231081
* Call Vim script function "func" and return the result as a string.
11241082
* Returns NULL when calling the function fails.
1125-
* Uses argv[argc] for the function arguments.
1083+
* Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
1084+
* have type VAR_UNKNOWN.
11261085
*/
11271086
void *
11281087
call_func_retstr(
11291088
char_u *func,
11301089
int argc,
1131-
char_u **argv,
1090+
typval_T *argv,
11321091
int safe) /* use the sandbox */
11331092
{
11341093
typval_T rettv;
11351094
char_u *retval;
11361095

1137-
/* All arguments are passed as strings, no conversion to number. */
1138-
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
1096+
if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL)
11391097
return NULL;
11401098

11411099
retval = vim_strsave(get_tv_string(&rettv));
@@ -1146,20 +1104,20 @@ call_func_retstr(
11461104

11471105
/*
11481106
* Call Vim script function "func" and return the result as a List.
1149-
* Uses argv[argc] for the function arguments.
1107+
* Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should
1108+
* have type VAR_UNKNOWN.
11501109
* Returns NULL when there is something wrong.
11511110
*/
11521111
void *
11531112
call_func_retlist(
11541113
char_u *func,
11551114
int argc,
1156-
char_u **argv,
1115+
typval_T *argv,
11571116
int safe) /* use the sandbox */
11581117
{
11591118
typval_T rettv;
11601119

1161-
/* All arguments are passed as strings, no conversion to number. */
1162-
if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
1120+
if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL)
11631121
return NULL;
11641122

11651123
if (rettv.v_type != VAR_LIST)

src/ex_getln.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5266,23 +5266,23 @@ expand_shellcmd(
52665266

52675267

52685268
# if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL)
5269-
static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, char_u **, int), expand_T *xp, int *num_file, char_u ***file);
5269+
static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, typval_T *, int), expand_T *xp, int *num_file, char_u ***file);
52705270

52715271
/*
52725272
* Call "user_expand_func()" to invoke a user defined Vim script function and
52735273
* return the result (either a string or a List).
52745274
*/
52755275
static void *
52765276
call_user_expand_func(
5277-
void *(*user_expand_func)(char_u *, int, char_u **, int),
5277+
void *(*user_expand_func)(char_u *, int, typval_T *, int),
52785278
expand_T *xp,
52795279
int *num_file,
52805280
char_u ***file)
52815281
{
52825282
int keep = 0;
5283-
char_u num[50];
5284-
char_u *args[3];
5283+
typval_T args[4];
52855284
int save_current_SID = current_SID;
5285+
char_u *pat = NULL;
52865286
void *ret;
52875287
struct cmdline_info save_ccline;
52885288

@@ -5297,10 +5297,15 @@ call_user_expand_func(
52975297
ccline.cmdbuff[ccline.cmdlen] = 0;
52985298
}
52995299

5300-
args[0] = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len);
5301-
args[1] = xp->xp_line;
5302-
sprintf((char *)num, "%d", xp->xp_col);
5303-
args[2] = num;
5300+
pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len);
5301+
5302+
args[0].v_type = VAR_STRING;
5303+
args[0].vval.v_string = pat;
5304+
args[1].v_type = VAR_STRING;
5305+
args[1].vval.v_string = xp->xp_line;
5306+
args[2].v_type = VAR_NUMBER;
5307+
args[2].vval.v_number = xp->xp_col;
5308+
args[3].v_type = VAR_UNKNOWN;
53045309

53055310
/* Save the cmdline, we don't know what the function may do. */
53065311
save_ccline = ccline;
@@ -5315,7 +5320,7 @@ call_user_expand_func(
53155320
if (ccline.cmdbuff != NULL)
53165321
ccline.cmdbuff[ccline.cmdlen] = keep;
53175322

5318-
vim_free(args[0]);
5323+
vim_free(pat);
53195324
return ret;
53205325
}
53215326

src/mbyte.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4795,12 +4795,11 @@ iconv_end(void)
47954795
static void
47964796
call_imactivatefunc(int active)
47974797
{
4798-
char_u *argv[1];
4798+
typval_T argv[2];
47994799

4800-
if (active)
4801-
argv[0] = (char_u *)"1";
4802-
else
4803-
argv[0] = (char_u *)"0";
4800+
argv[0].v_type = VAR_NUMBER;
4801+
argv[0].vval.v_number = active ? 1 : 0;
4802+
argv[1].v_type = VAR_NUMBER;
48044803
(void)call_func_retnr(p_imaf, 1, argv, FALSE);
48054804
}
48064805

src/normal.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2219,7 +2219,7 @@ op_colon(oparg_T *oap)
22192219
op_function(oparg_T *oap UNUSED)
22202220
{
22212221
#ifdef FEAT_EVAL
2222-
char_u *(argv[1]);
2222+
typval_T argv[2];
22232223
# ifdef FEAT_VIRTUALEDIT
22242224
int save_virtual_op = virtual_op;
22252225
# endif
@@ -2235,12 +2235,14 @@ op_function(oparg_T *oap UNUSED)
22352235
/* Exclude the end position. */
22362236
decl(&curbuf->b_op_end);
22372237

2238+
argv[0].v_type = VAR_STRING;
22382239
if (oap->block_mode)
2239-
argv[0] = (char_u *)"block";
2240+
argv[0].vval.v_string = (char_u *)"block";
22402241
else if (oap->motion_type == MLINE)
2241-
argv[0] = (char_u *)"line";
2242+
argv[0].vval.v_string = (char_u *)"line";
22422243
else
2243-
argv[0] = (char_u *)"char";
2244+
argv[0].vval.v_string = (char_u *)"char";
2245+
argv[1].v_type = VAR_UNKNOWN;
22442246

22452247
# ifdef FEAT_VIRTUALEDIT
22462248
/* Reset virtual_op so that 'virtualedit' can be changed in the

src/proto/eval.pro

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ varnumber_T eval_to_number(char_u *expr);
1919
list_T *eval_spell_expr(char_u *badword, char_u *expr);
2020
int get_spellword(list_T *list, char_u **pp);
2121
typval_T *eval_expr(char_u *arg, char_u **nextcmd);
22-
int call_vim_function(char_u *func, int argc, char_u **argv, int safe, int str_arg_only, typval_T *rettv);
23-
varnumber_T call_func_retnr(char_u *func, int argc, char_u **argv, int safe);
24-
void *call_func_retstr(char_u *func, int argc, char_u **argv, int safe);
25-
void *call_func_retlist(char_u *func, int argc, char_u **argv, int safe);
22+
int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv, int safe);
23+
varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv, int safe);
24+
void *call_func_retstr(char_u *func, int argc, typval_T *argv, int safe);
25+
void *call_func_retlist(char_u *func, int argc, typval_T *argv, int safe);
2626
int eval_foldexpr(char_u *arg, int *cp);
2727
void ex_let(exarg_T *eap);
2828
void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first);

src/testdir/test_ins_complete.vim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,31 @@ func Test_omni_dash()
117117
set omnifunc=
118118
endfunc
119119

120+
func Test_completefunc_args()
121+
let s:args = []
122+
func! CompleteFunc(findstart, base)
123+
let s:args += [[a:findstart, empty(a:base)]]
124+
endfunc
125+
new
126+
127+
set completefunc=CompleteFunc
128+
call feedkeys("i\<C-X>\<C-U>\<Esc>", 'x')
129+
call assert_equal(s:args[0], [1, 1])
130+
call assert_equal(s:args[1][0], 0)
131+
set completefunc=
132+
133+
let s:args = []
134+
set omnifunc=CompleteFunc
135+
call feedkeys("i\<C-X>\<C-O>\<Esc>", 'x')
136+
call assert_equal(s:args[0], [1, 1])
137+
call assert_equal(s:args[1][0], 0)
138+
set omnifunc=
139+
140+
bwipe!
141+
unlet s:args
142+
delfunc CompleteFunc
143+
endfunc
144+
120145
function! s:CompleteDone_CompleteFuncDict( findstart, base )
121146
if a:findstart
122147
return 0

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,8 @@ static char *(features[]) =
761761

762762
static int included_patches[] =
763763
{ /* Add new patch number below this line */
764+
/**/
765+
53,
764766
/**/
765767
52,
766768
/**/

0 commit comments

Comments
 (0)