diff options
| author | Peter Zhu <peter@peterzhu.ca> | 2024-07-31 13:32:29 -0400 |
|---|---|---|
| committer | Peter Zhu <peter@peterzhu.ca> | 2024-07-31 14:47:44 -0400 |
| commit | 635839749026b5d5bafeb892f2f01a9348a4b5c8 (patch) | |
| tree | ae9b62749e81ebb598c4bdfcce8e7ee4ab705bee | |
| parent | 70b4f45d9f1936128e73ab0b8701269c06e709f5 (diff) | |
Fix leak of AST when Ripper#compile_error jumps
For example, the following script leaks:
class MyRipper < Ripper
def initialize(src, &blk)
super(src)
@blk = blk
end
def compile_error(msg) = @blk.call(msg)
end
def call_parse = MyRipper.new("/") { |msg| return msg }.parse
10.times do
100_000.times do
call_parse
end
puts `ps -o rss= -p #{$$}`
end
Before:
93952
169040
244224
318784
394432
468224
544048
618560
693776
768384
After:
19776
19776
20352
20880
20912
21408
21328
21152
21472
20944
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/11287
| -rw-r--r-- | parse.y | 4 | ||||
| -rw-r--r-- | test/ripper/test_parser_events.rb | 22 |
2 files changed, 26 insertions, 0 deletions
@@ -15608,6 +15608,10 @@ rb_ruby_parser_free(void *ptr) struct parser_params *p = (struct parser_params*)ptr; struct local_vars *local, *prev; + if (p->ast) { + rb_ast_free(p->ast); + } + #ifndef RIPPER if (p->tokens) { rb_parser_ary_free(p, p->tokens); diff --git a/test/ripper/test_parser_events.rb b/test/ripper/test_parser_events.rb index 5434acb523..35264868b9 100644 --- a/test/ripper/test_parser_events.rb +++ b/test/ripper/test_parser_events.rb @@ -1743,4 +1743,26 @@ class TestRipper::ParserEvents < Test::Unit::TestCase parse('case 0; in {a:}; end', :on_hshptn) {thru_hshptn = true} assert_equal true, thru_hshptn end + + def test_return_out_of_compile_error_no_memory_leak + assert_no_memory_leak(%w(-rripper), "#{<<~'begin;'}", "#{<<~'end;'}", rss: true) + class MyRipper < Ripper + def initialize(src, &blk) + super(src) + @blk = blk + end + + def compile_error(msg) = @blk.call(msg) + end + + def call_parse = MyRipper.new("/") { |msg| return msg }.parse + + # Check that call_parse does return a syntax error + raise "call_parse should return a syntax error" unless call_parse + begin; + 100_000.times do + call_parse + end + end; + end end if ripper_test |
