diff options
| author | nagachika <nagachika@ruby-lang.org> | 2023-08-13 13:21:30 +0900 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2023-08-13 13:21:30 +0900 |
| commit | 6898389a0f640c4155a7073579f43d1e16893698 (patch) | |
| tree | 5de77c056251d4161120354da7ba891dfa9cad9f /parse.y | |
| parent | ead1a83b2f5951cd09667ed2722ab14b9bcf0834 (diff) | |
merge revision(s) 5bc8fceca8d47ed1ef9c603c6531a408de36b60c: [Backport #19835]
Fix memory leak in parser for incomplete tokens
[Bug #19835]
The parser does not free the `tbl` of the `struct vtable` when there are
leftover `lvtbl` in the parser. This causes a memory leak.
The following script reproduces this issue:
```
10.times do
100_000.times do
Ripper.parse("class Foo")
end
puts `ps -o rss= -p #{$$}`
end
```
---
parse.y | 42 ++++++++++++++++++++++++++++--------------
test/ripper/test_ripper.rb | 7 +++++++
2 files changed, 35 insertions(+), 14 deletions(-)
Diffstat (limited to 'parse.y')
| -rw-r--r-- | parse.y | 54 |
1 files changed, 34 insertions, 20 deletions
@@ -13176,26 +13176,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; - vtable_free(past); + 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 @@ -13776,16 +13789,17 @@ parser_free(void *ptr) if (p->tokenbuf) { ruby_sized_xfree(p->tokenbuf, p->toksiz); } + for (local = p->lvtbl; local; local = prev) { - if (local->vars) xfree(local->vars); - prev = local->prev; - xfree(local); + prev = local->prev; + local_free(p, local); } + { - token_info *ptinfo; - while ((ptinfo = p->token_info) != 0) { - p->token_info = ptinfo->next; - xfree(ptinfo); + token_info *ptinfo; + while ((ptinfo = p->token_info) != 0) { + p->token_info = ptinfo->next; + xfree(ptinfo); } } xfree(ptr); |
