diff options
| -rw-r--r-- | parse.y | 42 | ||||
| -rw-r--r-- | test/ripper/test_ripper.rb | 7 |
2 files changed, 35 insertions, 14 deletions
@@ -13229,26 +13229,39 @@ local_push(struct parser_params *p, int toplevel_scope) } static void -local_pop(struct parser_params *p) +local_free(struct parser_params *p, struct local_vars *local) { - struct local_vars *local = p->lvtbl->prev; - if (p->lvtbl->used) { - warn_unused_var(p, p->lvtbl); - vtable_free(p->lvtbl->used); + if (local->used) { + vtable_free(local->used); } + # if WARN_PAST_SCOPE - while (p->lvtbl->past) { - struct vtable *past = p->lvtbl->past; - p->lvtbl->past = past->prev; + while (local->past) { + struct vtable *past = local->past; + local->past = past->prev; vtable_free(past); } # endif - vtable_free(p->lvtbl->args); - vtable_free(p->lvtbl->vars); + + vtable_free(local->args); + vtable_free(local->vars); + + ruby_sized_xfree(local, sizeof(struct local_vars)); +} + +static void +local_pop(struct parser_params *p) +{ + struct local_vars *local = p->lvtbl->prev; + if (p->lvtbl->used) { + warn_unused_var(p, p->lvtbl); + } + + local_free(p, p->lvtbl); + p->lvtbl = local; + CMDARG_POP(); COND_POP(); - ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl)); - p->lvtbl = local; } #ifndef RIPPER @@ -13856,11 +13869,12 @@ rb_ruby_parser_free(void *ptr) if (p->tokenbuf) { ruby_sized_xfree(p->tokenbuf, p->toksiz); } + for (local = p->lvtbl; local; local = prev) { - xfree(local->vars); prev = local->prev; - xfree(local); + local_free(p, local); } + { token_info *ptinfo; while ((ptinfo = p->token_info) != 0) { diff --git a/test/ripper/test_ripper.rb b/test/ripper/test_ripper.rb index 2bb307eddf..25ddc381cc 100644 --- a/test/ripper/test_ripper.rb +++ b/test/ripper/test_ripper.rb @@ -154,6 +154,13 @@ end Ripper.parse("") end end; + + # [Bug #19835] + assert_no_memory_leak(%w(-rripper), "", "#{<<~'end;'}", rss: true) + 1_000_000.times do + Ripper.parse("class Foo") + end + end; end class TestInput < self |
