mirror of
https://github.com/vim/vim.git
synced 2025-09-25 03:54:15 -04:00
patch 8.2.2864: Vim9: crash when using inline function
Problem: Vim9: crash when using inline function. Solution: Check for NULL pointer. Make using inline function work inside lambda. (closes #8217)
This commit is contained in:
@@ -2102,6 +2102,20 @@ def Test_nested_lambda()
|
|||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_nested_inline_lambda()
|
||||||
|
# TODO: use the "text" argument
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
def F(text: string): func(string): func(string): string
|
||||||
|
return (arg: string): func(string): string => ((sep: string): string => {
|
||||||
|
return sep .. arg
|
||||||
|
})
|
||||||
|
enddef
|
||||||
|
assert_equal('--there', F('unused')('there')('--'))
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
enddef
|
||||||
|
|
||||||
def Shadowed(): list<number>
|
def Shadowed(): list<number>
|
||||||
var FuncList: list<func: number> = [() => 42]
|
var FuncList: list<func: number> = [() => 42]
|
||||||
return FuncList->mapnew((_, Shadowed) => Shadowed())
|
return FuncList->mapnew((_, Shadowed) => Shadowed())
|
||||||
|
@@ -606,6 +606,7 @@ is_function_cmd(char_u **cmd)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the body of a function, put every line in "newlines".
|
* Read the body of a function, put every line in "newlines".
|
||||||
|
* This stops at "}", "endfunction" or "enddef".
|
||||||
* "newlines" must already have been initialized.
|
* "newlines" must already have been initialized.
|
||||||
* "eap->cmdidx" is CMD_function, CMD_def or CMD_block;
|
* "eap->cmdidx" is CMD_function, CMD_def or CMD_block;
|
||||||
*/
|
*/
|
||||||
@@ -945,9 +946,8 @@ get_function_body(
|
|||||||
line_arg = NULL;
|
line_arg = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't define the function when skipping commands or when an error was
|
// Return OK when no error was detected.
|
||||||
// detected.
|
if (!did_emsg)
|
||||||
if (!eap->skip && !did_emsg)
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
|
|
||||||
theend:
|
theend:
|
||||||
@@ -960,6 +960,7 @@ theend:
|
|||||||
/*
|
/*
|
||||||
* Handle the body of a lambda. *arg points to the "{", process statements
|
* Handle the body of a lambda. *arg points to the "{", process statements
|
||||||
* until the matching "}".
|
* until the matching "}".
|
||||||
|
* When not evaluating "newargs" is NULL.
|
||||||
* When successful "rettv" is set to a funcref.
|
* When successful "rettv" is set to a funcref.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
@@ -974,6 +975,7 @@ lambda_function_body(
|
|||||||
char_u *ret_type)
|
char_u *ret_type)
|
||||||
{
|
{
|
||||||
int evaluate = (evalarg->eval_flags & EVAL_EVALUATE);
|
int evaluate = (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
|
garray_T *gap = &evalarg->eval_ga;
|
||||||
ufunc_T *ufunc = NULL;
|
ufunc_T *ufunc = NULL;
|
||||||
exarg_T eap;
|
exarg_T eap;
|
||||||
garray_T newlines;
|
garray_T newlines;
|
||||||
@@ -1010,6 +1012,52 @@ lambda_function_body(
|
|||||||
vim_free(cmdline);
|
vim_free(cmdline);
|
||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When inside a lambda must add the function lines to evalarg.eval_ga.
|
||||||
|
evalarg->eval_break_count += newlines.ga_len;
|
||||||
|
if (gap->ga_itemsize > 0)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
char_u *last;
|
||||||
|
size_t plen;
|
||||||
|
char_u *pnl;
|
||||||
|
|
||||||
|
for (idx = 0; idx < newlines.ga_len; ++idx)
|
||||||
|
{
|
||||||
|
char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]);
|
||||||
|
|
||||||
|
if (ga_grow(gap, 1) == FAIL)
|
||||||
|
goto erret;
|
||||||
|
|
||||||
|
// Going to concatenate the lines after parsing. For an empty or
|
||||||
|
// comment line use an empty string.
|
||||||
|
// Insert NL characters at the start of each line, the string will
|
||||||
|
// be split again later in .get_lambda_tv().
|
||||||
|
if (*p == NUL || vim9_comment_start(p))
|
||||||
|
p = (char_u *)"";
|
||||||
|
plen = STRLEN(p);
|
||||||
|
pnl = vim_strnsave((char_u *)"\n", plen + 1);
|
||||||
|
if (pnl != NULL)
|
||||||
|
mch_memmove(pnl + 1, p, plen + 1);
|
||||||
|
((char_u **)gap->ga_data)[gap->ga_len] = pnl;
|
||||||
|
++gap->ga_len;
|
||||||
|
}
|
||||||
|
if (ga_grow(gap, 1) == FAIL)
|
||||||
|
goto erret;
|
||||||
|
if (cmdline != NULL)
|
||||||
|
// more is following after the "}", which was skipped
|
||||||
|
last = cmdline;
|
||||||
|
else
|
||||||
|
// nothing is following the "}"
|
||||||
|
last = (char_u *)"}";
|
||||||
|
plen = STRLEN(last);
|
||||||
|
pnl = vim_strnsave((char_u *)"\n", plen + 1);
|
||||||
|
if (pnl != NULL)
|
||||||
|
mch_memmove(pnl + 1, last, plen + 1);
|
||||||
|
((char_u **)gap->ga_data)[gap->ga_len] = pnl;
|
||||||
|
++gap->ga_len;
|
||||||
|
}
|
||||||
|
|
||||||
if (cmdline != NULL)
|
if (cmdline != NULL)
|
||||||
{
|
{
|
||||||
// Something comes after the "}".
|
// Something comes after the "}".
|
||||||
@@ -1022,6 +1070,12 @@ lambda_function_body(
|
|||||||
else
|
else
|
||||||
*arg = (char_u *)"";
|
*arg = (char_u *)"";
|
||||||
|
|
||||||
|
if (!evaluate)
|
||||||
|
{
|
||||||
|
ret = OK;
|
||||||
|
goto erret;
|
||||||
|
}
|
||||||
|
|
||||||
name = get_lambda_name();
|
name = get_lambda_name();
|
||||||
ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||||
if (ufunc == NULL)
|
if (ufunc == NULL)
|
||||||
@@ -1078,6 +1132,7 @@ erret:
|
|||||||
SOURCING_LNUM = lnum_save;
|
SOURCING_LNUM = lnum_save;
|
||||||
vim_free(line_to_free);
|
vim_free(line_to_free);
|
||||||
ga_clear_strings(&newlines);
|
ga_clear_strings(&newlines);
|
||||||
|
if (newargs != NULL)
|
||||||
ga_clear_strings(newargs);
|
ga_clear_strings(newargs);
|
||||||
ga_clear_strings(default_args);
|
ga_clear_strings(default_args);
|
||||||
if (ufunc != NULL)
|
if (ufunc != NULL)
|
||||||
@@ -1222,6 +1277,7 @@ get_lambda_tv(
|
|||||||
int len;
|
int len;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
char_u *line_end;
|
||||||
char_u *name = get_lambda_name();
|
char_u *name = get_lambda_name();
|
||||||
|
|
||||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||||
@@ -1236,14 +1292,37 @@ get_lambda_tv(
|
|||||||
if (ga_grow(&newlines, 1) == FAIL)
|
if (ga_grow(&newlines, 1) == FAIL)
|
||||||
goto errret;
|
goto errret;
|
||||||
|
|
||||||
// Add "return " before the expression.
|
// If there are line breaks, we need to split up the string.
|
||||||
len = 7 + (int)(end - start) + 1;
|
line_end = vim_strchr(start, '\n');
|
||||||
|
if (line_end == NULL)
|
||||||
|
line_end = end;
|
||||||
|
|
||||||
|
// Add "return " before the expression (or the first line).
|
||||||
|
len = 7 + (int)(line_end - start) + 1;
|
||||||
p = alloc(len);
|
p = alloc(len);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
goto errret;
|
goto errret;
|
||||||
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
|
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
|
||||||
STRCPY(p, "return ");
|
STRCPY(p, "return ");
|
||||||
vim_strncpy(p + 7, start, end - start);
|
vim_strncpy(p + 7, start, line_end - start);
|
||||||
|
|
||||||
|
if (line_end != end)
|
||||||
|
{
|
||||||
|
// Add more lines, split by line breaks. Thus is used when a
|
||||||
|
// lambda with { cmds } is encountered.
|
||||||
|
while (*line_end == '\n')
|
||||||
|
{
|
||||||
|
if (ga_grow(&newlines, 1) == FAIL)
|
||||||
|
goto errret;
|
||||||
|
start = line_end + 1;
|
||||||
|
line_end = vim_strchr(start, '\n');
|
||||||
|
if (line_end == NULL)
|
||||||
|
line_end = end;
|
||||||
|
((char_u **)(newlines.ga_data))[newlines.ga_len++] =
|
||||||
|
vim_strnsave(start, line_end - start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (strstr((char *)p + 7, "a:") == NULL)
|
if (strstr((char *)p + 7, "a:") == NULL)
|
||||||
// No a: variables are used for sure.
|
// No a: variables are used for sure.
|
||||||
flags |= FC_NOARGS;
|
flags |= FC_NOARGS;
|
||||||
|
@@ -750,6 +750,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 */
|
||||||
|
/**/
|
||||||
|
2864,
|
||||||
/**/
|
/**/
|
||||||
2863,
|
2863,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user