Mercurial > vim
diff src/userfunc.c @ 26747:a8a4e1e7b111 v8.2.3902
patch 8.2.3902: Vim9: double free with nested :def function
Commit: https://github.com/vim/vim/commit/9c23f9bb5fe435b28245ba8ac65aa0ca6b902c04
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Dec 26 14:23:22 2021 +0000
patch 8.2.3902: Vim9: double free with nested :def function
Problem: Vim9: double free with nested :def function.
Solution: Pass "line_to_free" from compile_def_function() and make sure
cmdlinep is valid.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 26 Dec 2021 15:30:02 +0100 |
parents | 9c9b8d95b05f |
children | 3a2b222107a6 |
line wrap: on
line diff
--- a/src/userfunc.c +++ b/src/userfunc.c @@ -720,12 +720,14 @@ get_function_body( } else { - vim_free(*line_to_free); if (eap->getline == NULL) theline = getcmdline(':', 0L, indent, getline_options); else theline = eap->getline(':', eap->cookie, indent, getline_options); + if (*eap->cmdlinep == *line_to_free) + *eap->cmdlinep = theline; + vim_free(*line_to_free); *line_to_free = theline; } if (KeyTyped) @@ -837,7 +839,8 @@ get_function_body( // we can simply point into it, otherwise we need to // change "eap->cmdlinep". eap->nextcmd = nextcmd; - if (*line_to_free != NULL) + if (*line_to_free != NULL + && *eap->cmdlinep != *line_to_free) { vim_free(*eap->cmdlinep); *eap->cmdlinep = *line_to_free; @@ -1161,7 +1164,7 @@ lambda_function_body( } if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL) goto erret; - if (cmdline != NULL) + if (eap.nextcmd != NULL) // more is following after the "}", which was skipped last = cmdline; else @@ -1175,7 +1178,7 @@ lambda_function_body( ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; } - if (cmdline != NULL) + if (eap.nextcmd != NULL) { garray_T *tfgap = &evalarg->eval_tofree_ga; @@ -1187,6 +1190,8 @@ lambda_function_body( { ((char_u **)(tfgap->ga_data))[tfgap->ga_len++] = cmdline; evalarg->eval_using_cmdline = TRUE; + if (cmdline == line_to_free) + line_to_free = NULL; } } else @@ -3988,9 +3993,8 @@ list_functions(regmatch_T *regmatch) * Returns a pointer to the function or NULL if no function defined. */ ufunc_T * -define_function(exarg_T *eap, char_u *name_arg) +define_function(exarg_T *eap, char_u *name_arg, char_u **line_to_free) { - char_u *line_to_free = NULL; int j; int c; int saved_did_emsg; @@ -4258,7 +4262,7 @@ define_function(exarg_T *eap, char_u *na if (get_function_args(&p, ')', &newargs, eap->cmdidx == CMD_def ? &argtypes : NULL, FALSE, NULL, &varargs, &default_args, eap->skip, - eap, &line_to_free) == FAIL) + eap, line_to_free) == FAIL) goto errret_2; whitep = p; @@ -4368,7 +4372,7 @@ define_function(exarg_T *eap, char_u *na // Do not define the function when getting the body fails and when // skipping. - if (get_function_body(eap, &newlines, line_arg, &line_to_free) == FAIL + if (get_function_body(eap, &newlines, line_arg, line_to_free) == FAIL || eap->skip) goto erret; @@ -4660,7 +4664,6 @@ errret_2: } ret_free: ga_clear_strings(&argtypes); - vim_free(line_to_free); vim_free(fudi.fd_newkey); if (name != name_arg) vim_free(name); @@ -4676,7 +4679,10 @@ ret_free: void ex_function(exarg_T *eap) { - (void)define_function(eap, NULL); + char_u *line_to_free = NULL; + + (void)define_function(eap, NULL, &line_to_free); + vim_free(line_to_free); } /*