Skip to content

Commit c3c1477

Browse files
authored
Merge pull request #223 from jcalvert/fix/writer-string-buffer-leak
Fix XML::Writer.string buffer leak
2 parents daa51c5 + 1b9279b commit c3c1477

4 files changed

Lines changed: 45 additions & 10 deletions

File tree

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Rake::ExtensionTask.new do |ext|
2020
ext.gem_spec = spec
2121
ext.name = SO_NAME
2222
ext.ext_dir = "ext/libxml"
23-
ext.lib_dir = "lib/#{RUBY_VERSION.sub(/\.\d$/, '')}"
23+
ext.lib_dir = "lib/#{RUBY_VERSION.sub(/\.\d+$/, '')}"
2424
if RUBY_PLATFORM.match(/mswin|mingw/)
2525
ext.config_options <<
2626
if (dir = ENV['WINDOWS_XML2_INCLUDE'])

ext/libxml/ruby_xml_writer.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,16 @@ typedef struct
4343

4444
static void rxml_writer_free(rxml_writer_object* rwo)
4545
{
46-
#if 0 /* seems to be done by xmlFreeTextWriter */
47-
if (NULL != rwo->buffer)
48-
{
49-
xmlBufferFree(rwo->buffer);
50-
}
51-
#endif
46+
xmlBufferPtr buffer = rwo->buffer;
5247

5348
rwo->closed = 1;
5449
xmlFreeTextWriter(rwo->writer);
50+
51+
if (NULL != buffer)
52+
{
53+
xmlBufferFree(buffer);
54+
}
55+
5556
xfree(rwo);
5657
}
5758

@@ -1121,4 +1122,3 @@ void rxml_init_writer(void)
11211122
rb_undef_method(CLASS_OF(cXMLWriter), "new");
11221123
#endif
11231124
}
1124-

test/test_error.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ def test_get_handler
7171
else
7272
LibXML::XML::Error.reset_handler
7373
end
74-
75-
assert_equal(LibXML::XML::Error.get_handler, saved_handler)
74+
if saved_handler.nil?
75+
assert_nil(LibXML::XML::get_handler)
76+
else
77+
assert_equal(LibXML::XML::Error.get_handler, saved_handler)
78+
end
7679
end
7780

7881
def test_verbose_handler

test/test_writer.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,31 @@ def test_nil_pe_issue
446446
assert_equal(writer.result, expected)
447447
end
448448

449+
def test_string_writer_does_not_leak_memory
450+
skip('RSS check not supported on Windows') if windows?
451+
452+
rss_by_round = []
453+
454+
4.times do
455+
5_000.times do
456+
writer = LibXML::XML::Writer.string
457+
document(writer, encoding: LibXML::XML::Encoding::UTF_8) do
458+
writer.write_element('test', 'hello')
459+
end
460+
writer.result
461+
end
462+
463+
GC.start(full_mark: true, immediate_sweep: true)
464+
465+
rss = rss_in_kb
466+
skip('RSS check not available') unless rss
467+
468+
rss_by_round << rss
469+
end
470+
471+
assert_operator(rss_by_round.last - rss_by_round[1], :<, 5_000)
472+
end
473+
449474
private
450475

451476
def document(writer, options = {})
@@ -465,4 +490,11 @@ def element(writer, localname)
465490
yield if block_given?
466491
assert(writer.end_element)
467492
end
493+
494+
def rss_in_kb
495+
rss = `ps -o rss= -p #{Process.pid}`.strip
496+
Integer(rss)
497+
rescue Errno::ENOENT, Errno::EPERM, ArgumentError
498+
nil
499+
end
468500
end

0 commit comments

Comments
 (0)