0
0
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:
Bram Moolenaar
2020-07-08 22:01:49 +02:00
parent 6110e79a58
commit 8e2730a315
6 changed files with 67 additions and 33 deletions

View File

@@ -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;
} }
} }

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;
} }

View File

@@ -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,
/**/ /**/

View File

@@ -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;