mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 8.2.1161: Vim9: using freed memory
Problem: Vim9: using freed memory. Solution: Put pointer back in evalarg instead of freeing it.
This commit is contained in:
60
src/eval.c
60
src/eval.c
@@ -379,10 +379,17 @@ skip_expr(char_u **pp)
|
|||||||
* Skip over an expression at "*pp".
|
* Skip over an expression at "*pp".
|
||||||
* If in Vim9 script and line breaks are encountered, the lines are
|
* If in Vim9 script and line breaks are encountered, the lines are
|
||||||
* concatenated. "evalarg->eval_tofree" will be set accordingly.
|
* concatenated. "evalarg->eval_tofree" will be set accordingly.
|
||||||
|
* "arg" is advanced to just after the expression.
|
||||||
|
* "start" is set to the start of the expression, "end" to just after the end.
|
||||||
|
* Also when the expression is copied to allocated memory.
|
||||||
* Return FAIL for an error, OK otherwise.
|
* Return FAIL for an error, OK otherwise.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
|
skip_expr_concatenate(
|
||||||
|
char_u **arg,
|
||||||
|
char_u **start,
|
||||||
|
char_u **end,
|
||||||
|
evalarg_T *evalarg)
|
||||||
{
|
{
|
||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
int res;
|
int res;
|
||||||
@@ -398,12 +405,14 @@ skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
|
|||||||
if (ga_grow(gap, 1) == OK)
|
if (ga_grow(gap, 1) == OK)
|
||||||
++gap->ga_len;
|
++gap->ga_len;
|
||||||
}
|
}
|
||||||
|
*start = *arg;
|
||||||
|
|
||||||
// Don't evaluate the expression.
|
// Don't evaluate the expression.
|
||||||
if (evalarg != NULL)
|
if (evalarg != NULL)
|
||||||
evalarg->eval_flags &= ~EVAL_EVALUATE;
|
evalarg->eval_flags &= ~EVAL_EVALUATE;
|
||||||
*end = skipwhite(*end);
|
*arg = skipwhite(*arg);
|
||||||
res = eval1(end, &rettv, evalarg);
|
res = eval1(arg, &rettv, evalarg);
|
||||||
|
*end = *arg;
|
||||||
if (evalarg != NULL)
|
if (evalarg != NULL)
|
||||||
evalarg->eval_flags = save_flags;
|
evalarg->eval_flags = save_flags;
|
||||||
|
|
||||||
@@ -419,7 +428,7 @@ skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
char_u *p;
|
char_u *p;
|
||||||
size_t endoff = STRLEN(*end);
|
size_t endoff = STRLEN(*arg);
|
||||||
|
|
||||||
// Line breaks encountered, concatenate all the lines.
|
// Line breaks encountered, concatenate all the lines.
|
||||||
*((char_u **)gap->ga_data) = *start;
|
*((char_u **)gap->ga_data) = *start;
|
||||||
@@ -428,7 +437,14 @@ skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
|
|||||||
// free the lines only when using getsourceline()
|
// free the lines only when using getsourceline()
|
||||||
if (evalarg->eval_cookie != NULL)
|
if (evalarg->eval_cookie != NULL)
|
||||||
{
|
{
|
||||||
|
// Do not free the first line, the caller can still use it.
|
||||||
*((char_u **)gap->ga_data) = NULL;
|
*((char_u **)gap->ga_data) = NULL;
|
||||||
|
// Do not free the last line, "arg" points into it, free it
|
||||||
|
// later.
|
||||||
|
vim_free(evalarg->eval_tofree);
|
||||||
|
evalarg->eval_tofree =
|
||||||
|
((char_u **)gap->ga_data)[gap->ga_len - 1];
|
||||||
|
((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL;
|
||||||
ga_clear_strings(gap);
|
ga_clear_strings(gap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -437,8 +453,8 @@ skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
|
|||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
*start = p;
|
*start = p;
|
||||||
vim_free(evalarg->eval_tofree);
|
vim_free(evalarg->eval_tofree_lambda);
|
||||||
evalarg->eval_tofree = p;
|
evalarg->eval_tofree_lambda = p;
|
||||||
// Compute "end" relative to the end.
|
// Compute "end" relative to the end.
|
||||||
*end = *start + STRLEN(*start) - endoff;
|
*end = *start + STRLEN(*start) - endoff;
|
||||||
}
|
}
|
||||||
@@ -1936,7 +1952,7 @@ eval_next_line(evalarg_T *evalarg)
|
|||||||
((char_u **)gap->ga_data)[gap->ga_len] = line;
|
((char_u **)gap->ga_data)[gap->ga_len] = line;
|
||||||
++gap->ga_len;
|
++gap->ga_len;
|
||||||
}
|
}
|
||||||
else
|
else if (evalarg->eval_cookie != NULL)
|
||||||
{
|
{
|
||||||
vim_free(evalarg->eval_tofree);
|
vim_free(evalarg->eval_tofree);
|
||||||
evalarg->eval_tofree = line;
|
evalarg->eval_tofree = line;
|
||||||
@@ -1962,25 +1978,31 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After using "evalarg" filled from "eap" free the memory.
|
* After using "evalarg" filled from "eap": free the memory.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
|
clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (evalarg != NULL && evalarg->eval_tofree != NULL)
|
if (evalarg != NULL)
|
||||||
{
|
{
|
||||||
if (eap != NULL)
|
if (evalarg->eval_tofree != NULL)
|
||||||
{
|
{
|
||||||
// We may need to keep the original command line, e.g. for
|
if (eap != NULL)
|
||||||
// ":let" it has the variable names. But we may also need the
|
{
|
||||||
// new one, "nextcmd" points into it. Keep both.
|
// We may need to keep the original command line, e.g. for
|
||||||
vim_free(eap->cmdline_tofree);
|
// ":let" it has the variable names. But we may also need the
|
||||||
eap->cmdline_tofree = *eap->cmdlinep;
|
// new one, "nextcmd" points into it. Keep both.
|
||||||
*eap->cmdlinep = evalarg->eval_tofree;
|
vim_free(eap->cmdline_tofree);
|
||||||
|
eap->cmdline_tofree = *eap->cmdlinep;
|
||||||
|
*eap->cmdlinep = evalarg->eval_tofree;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vim_free(evalarg->eval_tofree);
|
||||||
|
evalarg->eval_tofree = NULL;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
vim_free(evalarg->eval_tofree);
|
vim_free(evalarg->eval_tofree_lambda);
|
||||||
evalarg->eval_tofree = NULL;
|
evalarg->eval_tofree_lambda = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv);
|
|||||||
int eval_expr_to_bool(typval_T *expr, int *error);
|
int eval_expr_to_bool(typval_T *expr, int *error);
|
||||||
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
|
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
|
||||||
int skip_expr(char_u **pp);
|
int skip_expr(char_u **pp);
|
||||||
int skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg);
|
int skip_expr_concatenate(char_u **arg, char_u **start, char_u **end, evalarg_T *evalarg);
|
||||||
char_u *eval_to_string(char_u *arg, int convert);
|
char_u *eval_to_string(char_u *arg, int convert);
|
||||||
char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
|
char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
|
||||||
varnumber_T eval_to_number(char_u *expr);
|
varnumber_T eval_to_number(char_u *expr);
|
||||||
|
@@ -1773,8 +1773,11 @@ typedef struct {
|
|||||||
// "eval_ga.ga_data" is a list of pointers to lines.
|
// "eval_ga.ga_data" is a list of pointers to lines.
|
||||||
garray_T eval_ga;
|
garray_T eval_ga;
|
||||||
|
|
||||||
// pointer to the line obtained with getsourceline()
|
// pointer to the last line obtained with getsourceline()
|
||||||
char_u *eval_tofree;
|
char_u *eval_tofree;
|
||||||
|
|
||||||
|
// pointer to the lines concatenated for a lambda.
|
||||||
|
char_u *eval_tofree_lambda;
|
||||||
} evalarg_T;
|
} evalarg_T;
|
||||||
|
|
||||||
// Flags for expression evaluation.
|
// Flags for expression evaluation.
|
||||||
|
@@ -389,8 +389,8 @@ get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
partial_T *pt = NULL;
|
partial_T *pt = NULL;
|
||||||
int varargs;
|
int varargs;
|
||||||
int ret;
|
int ret;
|
||||||
char_u *start;
|
char_u *s;
|
||||||
char_u *s, *e;
|
char_u *start, *end;
|
||||||
int *old_eval_lavars = eval_lavars_used;
|
int *old_eval_lavars = eval_lavars_used;
|
||||||
int eval_lavars = FALSE;
|
int eval_lavars = FALSE;
|
||||||
char_u *tofree = NULL;
|
char_u *tofree = NULL;
|
||||||
@@ -399,10 +399,10 @@ get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
ga_init(&newlines);
|
ga_init(&newlines);
|
||||||
|
|
||||||
// First, check if this is a lambda expression. "->" must exist.
|
// First, check if this is a lambda expression. "->" must exist.
|
||||||
start = skipwhite(*arg + 1);
|
s = skipwhite(*arg + 1);
|
||||||
ret = get_function_args(&start, '-', NULL, NULL, NULL, NULL, TRUE,
|
ret = get_function_args(&s, '-', NULL, NULL, NULL, NULL, TRUE,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
if (ret == FAIL || *start != '>')
|
if (ret == FAIL || *s != '>')
|
||||||
return NOTDONE;
|
return NOTDONE;
|
||||||
|
|
||||||
// Parse the arguments again.
|
// Parse the arguments again.
|
||||||
@@ -423,8 +423,8 @@ get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
|
|
||||||
// Get the start and the end of the expression.
|
// Get the start and the end of the expression.
|
||||||
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
|
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
|
||||||
s = *arg;
|
start = *arg;
|
||||||
ret = skip_expr_concatenate(&s, arg, evalarg);
|
ret = skip_expr_concatenate(arg, &start, &end, evalarg);
|
||||||
if (ret == FAIL)
|
if (ret == FAIL)
|
||||||
goto errret;
|
goto errret;
|
||||||
if (evalarg != NULL)
|
if (evalarg != NULL)
|
||||||
@@ -434,7 +434,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
evalarg->eval_tofree = NULL;
|
evalarg->eval_tofree = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = *arg;
|
|
||||||
*arg = skipwhite_and_linebreak(*arg, evalarg);
|
*arg = skipwhite_and_linebreak(*arg, evalarg);
|
||||||
if (**arg != '}')
|
if (**arg != '}')
|
||||||
{
|
{
|
||||||
@@ -463,13 +462,13 @@ get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
goto errret;
|
goto errret;
|
||||||
|
|
||||||
// Add "return " before the expression.
|
// Add "return " before the expression.
|
||||||
len = 7 + (int)(e - s) + 1;
|
len = 7 + (int)(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, s, e - s);
|
vim_strncpy(p + 7, start, 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;
|
||||||
@@ -509,7 +508,10 @@ get_lambda_tv(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
vim_free(tofree);
|
if (evalarg->eval_tofree == NULL)
|
||||||
|
evalarg->eval_tofree = tofree;
|
||||||
|
else
|
||||||
|
vim_free(tofree);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
errret:
|
errret:
|
||||||
@@ -517,7 +519,10 @@ errret:
|
|||||||
ga_clear_strings(&newlines);
|
ga_clear_strings(&newlines);
|
||||||
vim_free(fp);
|
vim_free(fp);
|
||||||
vim_free(pt);
|
vim_free(pt);
|
||||||
vim_free(tofree);
|
if (evalarg->eval_tofree == NULL)
|
||||||
|
evalarg->eval_tofree = tofree;
|
||||||
|
else
|
||||||
|
vim_free(tofree);
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
@@ -754,6 +754,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 */
|
||||||
|
/**/
|
||||||
|
1161,
|
||||||
/**/
|
/**/
|
||||||
1160,
|
1160,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -3113,6 +3113,8 @@ compile_lambda(char_u **arg, cctx_T *cctx)
|
|||||||
// Compile it into instructions.
|
// Compile it into instructions.
|
||||||
compile_def_function(ufunc, TRUE, cctx);
|
compile_def_function(ufunc, TRUE, cctx);
|
||||||
|
|
||||||
|
clear_evalarg(&evalarg, NULL);
|
||||||
|
|
||||||
if (ufunc->uf_def_status == UF_COMPILED)
|
if (ufunc->uf_def_status == UF_COMPILED)
|
||||||
return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
|
return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
Reference in New Issue
Block a user