Patch 8.2.1161
Problem: Vim9: using freed memory.
Solution: Put pointer back in evalarg instead of freeing it.
Files: src/userfunc.c, src/vim9compile.c, src/eval.c, src/proto/
eval.pro,
src/structs.h
*** ../vim-8.2.1160/src/userfunc.c 2020-07-08 19:35:17.767686401 +0200
--- src/userfunc.c 2020-07-08 21:33:04.828727980 +0200
***************
*** 389,396 ****
partial_T *pt = NULL;
int varargs;
int ret;
! char_u *start;
! char_u *s, *e;
int *old_eval_lavars = eval_lavars_used;
int eval_lavars = FALSE;
char_u *tofree = NULL;
--- 389,396 ----
partial_T *pt = NULL;
int varargs;
int ret;
! char_u *s;
! char_u *start, *end;
int *old_eval_lavars = eval_lavars_used;
int eval_lavars = FALSE;
char_u *tofree = NULL;
***************
*** 399,408 ****
ga_init(&newlines);
// First, check if this is a lambda expression. "->" must exist.
! start = skipwhite(*arg + 1);
! ret = get_function_args(&start, '-', NULL, NULL, NULL, NULL, TRUE,
NULL, NULL);
! if (ret == FAIL || *start != '>')
return NOTDONE;
// Parse the arguments again.
--- 399,408 ----
ga_init(&newlines);
// First, check if this is a lambda expression. "->" must exist.
! s = skipwhite(*arg + 1);
! ret = get_function_args(&s, '-', NULL, NULL, NULL, NULL, TRUE,
NULL, NULL);
! if (ret == FAIL || *s != '>')
return NOTDONE;
// Parse the arguments again.
***************
*** 423,430 ****
// Get the start and the end of the expression.
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
! s = *arg;
! ret = skip_expr_concatenate(&s, arg, evalarg);
if (ret == FAIL)
goto errret;
if (evalarg != NULL)
--- 423,430 ----
// Get the start and the end of the expression.
*arg = skipwhite_and_linebreak(*arg + 1, evalarg);
! start = *arg;
! ret = skip_expr_concatenate(arg, &start, &end, evalarg);
if (ret == FAIL)
goto errret;
if (evalarg != NULL)
***************
*** 434,440 ****
evalarg->eval_tofree = NULL;
}
- e = *arg;
*arg = skipwhite_and_linebreak(*arg, evalarg);
if (**arg != '}')
{
--- 434,439 ----
***************
*** 463,475 ****
goto errret;
// Add "return " before the expression.
! len = 7 + (int)(e - s) + 1;
p = alloc(len);
if (p == NULL)
goto errret;
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
! vim_strncpy(p + 7, s, e - s);
if (strstr((char *)p + 7, "a:") == NULL)
// No a: variables are used for sure.
flags |= FC_NOARGS;
--- 462,474 ----
goto errret;
// Add "return " before the expression.
! len = 7 + (int)(end - start) + 1;
p = alloc(len);
if (p == NULL)
goto errret;
((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
STRCPY(p, "return ");
! vim_strncpy(p + 7, start, end - start);
if (strstr((char *)p + 7, "a:") == NULL)
// No a: variables are used for sure.
flags |= FC_NOARGS;
***************
*** 509,515 ****
}
eval_lavars_used = old_eval_lavars;
! vim_free(tofree);
return OK;
errret:
--- 508,517 ----
}
eval_lavars_used = old_eval_lavars;
! if (evalarg->eval_tofree == NULL)
! evalarg->eval_tofree = tofree;
! else
! vim_free(tofree);
return OK;
errret:
***************
*** 517,523 ****
ga_clear_strings(&newlines);
vim_free(fp);
vim_free(pt);
! vim_free(tofree);
eval_lavars_used = old_eval_lavars;
return FAIL;
}
--- 519,528 ----
ga_clear_strings(&newlines);
vim_free(fp);
vim_free(pt);
! if (evalarg->eval_tofree == NULL)
! evalarg->eval_tofree = tofree;
! else
! vim_free(tofree);
eval_lavars_used = old_eval_lavars;
return FAIL;
}
*** ../vim-8.2.1160/src/vim9compile.c 2020-07-08 19:35:17.767686401 +0200
--- src/vim9compile.c 2020-07-08 21:08:44.792351587 +0200
***************
*** 3113,3118 ****
--- 3113,3120 ----
// Compile it into instructions.
compile_def_function(ufunc, TRUE, cctx);
+ clear_evalarg(&evalarg, NULL);
+
if (ufunc->uf_def_status == UF_COMPILED)
return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
return FAIL;
*** ../vim-8.2.1160/src/eval.c 2020-07-08 17:36:17.738105000 +0200
--- src/eval.c 2020-07-08 21:55:37.633123734 +0200
***************
*** 379,388 ****
* Skip over an expression at "*pp".
* If in Vim9 script and line breaks are encountered, the lines are
* concatenated. "evalarg->eval_tofree" will be set accordingly.
* Return FAIL for an error, OK otherwise.
*/
int
! skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg)
{
typval_T rettv;
int res;
--- 379,395 ----
* Skip over an expression at "*pp".
* If in Vim9 script and line breaks are encountered, the lines are
* 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.
*/
int
! skip_expr_concatenate(
! char_u **arg,
! char_u **start,
! char_u **end,
! evalarg_T *evalarg)
{
typval_T rettv;
int res;
***************
*** 398,409 ****
if (ga_grow(gap, 1) == OK)
++gap->ga_len;
}
// Don't evaluate the expression.
if (evalarg != NULL)
evalarg->eval_flags &= ~EVAL_EVALUATE;
! *end = skipwhite(*end);
! res = eval1(end, &rettv, evalarg);
if (evalarg != NULL)
evalarg->eval_flags = save_flags;
--- 405,418 ----
if (ga_grow(gap, 1) == OK)
++gap->ga_len;
}
+ *start = *arg;
// Don't evaluate the expression.
if (evalarg != NULL)
evalarg->eval_flags &= ~EVAL_EVALUATE;
! *arg = skipwhite(*arg);
! res = eval1(arg, &rettv, evalarg);
! *end = *arg;
if (evalarg != NULL)
evalarg->eval_flags = save_flags;
***************
*** 419,425 ****
else
{
char_u *p;
! size_t endoff = STRLEN(*end);
// Line breaks encountered, concatenate all the lines.
*((char_u **)gap->ga_data) = *start;
--- 428,434 ----
else
{
char_u *p;
! size_t endoff = STRLEN(*arg);
// Line breaks encountered, concatenate all the lines.
*((char_u **)gap->ga_data) = *start;
***************
*** 428,434 ****
--- 437,450 ----
// free the lines only when using getsourceline()
if (evalarg->eval_cookie != NULL)
{
+ // Do not free the first line, the caller can still use it.
*((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);
}
else
***************
*** 437,444 ****
if (p == NULL)
return FAIL;
*start = p;
! vim_free(evalarg->eval_tofree);
! evalarg->eval_tofree = p;
// Compute "end" relative to the end.
*end = *start + STRLEN(*start) - endoff;
}
--- 453,460 ----
if (p == NULL)
return FAIL;
*start = p;
! vim_free(evalarg->eval_tofree_lambda);
! evalarg->eval_tofree_lambda = p;
// Compute "end" relative to the end.
*end = *start + STRLEN(*start) - endoff;
}
***************
*** 1936,1942 ****
((char_u **)gap->ga_data)[gap->ga_len] = line;
++gap->ga_len;
}
! else
{
vim_free(evalarg->eval_tofree);
evalarg->eval_tofree = line;
--- 1952,1958 ----
((char_u **)gap->ga_data)[gap->ga_len] = line;
++gap->ga_len;
}
! else if (evalarg->eval_cookie != NULL)
{
vim_free(evalarg->eval_tofree);
evalarg->eval_tofree = line;
***************
*** 1962,1986 ****
}
/*
! * After using "evalarg" filled from "eap" free the memory.
*/
void
clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
{
! if (evalarg != NULL && evalarg->eval_tofree != NULL)
{
! if (eap != NULL)
{
! // We may need to keep the original command line, e.g. for
! // ":let" it has the variable names. But we may also need the
! // new one, "nextcmd" points into it. Keep both.
! 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;
}
}
--- 1978,2008 ----
}
/*
! * After using "evalarg" filled from "eap": free the memory.
*/
void
clear_evalarg(evalarg_T *evalarg, exarg_T *eap)
{
! if (evalarg != NULL)
{
! if (evalarg->eval_tofree != NULL)
{
! if (eap != NULL)
! {
! // We may need to keep the original command line, e.g. for
! // ":let" it has the variable names. But we may also need the
! // new one, "nextcmd" points into it. Keep both.
! 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;
}
!
! vim_free(evalarg->eval_tofree_lambda);
! evalarg->eval_tofree_lambda = NULL;
}
}
*** ../vim-8.2.1160/src/proto/
eval.pro 2020-07-04 14:14:55.633073475 +0200
--- src/proto/
eval.pro 2020-07-08 21:35:36.700364651 +0200
***************
*** 10,16 ****
int eval_expr_to_bool(typval_T *expr, int *error);
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
int skip_expr(char_u **pp);
! int skip_expr_concatenate(char_u **start, char_u **end, evalarg_T *evalarg);
char_u *eval_to_string(char_u *arg, int convert);
char_u *eval_to_string_safe(char_u *arg, int use_sandbox);
varnumber_T eval_to_number(char_u *expr);
--- 10,16 ----
int eval_expr_to_bool(typval_T *expr, int *error);
char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
int skip_expr(char_u **pp);
! 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_safe(char_u *arg, int use_sandbox);
varnumber_T eval_to_number(char_u *expr);
*** ../vim-8.2.1160/src/structs.h 2020-07-08 17:36:17.734105013 +0200
--- src/structs.h 2020-07-08 21:54:48.377262186 +0200
***************
*** 1773,1780 ****
// "eval_ga.ga_data" is a list of pointers to lines.
garray_T eval_ga;
! // pointer to the line obtained with getsourceline()
char_u *eval_tofree;
} evalarg_T;
// Flags for expression evaluation.
--- 1773,1783 ----
// "eval_ga.ga_data" is a list of pointers to lines.
garray_T eval_ga;
! // pointer to the last line obtained with getsourceline()
char_u *eval_tofree;
+
+ // pointer to the lines concatenated for a lambda.
+ char_u *eval_tofree_lambda;
} evalarg_T;
// Flags for expression evaluation.
*** ../vim-8.2.1160/src/version.c 2020-07-08 19:35:17.767686401 +0200
--- src/version.c 2020-07-08 21:07:20.828519290 +0200
***************
*** 756,757 ****
--- 756,759 ----
{ /* Add new patch number below this line */
+ /**/
+ 1161,
/**/
--
Normal people believe that if it ain't broke, don't fix it. Engineers believe
that if it ain't broke, it doesn't have enough features yet.
(Scott Adams - The Dilbert principle)
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///