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 ```
This commit is contained in:
parent
d3efce69ea
commit
5bc8fceca8
Notes:
git
2023-08-09 18:07:18 +00:00
42
parse.y
42
parse.y
@ -13228,27 +13228,40 @@ local_push(struct parser_params *p, int toplevel_scope)
|
||||
p->lvtbl = local;
|
||||
}
|
||||
|
||||
static void
|
||||
local_free(struct parser_params *p, struct local_vars *local)
|
||||
{
|
||||
if (local->used) {
|
||||
vtable_free(local->used);
|
||||
}
|
||||
|
||||
# if WARN_PAST_SCOPE
|
||||
while (local->past) {
|
||||
struct vtable *past = local->past;
|
||||
local->past = past->prev;
|
||||
vtable_free(past);
|
||||
}
|
||||
# endif
|
||||
|
||||
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);
|
||||
vtable_free(p->lvtbl->used);
|
||||
}
|
||||
# if WARN_PAST_SCOPE
|
||||
while (p->lvtbl->past) {
|
||||
struct vtable *past = p->lvtbl->past;
|
||||
p->lvtbl->past = past->prev;
|
||||
vtable_free(past);
|
||||
}
|
||||
# endif
|
||||
vtable_free(p->lvtbl->args);
|
||||
vtable_free(p->lvtbl->vars);
|
||||
|
||||
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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user