diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-08-18 13:28:31 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-08-18 13:28:31 +0100 |
commit | 91c7cbfe31bbef57d5fcf7d76989fc159f73ef15 (patch) | |
tree | 95aa1ecfabd5937db15f10648d79a61f42c417e4 /src/eval.c | |
parent | 4875d6ab068f09df88d24d81de40dcd8d56e243d (diff) |
patch 9.0.0225: using freed memory with multiple line breaks in expressionv9.0.0225
Problem: Using freed memory with multiple line breaks in expression.
Solution: Free eval_tofree later.
Diffstat (limited to 'src/eval.c')
-rw-r--r-- | src/eval.c | 102 |
1 files changed, 60 insertions, 42 deletions
diff --git a/src/eval.c b/src/eval.c index 42b883e9b0..60daca51ce 100644 --- a/src/eval.c +++ b/src/eval.c @@ -354,6 +354,63 @@ eval_to_string_skip( } /* + * Initialize "evalarg" for use. + */ + void +init_evalarg(evalarg_T *evalarg) +{ + CLEAR_POINTER(evalarg); + ga_init2(&evalarg->eval_tofree_ga, sizeof(char_u *), 20); +} + +/* + * If "evalarg->eval_tofree" is not NULL free it later. + * Caller is expected to overwrite "evalarg->eval_tofree" next. + */ + static void +free_eval_tofree_later(evalarg_T *evalarg) +{ + if (evalarg->eval_tofree != NULL) + { + if (ga_grow(&evalarg->eval_tofree_ga, 1) == OK) + ((char_u **)evalarg->eval_tofree_ga.ga_data) + [evalarg->eval_tofree_ga.ga_len++] + = evalarg->eval_tofree; + else + vim_free(evalarg->eval_tofree); + } +} + +/* + * 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; + } + + ga_clear_strings(&evalarg->eval_tofree_ga); + VIM_CLEAR(evalarg->eval_tofree_lambda); + } +} + +/* * Skip over an expression at "*pp". * Return FAIL for an error, OK otherwise. */ @@ -435,8 +492,8 @@ skip_expr_concatenate( // 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); + // later. Also free "eval_tofree" later if needed. + free_eval_tofree_later(evalarg); evalarg->eval_tofree = ((char_u **)gap->ga_data)[gap->ga_len - 1]; ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL; @@ -2274,7 +2331,7 @@ eval_next_line(char_u *arg, evalarg_T *evalarg) } else if (evalarg->eval_cookie != NULL) { - vim_free(evalarg->eval_tofree); + free_eval_tofree_later(evalarg); evalarg->eval_tofree = line; } @@ -2302,45 +2359,6 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg) } /* - * Initialize "evalarg" for use. - */ - void -init_evalarg(evalarg_T *evalarg) -{ - CLEAR_POINTER(evalarg); - ga_init2(&evalarg->eval_tofree_ga, sizeof(char_u *), 20); -} - -/* - * 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; - } - - ga_clear_strings(&evalarg->eval_tofree_ga); - VIM_CLEAR(evalarg->eval_tofree_lambda); - } -} - -/* * The "evaluate" argument: When FALSE, the argument is only parsed but not * executed. The function may return OK, but the rettv will be of type * VAR_UNKNOWN. The function still returns FAIL for a syntax error. |