# HG changeset patch # User Bram Moolenaar # Date 1616361303 -3600 # Node ID 5f3a2d31c48d9a37d5663d0fd2d2353fa408b573 # Parent 60c5b6cb513048e12f1882b195ddd6684caf1bd2 patch 8.2.2636: memory leak when compiling inline function Commit: https://github.com/vim/vim/commit/67da21a14726b106b49744f9773eba132fedd5f2 Author: Bram Moolenaar Date: Sun Mar 21 22:12:34 2021 +0100 patch 8.2.2636: memory leak when compiling inline function Problem: Memory leak when compiling inline function. Solution: Free the prefetched line. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -2179,8 +2179,8 @@ clear_evalarg(evalarg_T *evalarg, exarg_ evalarg->eval_tofree = NULL; } - vim_free(evalarg->eval_tofree_lambda); - evalarg->eval_tofree_lambda = NULL; + VIM_CLEAR(evalarg->eval_tofree_cmdline); + VIM_CLEAR(evalarg->eval_tofree_lambda); } } diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -1898,7 +1898,8 @@ EXTERN listitem_T range_list_item; // Passed to an eval() function to enable evaluation. EXTERN evalarg_T EVALARG_EVALUATE # ifdef DO_INIT - = {EVAL_EVALUATE, 0, NULL, NULL, NULL, {0, 0, 0, 0, NULL}, NULL, NULL} + = {EVAL_EVALUATE, 0, NULL, NULL, NULL, {0, 0, 0, 0, NULL}, + NULL, NULL, NULL} # endif ; #endif diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1882,6 +1882,9 @@ typedef struct { // pointer to the last line obtained with getsourceline() char_u *eval_tofree; + // pointer to the last line of an inline function + char_u *eval_tofree_cmdline; + // pointer to the lines concatenated for a lambda. char_u *eval_tofree_lambda; } evalarg_T; diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -970,17 +970,18 @@ lambda_function_body( ga_init2(&newlines, (int)sizeof(char_u *), 10); if (get_function_body(&eap, &newlines, NULL, &line_to_free) == FAIL) + { + vim_free(cmdline); goto erret; + } if (cmdline != NULL) { // Something comes after the "}". *arg = eap.nextcmd; - if (evalarg->eval_cctx == NULL) - { - // Need to keep the line and free it/ later. - vim_free(evalarg->eval_tofree_lambda); - evalarg->eval_tofree_lambda = cmdline; - } + + // "arg" points into cmdline, need to keep the line and free it later. + vim_free(evalarg->eval_tofree_cmdline); + evalarg->eval_tofree_cmdline = cmdline; } else *arg = (char_u *)""; diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2636, +/**/ 2635, /**/ 2634, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3202,6 +3202,16 @@ compile_lambda(char_u **arg, cctx_T *cct // Compile the function into instructions. compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx); + // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg" + // points into it. Point to the original line to avoid a dangling pointer. + if (evalarg.eval_tofree_cmdline != NULL) + { + size_t off = *arg - evalarg.eval_tofree_cmdline; + + *arg = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum] + + off; + } + clear_evalarg(&evalarg, NULL); if (ufunc->uf_def_status == UF_COMPILED)