summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-04-01 16:34:17 +0200
committerBram Moolenaar <Bram@vim.org>2020-04-01 16:34:17 +0200
commit25b70c780a7e6063544e7f93c368fe403076f34e (patch)
treed7bab440c76f5710607417302f11203240c9f31f
parent05afceeddc4afbbca60e4e6a729a50d33d4b19f7 (diff)
patch 8.2.0489: Vim9: memory leaksv8.2.0489
Problem: Vim9: memory leaks. Solution: Free memory in the right place. Add hints for using asan.
-rw-r--r--src/Makefile5
-rw-r--r--src/testdir/lsan-suppress.txt1
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c38
4 files changed, 39 insertions, 7 deletions
diff --git a/src/Makefile b/src/Makefile
index 690ac3f8e0..221b4f0de8 100644
--- 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
index a3008bdce6..f3d62b9826 100644
--- 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
index 58180acc4b..43f9e59435 100644
--- 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
index 3c3f5a1635..64ebddfb99 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -3500,7 +3500,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
{
// cannot happen?
emsg(_(e_letunexp));
- return NULL;
+ goto theend;
}
cc = *p;
*p = NUL;
@@ -3522,7 +3522,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
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 *eap, cmdidx_T cmdidx, cctx_T *cctx)
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)