# HG changeset patch # User Bram Moolenaar # Date 1585752305 -7200 # Node ID 1136ec381dd21125199e4c929d5d4f9da0e112c4 # Parent cbe06eef8c71c738b8720fd508762c6ad6541238 patch 8.2.0489: Vim9: memory leaks Commit: https://github.com/vim/vim/commit/25b70c780a7e6063544e7f93c368fe403076f34e Author: Bram Moolenaar Date: Wed Apr 1 16:34:17 2020 +0200 patch 8.2.0489: Vim9: memory leaks Problem: Vim9: memory leaks. Solution: Free memory in the right place. Add hints for using asan. diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -691,9 +691,12 @@ LINT_OPTIONS = -beprxzF # Uncomment one of the next two lines to compile Vim with the -# address sanitizer or with the undefined sanitizer. Works with gcc and +# address sanitizer (asan) or with the undefined sanitizer. Works with gcc and # clang. May make Vim twice as slow. Errors reported on stderr. # More at: https://code.google.com/p/address-sanitizer/ +# Useful environment variables: +# $ export ASAN_OPTIONS="print_stacktrace=1 log_path=asan" +# $ export LSAN_OPTIONS="suppressions=$cwd/testdir/lsan-suppress.txt" #SANITIZER_CFLAGS = -g -O0 -fsanitize=address -fno-omit-frame-pointer #SANITIZER_CFLAGS = -g -O0 -fsanitize=undefined -fno-omit-frame-pointer SANITIZER_LIBS = $(SANITIZER_CFLAGS) diff --git a/src/testdir/lsan-suppress.txt b/src/testdir/lsan-suppress.txt --- a/src/testdir/lsan-suppress.txt +++ b/src/testdir/lsan-suppress.txt @@ -9,3 +9,4 @@ leak:libtinfo.so.5 leak:libperl.so.* leak:libpython*.so.* leak:libruby*.so.* +leak:libxcb*.so.* diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 489, +/**/ 488, /**/ 487, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3500,7 +3500,7 @@ compile_assignment(char_u *arg, exarg_T if (cmdidx == CMD_const) { emsg(_(e_const_option)); - return NULL; + goto theend; } if (is_decl) { @@ -3513,7 +3513,7 @@ compile_assignment(char_u *arg, exarg_T { // cannot happen? emsg(_(e_letunexp)); - return NULL; + goto theend; } cc = *p; *p = NUL; @@ -3522,7 +3522,7 @@ compile_assignment(char_u *arg, exarg_T if (opt_type == -3) { semsg(_(e_unknown_option), arg); - return NULL; + goto theend; } if (opt_type == -2 || opt_type == 0) type = &t_string; @@ -3543,7 +3543,7 @@ compile_assignment(char_u *arg, exarg_T if (!valid_yank_reg(arg[1], TRUE)) { emsg_invreg(arg[1]); - return FAIL; + goto theend; } dest = dest_reg; if (is_decl) @@ -3994,6 +3994,23 @@ new_scope(cctx_T *cctx, scopetype_T type } /* + * Free the current scope and go back to the outer scope. + */ + static void +drop_scope(cctx_T *cctx) +{ + scope_T *scope = cctx->ctx_scope; + + if (scope == NULL) + { + iemsg("calling drop_scope() without a scope"); + return; + } + cctx->ctx_scope = scope->se_outer; + vim_free(scope); +} + +/* * Evaluate an expression that is a constant: * has(arg) * @@ -4412,7 +4429,6 @@ compile_endif(char_u *arg, cctx_T *cctx) return NULL; } ifscope = &scope->se_u.se_if; - cctx->ctx_scope = scope->se_outer; unwind_locals(cctx, scope->se_local_count); if (scope->se_u.se_if.is_if_label >= 0) @@ -4425,7 +4441,7 @@ compile_endif(char_u *arg, cctx_T *cctx) compile_fill_jump_to_end(&ifscope->is_end_label, cctx); cctx->ctx_skip = FALSE; - vim_free(scope); + drop_scope(cctx); return arg; } @@ -4486,25 +4502,35 @@ compile_for(char_u *arg, cctx_T *cctx) // Reserve a variable to store the loop iteration counter. loop_idx = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); if (loop_idx < 0) + { + drop_scope(cctx); return NULL; + } // Reserve a variable to store "var" var_idx = reserve_local(cctx, arg, varlen, FALSE, &t_any); if (var_idx < 0) + { + drop_scope(cctx); return NULL; + } generate_STORENR(cctx, loop_idx, -1); // compile "expr", it remains on the stack until "endfor" arg = p; if (compile_expr1(&arg, cctx) == FAIL) + { + drop_scope(cctx); return NULL; + } // now we know the type of "var" vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (vartype->tt_type != VAR_LIST) { emsg(_("E1024: need a List to iterate over")); + drop_scope(cctx); return NULL; } if (vartype->tt_member->tt_type != VAR_UNKNOWN)