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.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index e9d6089..b23145e 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -812,11 +812,13 @@
* Compile a nested :def command.
*/
static char_u *
-compile_nested_function(exarg_T *eap, cctx_T *cctx)
+compile_nested_function(exarg_T *eap, cctx_T *cctx, char_u **line_to_free)
{
int is_global = *eap->arg == 'g' && eap->arg[1] == ':';
char_u *name_start = eap->arg;
char_u *name_end = to_name_end(eap->arg, TRUE);
+ int off;
+ char_u *func_name;
char_u *lambda_name;
ufunc_T *ufunc;
int r = FAIL;
@@ -866,7 +868,17 @@
lambda_name = vim_strsave(get_lambda_name());
if (lambda_name == NULL)
return NULL;
- ufunc = define_function(eap, lambda_name);
+
+ // This may free the current line, make a copy of the name.
+ off = is_global ? 2 : 0;
+ func_name = vim_strnsave(name_start + off, name_end - name_start - off);
+ if (func_name == NULL)
+ {
+ r = FAIL;
+ goto theend;
+ }
+
+ ufunc = define_function(eap, lambda_name, line_to_free);
if (ufunc == NULL)
{
@@ -911,21 +923,14 @@
if (is_global)
{
- char_u *func_name = vim_strnsave(name_start + 2,
- name_end - name_start - 2);
-
- if (func_name == NULL)
- r = FAIL;
- else
- {
- r = generate_NEWFUNC(cctx, lambda_name, func_name);
- lambda_name = NULL;
- }
+ r = generate_NEWFUNC(cctx, lambda_name, func_name);
+ func_name = NULL;
+ lambda_name = NULL;
}
else
{
// Define a local variable for the function reference.
- lvar_T *lvar = reserve_local(cctx, name_start, name_end - name_start,
+ lvar_T *lvar = reserve_local(cctx, func_name, name_end - name_start,
TRUE, ufunc->uf_func_type);
if (lvar == NULL)
@@ -937,6 +942,7 @@
theend:
vim_free(lambda_name);
+ vim_free(func_name);
return r == FAIL ? NULL : (char_u *)"";
}
@@ -2861,7 +2867,7 @@
case CMD_def:
case CMD_function:
ea.arg = p;
- line = compile_nested_function(&ea, &cctx);
+ line = compile_nested_function(&ea, &cctx, &line_to_free);
break;
case CMD_return: